docs(plans): brief for the cohort release follow-ups after row 50

Engine exit proof and release, the crash window and release retry,
close's SIGKILL of a recorded PID, and the reviewers' surviving mutants
(relok, closeany, noprooffkind, nopush).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-10 00:10:38 -05:00
co-authored by Claude Opus 5.5
parent ac7acd6852
commit ef70ba6a64
@@ -0,0 +1,82 @@
# Conversation cohort: release follow-ups after row 50 (2026-10-10)
Status: written by Sage, lead. It follows `docs/plans/BRIEF-TEMPLATE.md`
and amends no section of the slice 1 brief. One row.
## Cohort release follow-ups: engine exit, crash window and close
### Problem
Row 50 (#1536) releases a cohort scope after a proven force stop and on
close of a proven-stopped binding. Its reviews (Filbert comment 27053,
Darkwing comment 27055) and Dewey's packet (comment 27052) leave these
open. Sage accepted the first as a deviation from the row 50 brief
(comment 27054).
- A normal engine exit leaves the scope and an idle shim. The binding is
`uncertain`, and only a confirmed force stop clears it. A bare release
at EOF isn't a fix: the claim would stay `uncertain` with its scope
gone, and every later force stop would end `unavailable`.
- A controller killed between `#claimFinish` and the release leaves the
scope. A restart classifies the claim `stopped` and never releases it.
A release that came back `unavailable` or `still listed` has no retry
either.
- `close({ killEngine: true })` after a proven stop sends SIGKILL to the
recorded engine PID, which may since belong to another process. This
predates row 50.
- Test gaps, all non-blocking in row 50:
- Filbert N1: a refused `release` isn't tested. Mutant `relok` survives
and would record `released` with `unit: "still listed"`.
- Filbert N3: close's `#stopped(...)` check (`closeany`) and
`#releaseScope`'s `cohortProof` check (`noprooffkind`) have no test
that fails without them.
- Darkwing note 1: mutant `nopush` survives; no test reads the release
entry pushed to observers.
### Owner and reviewer
Owner: Dewey. Reviewers: Darkwing and Filbert.
### Files owned
- `packages/conversation/src/cohort.mjs`, `packages/conversation/src/controller.mjs`
- `packages/conversation/src/shim.mjs`, only if the EOF proof needs a shim op
- `packages/conversation/tests/` and `packages/conversation/README.md`
### What ships
- Engine exit. On EOF the controller runs the same cohort proof the force
stop uses. If the cohort reads empty, it records `stopped` with that
`cohortProof` and releases the scope. Nothing is killed, so no client
confirmation is needed. If the cohort isn't empty, the binding stays
`uncertain` as today. Before writing code, the packet names every
claim-protocol rule this touches (K6 included). If one of them needs a
change to a rule written in the slice 1 brief, stop and report to Sage
first.
- Crash window and retry. The start and recover paths release a claim
recorded `stopped` with a `cohortProof` whose scope is still listed. A
release that ended `unavailable` or `still listed` is retried there,
and never for a claim without a proof.
- Close. After a proven stop, `close({ killEngine: true })` doesn't
signal the recorded PID, or it checks that the PID is still the same
engine before it does. The packet says which and why.
- Tests:
- an engine that exits on its own leaves no unit and records `stopped`;
- an engine that exits while another member still runs stays
`uncertain`, and nothing is released;
- a restart after a crash between `stopped` and the release removes the
unit;
- close after a proven stop doesn't signal a PID it can't show is the
engine;
- each of `relok`, `closeany`, `noprooffkind` and `nopush` fails a test.
### Out of scope
The force-stop phases, the pgroup fallback, and the release polling cost
(Darkwing note 2).
### Gate
Darkwing and Filbert approve on the row's issue. The conversation and
webui node suites and every `scripts/test-*.sh` green on Sage's gate rerun.
No `mosaic-chat-*` scope left after the suites.