Merge upstream round 3 of 3 through 7b88520c - #199
Merged
Merged
Conversation
…artup (kunchenguid#2876) tests/fm-watcher-lock.test.sh passed in isolation but failed intermittently under full-suite and ambient concurrent load. bin/fm-watch-arm.sh computes its confirmation deadline immediately after forking the real child watcher, so the child's entire fork, exec, lock acquisition and beacon publication has to land inside that wall clock. Two cases shrank that budget to one second, leaving a two-second window for work measured at 3.1-4.9s under CPU oversubscription, so the arm honestly reported "FAILED - no live watcher with a fresh beacon" and their premises collapsed. A third case ran on the production budget, but its child must also execute a registered check before exiting: measured at 1.9-2.3s idle and 9.1-13.1s under load, against an 11s budget. The two cases that must confirm a real child now hold the arm to production's own budget instead of a shrunken fixture one, the immediate-wake case gets an explicit budget with headroom over its measured loaded cost, and the two waits for the arm's typed failure are sized off the largest production default rather than a fixed eight seconds. No bin/ change and no default behavior change: the lock's fail-closed semantics, SIGSTOP handling, stale-heartbeat detection and the arm's typed failures are untouched. Verified 4/4 green at 3x CPU oversubscription (loadavg 75-80) after 3/3 red before the change, and CONTRIBUTING.md records the convention.
* fix(bin): order discovered tool installs by the shell's own expansion fm_remote_job_compose_operator_path built the asdf and mise install directories with `compgen -G`, which does not sort. Bash sorts glob matches in pathexp.c, on the shell's own pathname-expansion path only; `compgen -G` reaches the same glob_filename through pcomplete.c, which sorts nothing. On bash 3.2 (macOS /bin/bash) and every bash before 5.3 that handed the composition raw readdir order, so which install of a multi-version tool a remote job resolved was decided by directory order on disk rather than by this composition. Expand the globs at the call sites and let the function take the matches, so the composition and the documented portable-PATH contract are the same operation. Quoting the account home at the call site also stops a home whose name contains glob metacharacters from being reinterpreted. The colocated regression pins both the order and the mechanism: bash 5.3 moved sorting into the glob library, so an order-only assertion cannot see the defect there. * no-mistakes(review): Remove source-reading PATH regression guard
…2848) * fix: surface stalled secondmate queues and wake handoffs * no-mistakes(review): Make handoff wakes retryable and stall alerts crash-safe * no-mistakes(review): Prevent duplicate handoff wakes and cover remote delivery * no-mistakes(review): Serialize local handoffs and preserve pre-move wake intent * no-mistakes(review): Serialize teardown with handoffs and retain remote wake confirmation * no-mistakes(review): Reconcile correlated handoff wake delivery after crashes * no-mistakes(review): Keep failed wakes retryable and isolate stall receipts * no-mistakes(review): Reset known-undelivered wake attempts for durable retries * no-mistakes(review): Refuse duplicate sends for unresolved delivery attempts * no-mistakes(review): Atomically restore retryability after reconciled send failures * no-mistakes(review): Serialize delivery confirmation with reconciliation * no-mistakes(document): Document routed wake and stall supervision * no-mistakes(lint): Fix ShellCheck expansion and subshell warnings * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes(review): Retire stale wake state and defer pre-move wakes * no-mistakes(review): Secure markers, bind batches, and preserve teardown routes * no-mistakes(review): Preserve unresolved prepared wakes across unrelated handoffs * no-mistakes(review): Preserve prepared wakes before unrelated moving handoffs * no-mistakes(document): Document prepared wake batch ownership * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes(review): Make local wake retirement recoverable * no-mistakes(document): Clarify handoff recovery and teardown documentation
…guid#2856) * feat(bin): steer local tasks by durable inbox record plus constant doorbell Stage 1 (local steers) of the captain-adopted reframe in data/fm-send-reliability-reframe-s1/report.md: an ordinary fm-send text steer to a task recorded in this home is appended as a sequenced durable record under state/<id>.inbox/ and the terminal receives only one constant self-describing doorbell line, best-effort. The worker acknowledges by moving the record into handled/; the watcher re-rings an unacknowledged message on an idle pane and escalates once as an ordinary stale wake. --resolve-key closes decisions at enqueue time, because the durable enqueue IS delivery to the task's record. bin/fm-task-inbox-lib.sh owns the record format, doorbell line, and re-ring ladder. The typed plane remains for what must reach the terminal itself: lifecycle keys, harness-native slash and codex $-skill invocations, explicit backend targets, and the remote secondmate leg (unchanged until the remote inbox leg ships separately). The composer classifier is demoted from delivery proof to an advisory ring guard that skips only on a proven pending verdict. Verified live against claude, codex, opencode, pi, grok, and muse: each real worker read its record, acted, and acked with the mv (docs/verification/runtime-backends.md "Steering-inbox doorbell"). * docs(verification): flag the grok 1.0.5 composer-matrix staleness observed by the doorbell run * test(captain-hold): read the chat-channel answer from the durable inbox record * test: migrate fm-control's marker contrast to the inbox record and fix macOS wc padding in the tool-update suite * no-mistakes(review): Harden inbox locking, teardown races, and acknowledgements * no-mistakes(review): Serialize watcher actions with inbox acknowledgements * no-mistakes(review): Bound metadata locking and tighten acknowledgement rechecks * no-mistakes(review): Preserve exact inbox bytes and harden delivery recovery * no-mistakes(review): Harden watcher bookkeeping against concurrent inbox teardown * no-mistakes(document): Update inbox and typed-plane documentation * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * revert(pipeline): keep parser-native secondmate marking and the both-failed exit out of stage 1 The CI monitor's fix changed the secondmate marking contract for parser-native invocations (appending the marker after the text) and softened the both-commit-and-marker-failed branch to exit 0. The merge authority ruled the marking question out of scope for this stage-1 transport PR (follow-up: fm-send-secondmate-harness-invocation-r1) and ruled the both-failed case a loud nonzero local failure. Restore both, keeping the monitor's legitimate migrations and hardening. * no-mistakes(document): Document inbox and typed-plane boundaries * no-mistakes(document): Scope backend transport docs to typed plane * no-mistakes(document): Clarify inbox attempt-budget documentation * no-mistakes: apply CI fixes * fix(send): the durable record alone governs the inbox exit status Captain-refined ruling on the F2/Greptile finding: the durable inbox record is what delivers the steer, so pending-reply bookkeeping trouble after a successful enqueue never exits nonzero - a resend-inviting status would make automated callers enqueue the delivered instruction again under a new sequence. With the recovery marker stored the watcher reconciles silently; with the commit and marker both lost the send surfaces a distinct reply-tracking-degraded do-not-resend warning and still exits 0. Nonzero remains only where nothing was delivered (or a decision close needs its manual command). Regression: record durable + both bookkeeping writes lost -> exit 0, one record, no duplicate. * no-mistakes(review): Preserve inbox ordering with drain-all doorbells * no-mistakes(review): Surface unwritable inbox ladder bookkeeping * no-mistakes(review): Silence ladder failures after inbox acknowledgement * no-mistakes(document): Update steering inbox documentation * no-mistakes: apply CI fixes
* feat: add fast local lint mode * fix: preserve complete fm-lint help * fix: isolate fast lint mode * no-mistakes(document): Clarify lint mode documentation ownership * no-mistakes: apply CI fixes
…#2901) * feat(bin): deliver remote secondmate steers through durable task inboxes Stage 2 of the inbox+doorbell steer channel (stage 1: kunchenguid#2856). A remote secondmate steer now crosses fm-on.sh as a durable record written idempotently into the remote home's steering inbox plus a best-effort remote doorbell, and the last typed-payload steer transport is deleted: - fm-remote-secondmate-control.sh cmd_send writes the record via the new fm_task_inbox_write_idempotent and rings the doorbell; it no longer types the payload through an inner fm-send at an explicit pane target. - fm-send.sh routes every remote text steer (harness-native included, which marking already reduced to chat) onto the remote inbox leg, retries the identical leg once on ssh 255, closes --resolve-key decisions at enqueue for remote too, and preserves a marked request's reply expectation when completion stays unknown. The exit-3-as- delivered remap, the 255 do-not-resend trap, and the remote typed submit block are removed. - fm-task-inbox-lib.sh owns the idempotent enqueue: an exact-body re-run lands on the existing record, handled or not, so an ambiguous transport can always be safely re-run. - Tests pin the new contract end to end (record + doorbell + no typed payload across ssh, one-record idempotence under an ambiguous transport, enqueue-time decision close, loud real failures, and the deleted typed-payload behaviors gone), and AGENTS.md plus docs/remote-secondmates.md describe the remote leg's new semantics. * no-mistakes(review): Harden remote inbox delivery against lifecycle races * no-mistakes(review): Enable correlation-preserving remote steer resends * no-mistakes(review): Fail closed on stale correlation resends * no-mistakes(review): Include home context in remote resend commands * no-mistakes(review): Lock and revalidate remote parent routes * no-mistakes(document): Clarify remote steer retry documentation * no-mistakes: apply CI fixes
* wip: forked supervision on Pi (checkpoint before docs) * fix(pi-branch): harden mirror delivery, fallback encoding, and session replacement Peek-then-shift mirror flush so a failed append retries instead of dropping; durable mirror cursor commits only after delivery into the branch; the main fallback wake is operational-encoded like every watcher injection; session_shutdown quiesces the generation and session_start re-arms, so /new and /resume no longer kill the branch permanently. Registers the extension in the strict typecheck, adds the dispatch handshake test, the branch extension suite, the bash-level regression suite, the session-start replay test, and the opt-in real-SDK live guard. * test(fixtures): carry the branch-dispatch lib and lease lib into isolated fixtures The watcher extension now imports lib/fm-branch-dispatch.ts and fm-teardown sources fm-lease-lib.sh, so every fixture that copies or symlinks those files in isolation gains the new sibling. * no-mistakes(review): Prevent shutdown wake loss and serialize lease claims * no-mistakes(review): Durably hand off wakes and retain portable leases * no-mistakes(review): Require durable reports and clear disposed branch leases * no-mistakes(review): Enforce per-wake outcomes and quiescent lease cleanup * no-mistakes(review): Require wake acknowledgements and tighten branch lifecycle boundaries * no-mistakes(review): Require complete acknowledgements and replay cleanup failures * no-mistakes(review): Bind supervision to lock ownership and durable delivery * no-mistakes(review): Activate branch lazily after session lock acquisition * no-mistakes(review): Preserve undelivered mirror context across extension rebinds * no-mistakes(review): Acknowledge startup replay only after main delivery * no-mistakes(review): Isolate replay metadata from untrusted digest content * no-mistakes(review): Reject duplicate reports for active wake sequences * no-mistakes(review): Retain failed fallbacks and deduplicate outcome replay * no-mistakes(review): Deduplicate durable outcomes and cache delivery receipts * no-mistakes(review): Anchor wake sequence matching to outcome fields * no-mistakes(document): Clarify Pi supervision durability contracts * no-mistakes(lint): Fix ShellCheck issues in branch supervision scripts * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * refactor(pi-branch): collapse to confused-agent-grade guards per captain decision Captain decision A: the lease/actor guards target the CONFUSED-AGENT threat model bin/fm-gate-refuse-lib.sh already documents; adversarial-grade separation is impossible in the shared-process design and is filed as separate follow-up work. Rip out the machinery that chased it: the generation fence and shell-provenance markers, the wrapper-tagged ancestry walks, guard auto-claim with per-script release traps, the pending-wake files and ack-receipt correlation (the durable wake queue already re-presents anything unacknowledged), the delivery-receipt store with contiguous cursor advancement, the session-start replay-metadata channel, and the branch tool quiescence counters. Keep the behaviors the board requires, each on its simplest implementation: lazy per-action session-lock ownership (cold start activates after the lock lands; a secondary session stays inert), mirror durability across extension rebinds via the durable cursor, replay-exactly-once from the one read cursor, the awaited operational-encoded fallback, per-generation stray-lease cleanup, session-lock-bound lease liveness (a recycled pid or a non-Pi home never honors a leftover lease), the loud accidental-override guards (readonly actor prelude, cross-actor claim refusal), and the role-partition refinements (no forced teardown, no direct relaunch for the branch). Default-on-for-Pi is unchanged. * no-mistakes(review): Enforce lock ownership and serialize lease mutations * no-mistakes(review): Synchronize guard cleanup and bind leases to lock owner * no-mistakes(review): Report outcomes before acknowledging durable wakes * no-mistakes(review): Restrict leases to Pi and instruct main claims * no-mistakes(review): Reject malformed lease locks and torn outcome tails * no-mistakes(review): Validate complete outcome tails before appending * no-mistakes(review): Guard branch side effects across session replacements * no-mistakes(document): Update Pi supervision durability and lease documentation * no-mistakes(lint): Suppress intentional nested-shell expansion warning * no-mistakes: apply CI fixes * fix(pi-branch): authorize lease releases by caller * fix(lint): break redundant source-analysis path in fm-lease-lib.sh fm-lease-lib.sh's lazy fallback source of fm-wake-lib.sh gave ShellCheck's --external-sources traversal a second path into an already 1540-line file that fm-send.sh and fm-teardown.sh also source directly, blowing up the recursive analysis past CI's lint timeout. Mark it a source=/dev/null analysis boundary, matching the existing fm-task-inbox-lib.sh convention. Also restores bin/fm-lint.sh and tests/fm-lint.test.sh to the shared serial-lint definition (dropping an unrelated parallel-sharding change that was itself hanging and masked this root cause). * no-mistakes(document): Correct lease caller-authorization documentation * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes
Takes the contiguous upstream first-parent range f170ced..7b88520 from kunchenguid/firstmate as one merge, preserving upstream parentage. Resolutions keep every active fork divergence: the agy unverifiable send verdict, the run-progress wedge hold's fifth hold-count parameter, the watcher restart hand-over, the GBrain and fleet-dashboard attachments, the upstream-read-only posture, and repository-local validation evidence.
…e steer plane Upstream's steering inbox makes the durable record, not a confirmed submit, the delivery of an ordinary local steer, so the fork's scout completion-gate reopen now fires at enqueue and is restored when the record cannot be written. The typed plane keeps its existing send-failure and unconfirmed-submit behaviour, and the suite now pins both planes.
… send verdicts to the typed plane Upstream's durable steering inbox splits fm-send into two delivery planes, so the agy unverifiable/pending distinction now describes the typed plane alone. The scout completion-gate reopen was fork-local and unrecorded since 2026-08-12; this round is where it first collided, so it gets its own entry.
…harness A doorbell is ordinary text, so it takes the same submit dispatch as any steer. Without the target's harness, cursor and agy lost Herdr's atomic agent prompt and fell back to typed composer text, which this fleet does not trust for them. Every ring caller now resolves the harness from the target's metadata. The agy delivery-verdict cases move to the typed plane they actually test, and a new case pins that an ordinary agy steer is delivered by its durable record while its doorbell still reaches the pane through the atomic prompt. The brief goldens are regenerated for upstream's new instruction-inbox section.
…move it simulates crashing before The stub killed the handoff and then exec'd the real mv, leaving an orphan that landed the move about a second later. Every later assertion that the item was still in the source backlog then depended on outrunning that orphan, which is why the case passed locally and failed CI. The stub now exits without moving, which is the scenario it exists to build. Reproduced by widening the window with a three-second wait after the simulated crash: the old stub fails the case there, the new one passes.
…026-08-24-round-3 # Conflicts: # docs/configuration.md
This was referenced Aug 26, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Round 3 of 3. Takes the contiguous upstream first-parent range
f170cede..7b88520cfromkunchenguid/firstmateas one merge commit, preserving upstream parentage so the merge base can advance.HelloWorldSungin/firstmate@0344b1d23d3152f13ebcd753d1155d359e1459f6f170cedeb735759e9547a5b9de1a26eca7ea6d71kunchenguid/firstmate@7b88520c055408a18f1476ecce08be60b2885fc9d25ca4db), second parent7b88520c055408a18f1476ecce08be60b2885fc9(git rev-list --mergesover the branch returns 1)This completes the planned three-round sequence. Upstream has advanced 6 further first-parent commits beyond
7b88520c-fb2ce5b2,8b21c99e,52ff62e8,d55e00af,8fa0505e,038d0f7e- which a future round takes. Each was checked withgit merge-base --is-ancestoragainst this branch's head and is absent.Applicability of the eight upstream first-parent changes
kunchenguid/firstmate#28762f250c7ab37dtest(watcher): stop fixture confirmation budgets racing real child startuptests/fm-watcher-lock.test.shbeside the fork's own peer-readiness fix in the same file; both sides' changes are present. Upstream'sARM_FAIL_EXIT_POLLSbudget and its two production-budget cases landed unmodified.kunchenguid/firstmate#2870197afbb79f8bfix(bin): deterministically order remote tool pathsbin/fm-remote-job-lib.shhas no fork divergence. The only conflict was adjacency intests/fm-remote-job.test.sh, where the fork'sset -msits next to upstream's new mise-ordering assertion; both kept.kunchenguid/firstmate#284852f62ab155e8fix(bin): prevent routed secondmate work from strandingbin/fm-backlog-handoff.shplus the stagedhandoff_wake_retire*sequence inbin/fm-teardown.sh. This home has no registered secondmates, so the operational risk is low, but the handoff contract was merged rather than skimmed - see the teardown row below for how it composes with the fork's manifest gate. Its newtests/fm-backlog-handoff.test.shcarried a race that failed this PR's first CI run; see "Repair 3".kunchenguid/firstmate#2857822a9902484bfix: make macOS inbox test path portablebin/fm-inbox.shpath handling; no fork divergence, merged clean.kunchenguid/firstmate#2856e46df1a55a9efeat(bin): deliver local steers through durable task inboxesbin/fm-send.shinto two data planes. Two fork divergences collided with it; both are repaired and re-pinned. Details under "Send contract" below.kunchenguid/firstmate#28918d8362c9abebfeat(bin): add fast local lint modebin/fm-lint.shgains--fast; CI and no-mistakes keep the no-argument full-analysis path. The fork's ShellCheck divergence lives inbin/fm-install-shellcheck.sh, which this change does not touch (git diff 0344b1d2 HEAD -- bin/fm-install-shellcheck.shis empty).kunchenguid/firstmate#2901ddf74ef22f73feat(bin): deliver remote steers through durable inboxeskunchenguid/firstmate#28587b88520c0554feat: add persistent Pi supervision branch.pi/extensions/fm-branch-supervision.ts,lib/fm-branch-dispatch.ts,bin/fm-branch-{outcome,prompt}.sh,bin/fm-lease{,-lib}.sh,docs/pi-supervision-branch.md. The fork's own.pi/extensions/fm-primary-pi-watch.tsconflicted only on thenode:fsimport line; the fork'sexistsSync(away-flag read) and upstream'sreaddirSync(queue project scan) are both kept. Inert on this home, which is not a Pi primary and has noconfig/pi-supervision-branchgrant.Send contract: what a caller can now conclude from an exit status
This is a real contract change, adopted deliberately rather than reconciled quietly.
For an ordinary local or remote text steer, on every harness, the exit status now reports the durable inbox record, not whether the terminal accepted the keystroke. Exit 0 means the steer is durably recorded; a swallowed doorbell is no longer an error, because the watcher's re-ring ladder owns loss detection from there. The pre-merge property "fm-send exits non-zero when an Enter is positively swallowed" therefore now describes the typed plane only - a harness-native invocation (
/..., or$...to a codex target) or an explicit backend target.Verified as still holding after the merge, behaviourally and not merely by test presence:
tests/fm-send-strict.test.shcases unresolvable selectors do not fall back to tmux, prefixless herdr pane ids are rejected before tmux fallback, unmatched single-colon explicit targets must verify live before sending, and unset FM_HOME fails before target resolution all pass.unverifiablevspendingdistinction (active ledger divergence). Both still exit 3,unverifiablestill marks delivery state unknown whilependingstill discards as undelivered, and both are still exercised end to end.tests/fm-agy-adapter.test.shpasses, including a matching cached agy prompt snapshot without a receipt must remain unverifiable (exit 3,verdict=unverifiable), an unsubmitted steer on a composer-supported harness is reported as delivered-unconfirmed (exit 3,verdict=pending), and the threeagent_not_found/agent_not_ready/agent_prompt_failedknown-undelivered cases (exit 1).Those cases previously sent plain text. After the merge that text rides the inbox and exits 0 off the record, so they asserted nothing about the adapter - they had gone vacuous, not red. They now send a harness-native invocation, naming the plane they test, and the suite header records why.
unverifiable. Its delivery is now a durable record backed by a re-ring ladder, which is stronger in the direction that matters - a steer is never silently lost - but it is a narrowing of where that verdict is reachable. The ledger entry is updated to say so.Repair 1: the agy/cursor doorbell had silently lost the atomic prompt
Upstream's
fm_task_inbox_ringcalls the shared submit dispatch without an expected-harness argument. On Herdr, cursor and agy are routed to Herdr's atomicagent promptby exactly that argument, so every ordinary steer's doorbell fell back to the typed composer text this fleet does not trust for those harnesses. Nothing failed; the coverage simply stopped reaching the adapter.fm_task_inbox_ringnow takes the target's harness and passes it through, and all three ring callers -bin/fm-send.sh,bin/fm-watch.sh,bin/fm-remote-secondmate-control.sh- resolve it from the target's own metadata. New regressiontest_ordinary_agy_steer_rings_doorbell_through_atomic_promptasserts the prompt log is used and that no separately typed text is left behind. Counterfactual checked: reverting the one-argument change makes that case fail with the agy doorbell did not use the atomic prompt, so it is not vacuous.Repair 2: the fork's scout completion gate moved onto the durable plane
A steer to a scout that already reported its captain calls reviewed reopens that completion gate, so a follow-up cannot be erased past the gate
captain-hold-lifecycleowns. That reopen lived on the typed submit path, which ordinary steers no longer take - it would have retired silently. It now fires at durable enqueue and is restored when the record cannot be written, while the typed plane keeps its existing send-failure and unconfirmed-submit behaviour.tests/fm-send-strict.test.shpins both planes in both failure directions.This divergence was fork-local and unrecorded since 2026-08-12; it now has its own ledger entry.
Repair 3: the pre-move crash fixture landed the move it simulates crashing before
The first CI run on this branch was green except for the expected no-mistakes check and
Behavior portable serial 6, which failed intests/fm-backlog-handoff.test.sh(new upstream suite fromkunchenguid/firstmate#2848) withpre-move crash recovery failed: Task "pre-move-crash" not found in this backlog.The stub
tasks-axifor that case kills the handoff and thenexecs the realmvanyway, so an orphan lands the move about a second later. Every later assertion that the item is still in the source backlog then holds or fails purely on how fast the runner is - it passes locally and failed on CI.Reproduced deterministically rather than assumed: adding a three-second wait after the simulated crash makes the upstream stub fail the case locally every time. The stub now exits without moving, which is the scenario it exists to build, and with that same three-second window the case passes. Recorded as a ledger entry, since upstream will most likely land its own fix and retire it.
Base reconciliation after
HelloWorldSungin/firstmate#200#200landed onmainafter this PR first went green, soorigin/mainmoved from0344b1d2to32d2e6ca. The base was absorbed by merge (git merge origin/main, commitc5e824c2) rather than by rebase: this branch's value is the single upstream merge and its two parents, and a rebase would linearize it and destroy that parentage. No force-push and no squash; the push was a fast-forward.One file conflicted,
docs/configuration.md, and it was a collision rather than a contradiction - one sentence, two different clauses appended to the same list. The resolution starts from main's sentence, which carries#200's new recall search-read clause, and re-inserts this round's steering-inbox clause ahead of the pending-reply clause. All three of#200's edits to that file are present after the merge: thestate/recall.jsonlclause, the widenedFM_RECALL_TIMEOUTnote, and the newFM_RECALL_JSONL_MAX_BYTESoperator-inventory entry.AGENTS.mdauto-merged, keeping#200's trimmed-to-a-pointerrecall.jsonlrow alongside this round's four new state records.Structure re-verified after the reconciliation:
d25ca4db, unchanged, with exactly two parents; the second is still7b88520c055408a18f1476ecce08be60b2885fc9.c5e824c2absorbingorigin/main(whose second parent is a fork commit).git merge-base --is-ancestor. Every branch commit that is not an ancestor of the endpoint is fork-side work.Re-run on the reconciled head
c5e824c2:bin/fm-lint.shexit 0; full suite 207 suites, 3 failed - the same three suites and the same failing cases as the fork-parent baseline (ruby is required to parse .github/workflows/ci.yml as YAML,arm did not exit with HUP status (got 124), and the orphaned-process case infm-remote-job-worker-leak).bin/fm-doc-audience-check.sh(118 surfaces, 635 local links) andbin/fm-pointer-check.sh(0 broken, 0 unverified) both pass.Baseline versus final, matched by suite and case identity
All three runs on one host, Linux, 24 cores, under
bin/fm-test-run.sh --all, taken from isolated temporary clones for the two parents so the task branch and its merge structure stayed untouched. Harness taken underclaude, which is what CI's harness-detection and supervision-text suites expect - a non-claude local harness fails those suites spuriously, which is exactly how a real regression hides behind an unchanged failure count, so the set is matched by identity below rather than by count.0344b1d2bin/fm-lint.shexit 07b88520cbin/fm-lint.shexit 0a0e41ea7bin/fm-lint.shexit 0Every remaining merge failure is attributed to the fork parent by suite AND failing-case identity:
tests/fm-test-run.test.shruby is required to parse .github/workflows/ci.yml as YAMLtests/fm-watcher-lock.test.sharm did not exit with HUP status (got 124)tests/fm-remote-job-worker-leak.test.shHUP of the serving worker after its lock directory disappeared left orphaned processesfm-test-runis a host gap (norubyinstalled). The other two are host timing and process-group cases. None is introduced by this round: the merge's failing set is identical to the fork parent's.The upstream parent additionally fails
fm-bootstrap,fm-on,fm-remote-doctor, andfm-session-start. None of those four appears in the merge result, so nothing upstream-parent-only was carried in. The upstream parent runs 160 suites rather than 201 because the fork carries suites upstream does not have; the merge runs 207 because this round addsfm-task-inbox,fm-send-inbox,fm-pi-branch-extension,fm-branch-supervision, and their live-gated siblings.Also green on the merge result:
bin/fm-doc-audience-check.sh(118 surfaces, 630 local links) andbin/fm-pointer-check.sh(32 checked, 0 broken, 0 unverified).Survival evidence for every active deliberate divergence
unverifiable/pendingsend verdictstests/fm-agy-adapter.test.shgreen with the verdict cases retargeted to the plane where those verdicts live, plus the new atomic-prompt doorbell regression and its counterfactual. See "Send contract" above. Entry updated.bin/fm-watch-arm.shstill declares--restartupstream's handling successor viaFM_WATCH_PREDECESSOR_ARM_PID(bin/fm-watch-arm.sh:376,445-446,504), andtests/fm-watcher-lock.test.shretainstest_watch_restart_rejects_reused_pid,test_watch_restart_attaches_to_healthy_peer, andtest_watch_restart_hands_over_within_its_own_budget, all registered in the runner and all passing. The only failing case in that suite is the pre-existing HUP-status case, which fails identically on the fork parent. Both halves hold: a fresh watcher takes the lock inside the arm's own stop budget, and the outgoing watcher is gone by the time it does.wedge_timer_checkkeeps its 5-parameter signature atbin/fm-watch.sh:720, and all four call sites plusbusy_turn_bound_checkpass the hold-count file. Upstream added no newwedge_timer_checkcaller this round, so nothing arrived one argument short.bin/fm-run-progress.shandcrew_wedge_progressare unchanged.git diff 0344b1d2 HEAD -- bin/fm-install-shellcheck.shis empty; the wall-time budget and its comment are untouched bykunchenguid/firstmate#2891..no-mistakes.yamltest.evidence.store_in_repore-read after the merge and stillfalse, with the fork's explanatory comment intact. (This file does not conflict textually, so it is re-read rather than trusted to a clean merge.)AGENTS.md's hard-rule block kept the fork's rule-2 insertion and 3-6 renumbering;tests/fm-agents-hard-rules.test.shpasses.CONTRIBUTING.mdstill does not restore upstream's clone-the-parent instruction (the onlykunchenguidreferences left are the no-mistakes product links).tests/fm-quota-sidecar.test.shpasses.tests/fm-backend-herdr.test.shmerged clean and passes, keeping the fork's renumbered response indices.bin/fm-brief.sh(the# Brainsection still renders in the generated briefs),bin/fm-bootstrap.sh, andbin/fm-teardown.sh;fm-gbrain-*andfm-recallsuites pass.bin/fm-spawn.shstill composes the per-harness event emitters; teardown still publishes the completion manifest and still refuses to erase a task whose manifest could not be written -publish_outcome_manifestremains a blocking `Per-file reasoning for every changed contract file
Conflicted files (20), resolved on meaning:
AGENTS.md- kept the fork's condensed layout lines and added upstream's four new records (config/pi-supervision-branch,<id>.inbox/, the branch outcome store and session,.lease-<task>) rewritten in that condensed style. Upstream's rewritten section 7 steer paragraphs merged clean and now describe the durable-inbox model..agents/skills/harness-adapters/SKILL.md- the "theirs" side was upstream's pre-split per-harness tables, which the fork moved intoharnesses/*.md. Kept the fork's structure and ported upstream's two sentence edits intoharnesses/opencode.mdandharnesses/cursor.md, where those facts now live.bin/fm-send.sh- adopted upstream's two-plane header and rewritten body; re-inserted the fork'sunverifiableparagraph into the typed-plane exit contract, the fork'sTARGET_HARNESSargument tofm_backend_send_text_submit, theunverifiableverdict arm, and the scout completion-gate helpers on both planes. Upstream'sfm_send_known_undelivered_cleanupreplaces the fork's inline discard branches, with the fork'sfm_send_restore_scout_completionkept beside it. Upstream removed the remote branch from the typed block entirely (remote text now rides the inbox), so the fork's remote exit-3 handling there is superseded rather than duplicated.bin/fm-watch.sh- kept the fork'sfm_sup_busy_turn_max_secondswindow and itsbin/fm-supervision-lib.shsource, added upstream'sSECONDMATE_WAKE_STALL_SECS,fm-task-inbox-lib.shsource, and two new stale-reason header entries. Threaded the target harness into the re-ring call.bin/fm-teardown.sh- kept both library sources; ordered upstream'shandoff_wake_retire(retryable route cleanup) before the fork'spublish_outcome_manifest(blocking, last point at which the composed records still exist). In the secondmate path, upstream's stage/restore/commit sequence now wraps the fork'sNO_VERDICT_RETAIN_WORKTREEguard, so a retained worktree still commits the route retirement.bin/fm-brief.sh- kept the fork'sBRAIN_SECTIONand ship-onlyPROJECT_MEMORY_SECTIONvariables and added upstream's$INBOX_SECTIONin the ordering the already-merged charter template established (inbox, then brain, then the rest).bin/fm-pr-merge.sh- kept the fork'sfm-issue-lib.sh/fm-forge-lib.shsources and added upstream'sfm_lease_forbid_branchguard. Re-verified for this PR's own landing:caller_has_merge_methodstill detects an explicit--merge, so--squashis not added and--mergeis forwarded verbatim togh-axi pr merge.bin/fm-test-run.sh- took upstream's re-wrapped family lists and newfm-task-inboxrouting, unioned thelive-harness-optinlist so the fork'sfm-agy-smoke,fm-gbrain-*,fm-cmux-claude-composer, andfm-dashboard-browserentries survive alongside upstream's newfm-pi-branch-live-e2eandfm-send-inbox-doorbell-live-e2e, and kept the fork's dashboard-inclusivesnapshot-bearingsarm..pi/extensions/fm-primary-pi-watch.ts- import-line conflict only; kept bothexistsSync(fork away-flag read) andreaddirSync(upstream queue project scan).CONTRIBUTING.md- took upstream's two new fixture-timeout sentences and kept the fork's wording about opt-in live tests staying outside portable lanes.docs/architecture.md- adopted upstream's reworded secondmate sentence (which now distinguishes worktree-write probing from the new wake-queue probing) and dropped the duplicate busy-pane sentence the fork had already moved into the run-progress paragraph.docs/configuration.md- kept the fork'sdata/and fleet-data-contracts lines while taking upstream's inbox clause into thestate/sentence; kept the fork's agy sentence beside upstream's typed-plane Cursor rewording; kept the fork's four supervision env lines and added upstream'sFM_SECONDMATE_WAKE_STALL_SECS.docs/herdr-backend.md- adopted upstream's typed-plane framing sentence and rewrote the following sentence so the fork's cursor/agy atomic-prompt paragraph reads as part of that plane rather than an unrelated "instead"; applied upstream's agent-process liveness rewording to the fork's longer bullet.docs/scripts.md- took upstream's updatedfm-send.shrow and four new rows, kept the fork'sfm-trigger-validation.shrow.docs/supervision-protocols/pi.md- kept both paragraphs: the fork's away-mode standby rule and upstream's supervision-branch delegation rule.docs/verification/runtime-backends.md- both sides added a new section at the same position; kept the fork's agy control-mechanics record and upstream's Pi supervision-branch record.tests/fm-gotmp.test.sh- unioned the teardown fixture symlinks, folded the twofm-timeout-lib.shrationales into one comment, and removed the duplicatefm-control-lib.shlink that the union would otherwise have made a secondln -sonto an existing path.tests/fm-remote-job.test.sh,tests/fm-remote-secondmate-lifecycle-e2e.test.sh,tests/fm-send-popup-settle.test.sh- kept both sides; the popup-settle case adopts upstream'srides_inboxassertion and keeps the fork's trailing all-tests-passed marker.Non-conflicted contract files worth naming:
bin/fm-task-inbox-lib.sh(new, upstream) - amended sofm_task_inbox_ringtakes and forwards the target harness; the header comment records why that argument is not optional in effect.bin/fm-remote-secondmate-control.sh- resolvesREMOTE_ENDPOINT_HARNESSfrom the endpoint metadata and passes it to the ring.tests/fixtures/fm-brief-no-issue.sha256- regenerated for upstream's new instruction-inbox section (about +600 bytes per variant, +735/+759 for the two secondmate charters, which also gained a sentence). Values match whattests/fm-brief.test.shindependently computes; the suite is green.docs/fork-divergence.md- see below.Parked branches
The ledger's parked-branch list is
docs/fork-divergence.md"Parked branches outside the fork baseline":fm/fm-afk-injection-wedge,fm/fm-crew-state-blind-during-fix-round,fm/fm-parked-decision-stale-noise,fm/fm-subagent-model-routing-guard,fm/fm-vault-drift-check.Each was checked with
git merge-base --is-ancestor <branch> HEAD; none is an ancestor of this branch. Nothing was merged, rebased onto, resurrected, or cherry-picked from any of them.Ledger changes in this round
unverifiable/pendingverdicts to the typed plane, that the distinction itself is unchanged, thattests/fm-agy-adapter.test.shnow names the plane so a verdict case cannot go vacuous, and that the inbox plane still owes this adapter its atomic prompt through the harness argument every ring caller resolves from metadata.Head and mergeability
c5e824c2658a5b33626831f43c45e8d09d75967corigin/main=32d2e6ca1fc40c8251cefc78b8972a7d55f71d2d(afterHelloWorldSungin/firstmate#200)git merge-base --is-ancestor origin/main HEADsucceeds, so the base is an ancestor of this head and no conflict is possible;git merge-tree --write-tree origin/main HEADwrites a tree cleanly.PR must be raised via no-mistakes; every other check must be green. The previous head4f8364cfreached exactly that state (16 passed, 1 failed), includingBehavior portable serial 6, which the Repair 3 fixture fix turned green.Expected red check
This round ships direct-PR, not through no-mistakes. The no-mistakes pipeline rebases onto
origin/main, which would replay and linearize this merge-only branch and destroy the upstream parentage the round exists to preserve. The fork's compliance workflow requires a no-mistakes signature with no bypass for direct PRs, so this PR carries the redPR must be raised via no-mistakescheck by design. Every other required check must pass.Landing
Do not squash. Land with:
The script defaults to squash, and squashing loses upstream parentage and prevents the merge base from advancing. The explicit
--mergeis load-bearing. Rounds 1 and 2 both proved this path: the merge base moved1cb900c2to52d20f13tof170cedeexactly as intended, and this round should move it to7b88520c.