Skip to content

fix(pi): keep supervision outcome delivery responsive - #3767

Merged
kunchenguid merged 5 commits into
mainfrom
fm/fm-pi-subsecond-freeze-s1
Sep 5, 2026
Merged

fix(pi): keep supervision outcome delivery responsive#3767
kunchenguid merged 5 commits into
mainfrom
fm/fm-pi-subsecond-freeze-s1

Conversation

@kunchenguid

@kunchenguid kunchenguid commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Intent

The captain approved shipping a focused ASYNCHRONOUS conversion of the Pi supervision outcome-delivery path to eliminate the visible subsecond UI freeze that occurs whenever a routine (sailboat) or captain-facing (anchor) outcome arrives into his Pi main session. Captain's exact words: "I agree with the asynchronous fix."

THE PROBLEM (established diagnosis): the supervision branch runs inside the captain's own Pi process, and Pi runs extensions, their tools, and their event handlers on the single JavaScript thread that also draws the TUI and reads the keyboard. Each delivered outcome runs about five bash script invocations (bin/fm-branch-outcome.sh append, processed-init, unread, mark-read per row, unprocessed, plus bin/fm-lease.sh and bin/fm-operational-input.sh encode) plus four to six ps calls for the lock-ownership ancestry walk, all through synchronous spawnSync on that thread, so the TUI cannot repaint or echo a keystroke for roughly 250-440 ms per outcome. It is not rendering, transcript size, store size, or the model: a silent heartbeat that paints nothing still blocked, and the same chain minus the append also runs at the session_start, turn_end, and agent_settled boundaries, so a turn boundary costs the same stall even when no outcome exists. The relevant code is .pi/extensions/fm-branch-supervision.ts: createReportTool/execute, lockOwnership, runOutcomeScript, reconcileUnreadOutcomes, presentUnprocessedOutcomes, and those three event boundaries. Those millisecond figures are host- and Pi-version-specific, not the captain's live-session latency; the code-path finding is what holds.

THE FIX (the captain's chosen option): convert the delivery path's subprocess calls from spawnSync to asynchronous spawn plus await behind a serializing queue, so the TUI keeps painting while the store and script work happens off the render-blocking path.

INVARIANTS THAT MUST BE PRESERVED (the captain's explicit constraints):

  • store-before-visible-delivery ("nothing is delivered before it is durable"),
  • acknowledgement ordering,
  • serialization of deliveries,
  • generation/session ownership checks between steps,
  • cancellation behavior across the awaits.
    Keep the existing durable store and script contracts (bin/fm-branch-outcome.sh and friends) unchanged. Do NOT add a new framework, do NOT batch away acknowledgement boundaries, and do NOT cache the ownership authority merely for speed: process ancestry is not immutable (reparenting and pid-identity reuse can invalidate a cached ancestor chain) and it feeds an ownership-authority check, so caching it is correctness-sensitive rather than trivial.

TESTS (behavioral, required): interleaved deliveries; session replacement/cancellation; failures that must not lose or duplicate outcomes; PLUS a real-Pi typing/repaint responsiveness check during the delivery path under the tested supported Pi version.

BOUNDARIES: preserve the MacBook/Pi-version limitations of the measurements rather than overclaiming them; do NOT alter the captain's live Pi session or global Pi settings, using an isolated Pi/session for testing. Report readiness with the full PR URL and the ACTUAL measured responsiveness, not a predicted latency target. Implementation is approved; merge is NOT (the captain merges).

What Changed

  • Replace blocking supervision delivery subprocesses with awaited asynchronous execution while preserving uncached ownership checks and durable store contracts.
  • Serialize outcome delivery, reconciliation, and acknowledgements to preserve ordering, cancellation, and store-before-visible delivery across session changes and failures.
  • Add interleaving, replacement, failure, and real-Pi responsiveness coverage, with host- and Pi-version-specific measurements documented.

Risk Assessment

⚠️ Medium: The asynchronous delivery implementation is well-bounded and preserves the reviewed ordering and cancellation invariants, but the branch also introduces an unrelated conditional test suppression that should receive explicit approval.

Testing

The successful changed-test baseline was supplemented with focused delivery regressions covering event-loop responsiveness, interleaving and serialization, session replacement/cancellation, durability, failure handling, and acknowledgement behavior. An isolated real Pi 0.82.0 TUI measured worst keystroke echo at 32.0 ms unloaded, 54.4 ms extension-idle, and 53.0 ms while delivering outcomes. No screenshot was captured because the reported defect is a temporal input/repaint freeze; the reviewer-visible timing transcript directly records the end-user behavior.

Evidence: Real Pi typing and repaint responsiveness measurement

Source: Real Pi typing and repaint responsiveness measurement

pi 0.82.0 keystroke echo, worst observed: floor 32.0 ms, extension idle 54.4 ms, extension delivering 53.0 ms

pi 0.82.0 keystroke echo, worst observed: floor 32.0 ms, extension idle 54.4 ms, extension delivering 53.0 ms
ok - supervision outcome delivery keeps the real Pi 0.82.0 TUI echoing keystrokes at its unloaded floor
Evidence: Focused asynchronous delivery behavioral regressions

Source: Focused asynchronous delivery behavioral regressions

FM_TEST_BEGIN 2026-09-05T04:23:20Z tests/fm-pi-branch-extension.test.sh family=standalone expected_gate_skip=none
skip: installed Pi 0.81.1 predates the stock renderer contract 0.84.4 this case compares against
ok - the installed Pi still bounds the picker's list and ranks its search
ok - branch owns accepted wakes with a stable prefix and deterministic verdict-driven delivery
ok - a captain outcome reaches main's model as one typed, sequence-keyed processing request while routine notes stay plain
ok - requested and unsolicited healthy outcomes keep distinct delivery and event ownership
ok - captain outcomes are exact and exactly once across crash, reload, busy main, compaction, and an unrelated assistant response
ok - a captain outcome opens one sequence-keyed processing turn, survives empty and unrelated answers, is re-presented at run end and session start, and closes only on its acknowledgement
ok - scopeForUnreadWake excludes every main-only class without vetoing eligible task-local rows, and writes the eligible snapshot
ok - branch prompt_cache_key is stable per home across sessions and distinct between homes
ok - branch default-on eligibility (task-scoped, heartbeat, afk) binds and a broken branch rejects to watcher fallback
ok - a heartbeat review survives a check row arriving before its drain
ok - fm_branch_report refuses a task the wake did not name, fleet included, while a heartbeat is unscoped
ok - pre-drain eligibility re-check excludes a newly main-owned row without deferring eligible work
ok - a settled branch turn without a durable outcome falls back and releases its grant for main replay
ok - provider-error latches cool down, re-probe once with backoff, and recover through a durable report
ok - selection changes preserve in-flight transcript ownership and reset provider-error streaks
ok - a stale main claim returns the durable wake to watcher delivery
ok - pre-drain eligibility re-check no-ops an already-drained wake
ok - dialog mirror filters tool and operational traffic, lands before wakes, and keeps a durable cursor
ok - the dialog mirror re-anchors for each session's new branch conversation and stays incremental within it
ok - every main session start begins a new branch conversation while one session keeps its own
ok - the current pin state binds every branch build, and clearing it returns the branch to main's model
ok - unpinned branches follow main model changes live while pinned branches stay fixed
ok - supervision-model command persists the captain's pick and rebinds the live branch
ok - supervision-model opens a bounded searchable list, follow main first, and pins the branch alone
ok - branch model picker keeps follow main first and filters the eligible catalog
ok - the effort pin binds every branch build, and clearing it returns the branch to main's effort
ok - unpinned branches follow main effort changes live while pinned branches stay fixed
ok - supervision-model runs an effort picker after the model picker and persists both independently
ok - an unusable model pin rejects to watcher fallback and an unparseable one is treated as no pin
ok - replacement activation cleans old branch leases and retries failed cleanup
ok - branch activates on a cold start once the lock is acquired, never before
ok - queued wakes and mirrors stop mutating branch state after lock ownership is lost
ok - stale reports, shells, mirrors, cursors, leases, and prompts perform no side effects
ok - a Pi session that does not own the lock accepts nothing and mutates no branch state
ok - an extension rebind re-mirrors undelivered dialog instead of dropping it
ok - outcome delivery keeps the event loop running and interleaved reports stay ordered and exactly once
ok - a session replaced mid-delivery cancels cleanly and the stored outcome still arrives exactly once
ok - a failing store script surfaces to the branch and its outcome is neither lost nor delivered twice
ok - a failed cursor write re-delivers a routine note exactly once more while a captain outcome stays deduplicated
FM_TEST_END 2026-09-05T04:24:30Z tests/fm-pi-branch-extension.test.sh exit=0 duration_ms=69479 gate_skip=true
FM_TEST_SUMMARY total=1 failed=0 skipped_gate=1 duration_ms=69553
FM_TEST_SUMMARY_FAMILY family=standalone count=1 duration_ms=69479 failed=0
FM_TEST_SLOWEST rank=1 script=tests/fm-pi-branch-extension.test.sh duration_ms=69479

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 warning
  • ⚠️ tests/fm-pi-branch-extension.test.sh:21 - The new Pi renderer version floor, custom version comparator, and conditional skip are unrelated to the required asynchronous outcome-delivery conversion or its responsiveness tests. No stated intent requires changing this pre-existing renderer test; remove this component and handle renderer compatibility separately if desired.
✅ **Test** - passed

✅ No issues found.

  • bin/fm-test-run.sh --changed --exclude-family real-herdr-gated
  • Baseline (already completed): bin/fm-test-run.sh --changed --exclude-family real-herdr-gated
  • bin/fm-test-run.sh tests/fm-pi-branch-extension.test.sh
  • FM_PI_BRANCH_RESPONSIVENESS_E2E=1 bash tests/fm-pi-branch-responsiveness-live-e2e.test.sh
  • git status --short confirmed testing left the worktree clean
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

kunchenguid and others added 2 commits September 4, 2026 19:07
The supervision branch runs inside the captain's own Pi process, and Pi
runs extensions, their tools, and their event handlers on the single
JavaScript thread that also draws the TUI and reads the keyboard. Every
delivered outcome ran roughly five bash script invocations plus several
`ps` calls through spawnSync on that thread, so the TUI could not repaint
or echo a keystroke for the whole chain - the subsecond freeze the
captain saw every time a routine or captain-facing outcome arrived.

Convert the delivery path's subprocess calls to an awaited spawn behind a
serializing queue. lib/fm-async-exec.ts is the single owner of the
awaited-spawn replacement and returns the same capture shape and failure
verdicts spawnSync returned. Awaiting yields the thread, so what the
single thread used to guarantee for free is now an explicit queue: every
delivery, acknowledgement, and turn-boundary reconciliation runs as one
unit of it, preserving the durable append before anything visible, one
delivery at a time in sequence order, the read cursor advanced before the
next reader sees a row, and one ownership activation per generation.
Cancellation is preserved by the generation and lock-ownership rechecks
the awaits are placed around.

Two reads stay synchronous because Pi's own API is synchronous there, not
as an optimization: its bash spawn hook is typed as a plain function, and
the watcher reads offer.accepted the moment its dispatch event returns, so
a session that does not own the fleet lock must still refuse a wake
without waiting. Both walk the lock's process ancestry in full every time,
never cached, because reparenting and pid reuse can invalidate a
remembered chain and that answer decides ownership rather than hinting at
it. The store scripts and their durability contracts are unchanged.

Measured through the real fm_branch_report tool and real bin/ scripts with
a 1 ms interval timer, the largest block of the JS thread falls from 273
to 2.0 ms for a routine outcome, 286 to 2.0 ms for a captain outcome, and
134 to 1.9 ms for main's acknowledgement, against a 1.3-2.2 ms idle floor.
In a real Pi 0.82.0 TUI the worst keystroke echo while two outcomes arrive
falls from 676.9 ms to 36.8 ms, against a 22.6 ms extension-free floor.

Regressions: a delivery must leave the event loop running (zero timer
ticks before this change, in 250 ms), interleaved reports stay ordered and
exactly once, a session replaced mid-delivery neither loses nor duplicates
an outcome, and a failing store script surfaces without losing or doubling
one. The real-TUI half is an opt-in live guard that types into an isolated
Pi pane while outcomes are delivered and fails if echo leaves the class of
the same machine's own floor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bzoWyr2EcJGBKuoUjVRSp
@greptile-apps

greptile-apps Bot commented Sep 5, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge because no unacknowledged blocking failure remains.

No blocking failure remains.

Reviews (3): Last reviewed commit: "no-mistakes(document): Clarify asynchron..." | Re-trigger Greptile

Comment thread .pi/extensions/fm-branch-supervision.ts
kunchenguid and others added 3 commits September 4, 2026 20:16
…uence-keyed delivery receipt before awaiting cursor advancement, preventing duplicate delivery after mark-read failure. Corrected the session-replacement test to exercise an actual asynchronous ps ancestry lookup. Targeted behavioral tests, strict Pi typecheck, ShellCheck, and diff checks pass. The full extension test remains locally blocked by an unrelated stock-render assertion under the installed Pi runtime. The no-mistakes attestation failure is external pipeline state (test was previously skipped), not a source defect
…case below its Pi floor

Four follow-ups on the same branch, plus one revert.

Revert the routine-delivery receipt a CI auto-fix round added. It introduced a
new persisted `fm-branch-routine-delivery` entry, written into the captain's
transcript for every routine note, to deduplicate a note whose cursor write
failed. That is a change to the delivery contract, which this task is not
authorized to make: the approved work is the asynchronous conversion with the
existing durability contract preserved. The ownership re-read and output
bounding from the review round are kept - both are genuine asynchronous
correctness, not contract changes - as is that round's use of a real parent pid
so the replacement regression traverses an actual ps subprocess.

Record the routine gap instead of closing it. A routine note is a plain
message with no sequence-keyed record, so a mark-read failure after delivery
makes the next reconciliation send it once more; a captain row cannot
duplicate that way because its visible entry is found by store sequence. That
asymmetry predates moving delivery off the render thread. It is now stated at
the call site and in the delivery-contract docs, tracked as
fm-pi-routine-delivery-idempotency-followup-r1, and pinned by a regression
that proves the routine note is re-delivered exactly once more and never
again, the captain entry stays single, and the store keeps both rows.

Give the stock-renderer case a Pi version floor. It compares the extension's
renderers against Pi's stock rendering, so its verdict only means anything
against the contract those renderers target: since 0.84.4 the stock renderer
no longer supplies an implicit reset at multiline boundaries and the extension
emits that reset itself, so an older installed Pi differs legitimately. It now
names the installed version and the floor and skips, while a package whose
version cannot be read at all still fails.

Make the responsiveness regression's second signal a fraction rather than a
millisecond budget. A loaded machine that deschedules the process inflates an
absolute stall budget into a false failure, but it inflates the delivery's own
wall time too, so requiring the worst stall to be a minority of that wall time
holds under load. Synchronous delivery sits near 1.0 there whatever the load,
and the tick-count signal still reads zero on it.

Replace the test-family mapping for the Pi extension libraries with per-script
targeting. Routing them to whole families - or leaving them unmapped, which
widens through the reference scan to each referencing suite's entire family -
selected dozens of suites with nothing to do with Pi and pulled an unrelated
flake into the run. The changed-file selection drops from 112 scripts to 61.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bzoWyr2EcJGBKuoUjVRSp
@kunchenguid kunchenguid changed the title fix(pi): deliver supervision outcomes without freezing the TUI fix(pi): keep supervision outcome delivery responsive Sep 5, 2026
@kunchenguid
kunchenguid merged commit f09de8a into main Sep 5, 2026
15 of 16 checks passed
@kunchenguid
kunchenguid deleted the fm/fm-pi-subsecond-freeze-s1 branch September 5, 2026 05:39
lytv pushed a commit to lytv/mymate that referenced this pull request Sep 8, 2026
* fix(pi): deliver supervision outcomes off Pi's render thread

The supervision branch runs inside the captain's own Pi process, and Pi
runs extensions, their tools, and their event handlers on the single
JavaScript thread that also draws the TUI and reads the keyboard. Every
delivered outcome ran roughly five bash script invocations plus several
`ps` calls through spawnSync on that thread, so the TUI could not repaint
or echo a keystroke for the whole chain - the subsecond freeze the
captain saw every time a routine or captain-facing outcome arrived.

Convert the delivery path's subprocess calls to an awaited spawn behind a
serializing queue. lib/fm-async-exec.ts is the single owner of the
awaited-spawn replacement and returns the same capture shape and failure
verdicts spawnSync returned. Awaiting yields the thread, so what the
single thread used to guarantee for free is now an explicit queue: every
delivery, acknowledgement, and turn-boundary reconciliation runs as one
unit of it, preserving the durable append before anything visible, one
delivery at a time in sequence order, the read cursor advanced before the
next reader sees a row, and one ownership activation per generation.
Cancellation is preserved by the generation and lock-ownership rechecks
the awaits are placed around.

Two reads stay synchronous because Pi's own API is synchronous there, not
as an optimization: its bash spawn hook is typed as a plain function, and
the watcher reads offer.accepted the moment its dispatch event returns, so
a session that does not own the fleet lock must still refuse a wake
without waiting. Both walk the lock's process ancestry in full every time,
never cached, because reparenting and pid reuse can invalidate a
remembered chain and that answer decides ownership rather than hinting at
it. The store scripts and their durability contracts are unchanged.

Measured through the real fm_branch_report tool and real bin/ scripts with
a 1 ms interval timer, the largest block of the JS thread falls from 273
to 2.0 ms for a routine outcome, 286 to 2.0 ms for a captain outcome, and
134 to 1.9 ms for main's acknowledgement, against a 1.3-2.2 ms idle floor.
In a real Pi 0.82.0 TUI the worst keystroke echo while two outcomes arrive
falls from 676.9 ms to 36.8 ms, against a 22.6 ms extension-free floor.

Regressions: a delivery must leave the event loop running (zero timer
ticks before this change, in 250 ms), interleaved reports stay ordered and
exactly once, a session replaced mid-delivery neither loses nor duplicates
an outcome, and a failing store script surfaces without losing or doubling
one. The real-TUI half is an opt-in live guard that types into an isolated
Pi pane while outcomes are delivered and fails if echo leaves the class of
the same machine's own floor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bzoWyr2EcJGBKuoUjVRSp

* no-mistakes(review): Revalidate ownership and bound asynchronous subprocess output

* no-mistakes(ci): Fixed CI defects: routine outcomes now persist a sequence-keyed delivery receipt before awaiting cursor advancement, preventing duplicate delivery after mark-read failure. Corrected the session-replacement test to exercise an actual asynchronous ps ancestry lookup. Targeted behavioral tests, strict Pi typecheck, ShellCheck, and diff checks pass. The full extension test remains locally blocked by an unrelated stock-render assertion under the installed Pi runtime. The no-mistakes attestation failure is external pipeline state (test was previously skipped), not a source defect

* fix(pi): keep the declined routine receipt out and skip the renderer case below its Pi floor

Four follow-ups on the same branch, plus one revert.

Revert the routine-delivery receipt a CI auto-fix round added. It introduced a
new persisted `fm-branch-routine-delivery` entry, written into the captain's
transcript for every routine note, to deduplicate a note whose cursor write
failed. That is a change to the delivery contract, which this task is not
authorized to make: the approved work is the asynchronous conversion with the
existing durability contract preserved. The ownership re-read and output
bounding from the review round are kept - both are genuine asynchronous
correctness, not contract changes - as is that round's use of a real parent pid
so the replacement regression traverses an actual ps subprocess.

Record the routine gap instead of closing it. A routine note is a plain
message with no sequence-keyed record, so a mark-read failure after delivery
makes the next reconciliation send it once more; a captain row cannot
duplicate that way because its visible entry is found by store sequence. That
asymmetry predates moving delivery off the render thread. It is now stated at
the call site and in the delivery-contract docs, tracked as
fm-pi-routine-delivery-idempotency-followup-r1, and pinned by a regression
that proves the routine note is re-delivered exactly once more and never
again, the captain entry stays single, and the store keeps both rows.

Give the stock-renderer case a Pi version floor. It compares the extension's
renderers against Pi's stock rendering, so its verdict only means anything
against the contract those renderers target: since 0.84.4 the stock renderer
no longer supplies an implicit reset at multiline boundaries and the extension
emits that reset itself, so an older installed Pi differs legitimately. It now
names the installed version and the floor and skips, while a package whose
version cannot be read at all still fails.

Make the responsiveness regression's second signal a fraction rather than a
millisecond budget. A loaded machine that deschedules the process inflates an
absolute stall budget into a false failure, but it inflates the delivery's own
wall time too, so requiring the worst stall to be a minority of that wall time
holds under load. Synchronous delivery sits near 1.0 there whatever the load,
and the tick-count signal still reads zero on it.

Replace the test-family mapping for the Pi extension libraries with per-script
targeting. Routing them to whole families - or leaving them unmapped, which
widens through the reference scan to each referencing suite's entire family -
selected dozens of suites with nothing to do with Pi and pulled an unrelated
flake into the run. The changed-file selection drops from 112 scripts to 61.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bzoWyr2EcJGBKuoUjVRSp

* no-mistakes(document): Clarify asynchronous execution documentation

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
BenWilcox8 pushed a commit to BenWilcox8/firstmate that referenced this pull request Sep 12, 2026
* fix(pi): deliver supervision outcomes off Pi's render thread

The supervision branch runs inside the captain's own Pi process, and Pi
runs extensions, their tools, and their event handlers on the single
JavaScript thread that also draws the TUI and reads the keyboard. Every
delivered outcome ran roughly five bash script invocations plus several
`ps` calls through spawnSync on that thread, so the TUI could not repaint
or echo a keystroke for the whole chain - the subsecond freeze the
captain saw every time a routine or captain-facing outcome arrived.

Convert the delivery path's subprocess calls to an awaited spawn behind a
serializing queue. lib/fm-async-exec.ts is the single owner of the
awaited-spawn replacement and returns the same capture shape and failure
verdicts spawnSync returned. Awaiting yields the thread, so what the
single thread used to guarantee for free is now an explicit queue: every
delivery, acknowledgement, and turn-boundary reconciliation runs as one
unit of it, preserving the durable append before anything visible, one
delivery at a time in sequence order, the read cursor advanced before the
next reader sees a row, and one ownership activation per generation.
Cancellation is preserved by the generation and lock-ownership rechecks
the awaits are placed around.

Two reads stay synchronous because Pi's own API is synchronous there, not
as an optimization: its bash spawn hook is typed as a plain function, and
the watcher reads offer.accepted the moment its dispatch event returns, so
a session that does not own the fleet lock must still refuse a wake
without waiting. Both walk the lock's process ancestry in full every time,
never cached, because reparenting and pid reuse can invalidate a
remembered chain and that answer decides ownership rather than hinting at
it. The store scripts and their durability contracts are unchanged.

Measured through the real fm_branch_report tool and real bin/ scripts with
a 1 ms interval timer, the largest block of the JS thread falls from 273
to 2.0 ms for a routine outcome, 286 to 2.0 ms for a captain outcome, and
134 to 1.9 ms for main's acknowledgement, against a 1.3-2.2 ms idle floor.
In a real Pi 0.82.0 TUI the worst keystroke echo while two outcomes arrive
falls from 676.9 ms to 36.8 ms, against a 22.6 ms extension-free floor.

Regressions: a delivery must leave the event loop running (zero timer
ticks before this change, in 250 ms), interleaved reports stay ordered and
exactly once, a session replaced mid-delivery neither loses nor duplicates
an outcome, and a failing store script surfaces without losing or doubling
one. The real-TUI half is an opt-in live guard that types into an isolated
Pi pane while outcomes are delivered and fails if echo leaves the class of
the same machine's own floor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bzoWyr2EcJGBKuoUjVRSp

* no-mistakes(review): Revalidate ownership and bound asynchronous subprocess output

* no-mistakes(ci): Fixed CI defects: routine outcomes now persist a sequence-keyed delivery receipt before awaiting cursor advancement, preventing duplicate delivery after mark-read failure. Corrected the session-replacement test to exercise an actual asynchronous ps ancestry lookup. Targeted behavioral tests, strict Pi typecheck, ShellCheck, and diff checks pass. The full extension test remains locally blocked by an unrelated stock-render assertion under the installed Pi runtime. The no-mistakes attestation failure is external pipeline state (test was previously skipped), not a source defect

* fix(pi): keep the declined routine receipt out and skip the renderer case below its Pi floor

Four follow-ups on the same branch, plus one revert.

Revert the routine-delivery receipt a CI auto-fix round added. It introduced a
new persisted `fm-branch-routine-delivery` entry, written into the captain's
transcript for every routine note, to deduplicate a note whose cursor write
failed. That is a change to the delivery contract, which this task is not
authorized to make: the approved work is the asynchronous conversion with the
existing durability contract preserved. The ownership re-read and output
bounding from the review round are kept - both are genuine asynchronous
correctness, not contract changes - as is that round's use of a real parent pid
so the replacement regression traverses an actual ps subprocess.

Record the routine gap instead of closing it. A routine note is a plain
message with no sequence-keyed record, so a mark-read failure after delivery
makes the next reconciliation send it once more; a captain row cannot
duplicate that way because its visible entry is found by store sequence. That
asymmetry predates moving delivery off the render thread. It is now stated at
the call site and in the delivery-contract docs, tracked as
fm-pi-routine-delivery-idempotency-followup-r1, and pinned by a regression
that proves the routine note is re-delivered exactly once more and never
again, the captain entry stays single, and the store keeps both rows.

Give the stock-renderer case a Pi version floor. It compares the extension's
renderers against Pi's stock rendering, so its verdict only means anything
against the contract those renderers target: since 0.84.4 the stock renderer
no longer supplies an implicit reset at multiline boundaries and the extension
emits that reset itself, so an older installed Pi differs legitimately. It now
names the installed version and the floor and skips, while a package whose
version cannot be read at all still fails.

Make the responsiveness regression's second signal a fraction rather than a
millisecond budget. A loaded machine that deschedules the process inflates an
absolute stall budget into a false failure, but it inflates the delivery's own
wall time too, so requiring the worst stall to be a minority of that wall time
holds under load. Synchronous delivery sits near 1.0 there whatever the load,
and the tick-count signal still reads zero on it.

Replace the test-family mapping for the Pi extension libraries with per-script
targeting. Routing them to whole families - or leaving them unmapped, which
widens through the reference scan to each referencing suite's entire family -
selected dozens of suites with nothing to do with Pi and pulled an unrelated
flake into the run. The changed-file selection drops from 112 scripts to 61.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013bzoWyr2EcJGBKuoUjVRSp

* no-mistakes(document): Clarify asynchronous execution documentation

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant