Commit Graph

4 Commits

Author SHA1 Message Date
Levi Neuwirth 2a1cf9be2e docs(process): framing revision 4 — record what implementing found
Not a new design round. Every bet resolved, and one acceptance turned
out to be satisfiable vacuously.

Acceptance 2's in-drain clause said "the live descendant's named late
output absent" without saying how the descendant stays live. It does
not, by default: `poll_one` TERMs the whole group on leader exit. The
first fixture's marker was therefore absent on both paths, and the pin
would have stayed green with the collapse fixed.

Bets 1 and 2 hold — every site took a directed outcome without
restructuring, and every consequence is reachable, so the lane does not
shrink. Bet 3 resolves the shutdown coupling as real and measured. Bet
4 is falsified exactly as its own clause anticipated: `ProcessEvent` is
keyed by `ProcessId` while the ledger is keyed by pgid and is
deliberately independent of managed records, every production consumer
polls per known id, and `take_all_events` has no production consumer at
all. Q#RL3 is answered accordingly and reporting is parked as its own
lane.

Also records the four sites and the two reusable lessons in
`docs/agent-handoff.md` — that a seam for a background loop has to be
directed, and that an absence assertion is only as good as its
fixture's ability to produce the thing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lv428Fth9LRtffwJSsqH7T
2026-07-30 18:58:17 -04:00
Levi Neuwirth a9a1484ff7 docs(process): make reap-ledger seam falsifiable
Refine the framing's in-drain test seam: a one-shot probe error cannot
survive the 50 ms quiescence interval, so the test-only override lasts
for one drain context and remains per-supervisor. Name the in-drain
SIGKILL as a non-observable local fact rather than adding an untestable
seam, and synchronize the revision-three ledger record.
2026-07-30 16:41:10 -04:00
Levi Neuwirth b881bd4c4e docs(process): framing revision 2 — close review round 1
Three blocking and two major findings, all accepted, all verified in the
code first.

- **§0 named the wrong journey step**, and contradicted Q#RL5 in the same
  document. The ledger arms only for `spec.group`, which spawn rejects
  for PTY mode, so no terminal reaches it. The only production
  `group = true` caller is compile mode, making this journey step 9
  (build/test) plus general pipe-process cleanup.
- **A fourth site was missed.** `final_drain_runtime` collapses every
  probe errno to "dead" while no tick runs, discards its SIGKILL result,
  and sets its own flag. It is not identical to the persistent ledger —
  a later tick can retry that, this decision is terminal for the drain —
  and its consequence differs: a false "dead" cancels the readers, so
  the failure mode is truncated output rather than a leaked process. It
  also constrains the seam, being a free function with no `&mut self`.
- **The staging contradicted itself**: "Bet 1 ships alone" against an
  acceptance requiring failure-path tests, under one-branch/one-PR. It
  was also wrong on its own terms — a seam with no tests does not show
  it reaches the intended production calls. The first PR is now seam
  plus behaviour-preserving tests, still diagnosis-only.
- **A generic seam is the wrong shape.** `shutdown()` calls
  `self.signal(*id, SIGKILL)` before its ledger force-kill, so one
  shared "next kill errno" would be consumed by the wrong call and the
  test would pass while proving nothing. The seam is now site-directed
  with four independently addressable outcomes, expressing more than one
  pending result because the coupling test needs two at once, and with
  fixture cleanup stated rather than assumed.
- **§1.3 overstated the loop coupling.** Early exit needs the ledger
  empty AND `any_running()` already false. The precondition is now in
  the ground truth and in Bet 3's fixture requirement.

Framing only. No code.
2026-07-30 16:20:09 -04:00
Levi Neuwirth 088f417e70 docs(process): frame the reap ledger's silent failures
Unparked from PR #200's §5, which retired the premise justifying the
ledger's leniency and deliberately changed no disposition.

Scouting found three silent failures where #200 named two. A probe error
of any errno drops the entry and cancels escalation; a failed escalating
SIGKILL is recorded as a success and never retried; and `shutdown()`
discards its own force-kill result identically — on the path written
specifically to stop a leak at editor exit.

Two facts shape the lane. `shutdown()`'s final loop terminates when the
ledger empties, which happens through the same silent drop, so the probe
error that hides a leak can also end the cleanup loop early — the probe
cannot be made strict in isolation. And all three paths are untestable
today: `tick_reap_ledger` and `shutdown()` call nix directly and consult
no injection seam, unlike `signal()`'s `forced_kill_errno`, so every one
of the five existing ledger tests exercises only the success path.

Diagnosis first; no disposition change is proposed. Stage A of the signal
lane had three tolerance rules rejected across three revisions, each for
concluding something about one entity from something about another, on
this same data structure.

The framing states plainly that none of the three has been observed:
#200 saw an explicit SIGTERM fail in `signal()`, not a ledger call.

Framing only. No code.
2026-07-30 16:13:02 -04:00