Skip to content

Sync upstream through 2e65d2e24822 with additive Gemini support - #271

Merged
HelloWorldSungin merged 33 commits into
mainfrom
fm/fm-upstream-sync-2026-09-08-round-3
Sep 11, 2026
Merged

Sync upstream through 2e65d2e24822 with additive Gemini support#271
HelloWorldSungin merged 33 commits into
mainfrom
fm/fm-upstream-sync-2026-09-08-round-3

Conversation

@HelloWorldSungin

@HelloWorldSungin HelloWorldSungin commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Integrate the second of four remaining approved upstream prefixes, through kunchenguid/firstmate@2e65d2e2482247c22db2ba7aeeb055eb7876fef1.
This takes 24 first-parent changes while preserving the fork's agy transport/trust, launch owner, daemon-owned away supervision, run attribution, bounded snapshots, GBrain and dashboard behavior.

Topology and publishing scope

  • Exact fork parent: f49a50d4f2cc1dcad6005c835a62d1e377419b71.
  • Exact upstream parent: 2e65d2e2482247c22db2ba7aeeb055eb7876fef1.
  • Measured merge base: d43e610b0a6b1c6eb79bcf37e6c41074d89a4c6d.
  • The one upstream merge commit is 974e9e88485e3b324f80f8f8b11af223ab547580, with exactly those two parents.
  • Exact pushed head: 14de8ecb36fd384925ad018ea1ee63ca0faf899f.
  • Branch: fm/fm-upstream-sync-2026-09-08-round-3; target: HelloWorldSungin/firstmate:main.
  • The eventual ceiling remains 4768e98d469b7216569acf6e7a5cc696ecd15c2e; later upstream heads did not widen this prefix.
  • The 152-path remaining-range inventory was preserved; exact prefix intersection is 95 overlap paths across 149 upstream-changed paths.
  • No rebase, cherry-pick, squash, force push, default-branch write or third-party upstream write occurred.

Validation

Revision Scripts Failures Gate skips Full lint
Fork parent 225 0 30 exit 0
Upstream parent 185 7 27 exit 0
Final branch head 233 0 30 exit 0

Both exact parents were tested in independent copies with unchanged tracked bytes, deliberate umask 022, real HOME for Herdr discovery, cleared inherited fleet endpoint variables, and scratch Claude configuration.
The final committed copy also enables strict installed-Pi checks and credential-free real SDK/TUI guards.

Upstream-only baseline failures were retained: missing-node fixture leakage in bootstrap/session-start, unavailable Ruby in two YAML checks, Nix PATH and remote-wrapper expectations, and one OpenCode external-healthy assertion.
The OpenCode assertion did not reproduce in isolated, delayed-guard, real-HOME, or instrumented full-suite diagnostics; its cause remains unconfirmed, and no production fix is claimed for it.
Existing fork fixture protections survive, and the new YAML contract uses an available real parser without installing tools.

Focused candidate checks passed for launch rendering, brief generation after its exact ADR expectation was updated, run-state attribution, test selection, all four affected worker adapters, dispatch, teardown and snapshot behavior.
Strict Pi typechecking passed against Pi 0.85.1 with already-cached TypeScript 7.0.2.
The final-head offline Pi TUI measured worst echo 3.7 ms unloaded, 12.9 ms extension-idle and 13.1 ms during delivery; these are host-local samples.
The real SDK guard covered construction, rejected-provider fallback, model/effort precedence, visible outcome persistence and streaming consumption without provider requests.

Compatibility decisions

The public bootstrap path reproduced the configured-profile defect in this exact prefix: a Gemini default profile was rejected while the Codex control was accepted.
The smallest reachability fix adds Gemini to the verified configured-profile list; default, rule, and profile-array cases pass without changing authentication or fleet dispatch defaults.

  • Firstmate retained strict local commit identity for teardown. The destructive ledger-only abort from the upstream teardown change is deliberately omitted; compatible row validation remains in the fork relation-table owner, including malformed-input degradation.
  • Gemini CLI and Antigravity/agy remain distinct. Gemini adds per-task semantic hooks; agy keeps its crew-only/Herdr-only restrictions, owned trust cleanup and atomic inbox transport.
  • Gemini, Rovo and OMP launch construction stays in bin/fm-launch-lib.sh. Explicit adapter path bindings render once, preserving literal placeholder-like path text.
  • The new Treehouse lock traversal initially refused a remotely parented home's worker spawn. An executable fork/upstream comparison reproduced it; the local traversal now stops at a validated remote parent boundary while local peers share locks and malformed/cyclic bindings still refuse.
  • OMP receives the fork's existing .afk standby, with pending-wake and replacement regression coverage. Later AFK-posture changes remain excluded.
  • Pi keeps selective context transfer, stable prompt structure, sequence-keyed visible outcomes, separate processed acknowledgements and generation/lease ownership. Later provider-registry sharing, Windows shell transport and native-Codex integration remain outside this prefix.
  • Structured hold buckets use the existing bounded snapshot owner and preserve abandoned children and the dashboard's read-only cache mode.
  • Final validation exposed a legacy combined-hold parsing regression through the real Backlog endpoint. The follow-up preserves (repo: project, hold: reason) alongside canonical comma-containing reasons and rejects unparenthesized title prose.

The real-Herdr fixture audit reproduced same-slot reuse after a stopped process while a completed p1 record remained; the existing exclusive teardown refused it.
A normal pre-restart retirement control passed, and a registered cross-home negative proved the same refusal across local homes.
A full diagnostic pass still contained cross-home overlapping records because its hand-built secondmate homes lacked parent/registry bindings; that pass was not accepted as ownership coverage.
The recovery fixture now registers one ownership tree, retires completed tasks before restarting their lab, preserves a task-free presentation parent, and retries only documented lock refusals in positive concurrent cases.
Cleanup joins operations, stops the named lab, checks remaining claims and repository identity before ordinary returns, and preserves source Git metadata plus separate logs on failure.
Portable deliberate failure/double-cleanup cases and both final real entrypoints validate that fixture contract without changing production allocation or exclusive-slot policy.
The original 11 stranded diagnostic slots remain untouched and explicitly unresolved under Firstmate instructions.

The pre-split fixture took about 516 seconds, so green explicit-900-second validation did not preserve usable ordinary 480-second validation.
Firstmate required the default path to be restored without inflating its bound.
Presentation/focus/negative/concurrency coverage now lives in one entrypoint and registered multi-home/recovery/generation coverage in another.
They share only common fixture functions and own separate source, home, lab, evidence and task identities, with no state handoff.
All 242 original assertion lines retain their multiplicities and all 25 success labels remain; the first suite additionally retires its own anchor.
The finalized ordinary named-script runs passed in 295.146 and 232.258 seconds, with no timeout override and successful cleanup/default-session tripwires.
The temporary CI 900-second override was removed; ordinary local and CI selection use the unchanged 480-second default and existing outer CI limits.
The final complete run uses canonical bin/fm-test-run.sh --all with no per-script override, followed by exact-head canonical lint evidence.

The new dead/missing-endpoint inbox guard exposed a strict-send fixture that omitted two positive window names and retained a pre-prefix doorbell expectation.
Only the fixture changed; the missing-endpoint negative still records the steer durably without typing, and scout completion/unknown-delivery checks remain intact.

Runtime evidence and limits

Runtime Interface and role boundary Local coverage
Gemini Google gemini; interactive /model; effort recorded and omitted; per-task BeforeAgent/AfterAgent/SessionEnd settings; no primary or secondmate protocol. Existing Gemini auth is required and is not agy auth. Executable absent; portable adapter tests only. Upstream dated live evidence is retained.
agy Antigravity agy; own trust store; model flag and low/medium/high effort; crew/design/scout on Herdr only; no raw bypass. Installed 1.2.0 help/version observed; portable lifecycle/atomicity/trust tests. No new credentialed live trial.
Rovo Bare launch then readiness/brief/delivery; /models; one JSON override combines external-path grants and effort. Crew/scout only; skill-schema and ghost-composer limits remain documented. Executable absent; portable adapter tests only.
OMP Bun executable; models --json omits extension providers, which remain disclosed unvalidated; --thinking; separate worker hooks and primary protocol; remote secondmate launch refused. Executable absent; portable API/lifecycle/standby tests only.
Pi Existing multi-conversation supervision receives async delivery and decision routing; no new provider authentication. Installed 0.85.1: strict types, real SDK and isolated offline TUI.

No credentials were copied or configured, no tools installed, no fleet dispatch defaults changed and no services deployed.
Missing live adapters and gated tests are explicit limits, not live passes.
The routine-outcome replay residual after a failed mark-read and the async helper's lack of a general child wall-time bound remain documented.

Every upstream first-parent change

Upstream Change Disposition
kunchenguid/firstmate@a5c64a0b6791 (a5c64a0b6791) feat: add verified Gemini crewmate runtime adapted: Add Gemini separately from agy; use the fork launch owner and repair configured-profile reachability.
kunchenguid/firstmate@8f7b79c77c21 (8f7b79c77c21) fix(teardown): conclude parked runs advanced past task copy adapted: Take row validation; Firstmate explicitly excludes ledger-only unfetched-run abort and retains strict local identity.
kunchenguid/firstmate@86ff1bf5e67b (86ff1bf5e67b) fix: classify captain holds from structured state adapted: Add structured hold buckets to the existing bounded snapshot, preserving abandoned children and read-only cache mode. Retain legacy combined hold metadata as well as canonical comma-containing reasons.
kunchenguid/firstmate@f09de8a3d3a5 (f09de8a3d3a5) fix(pi): keep supervision outcome delivery responsive adapted: Take async delivery and serialization; preserve fork standby and reconcile the equivalent stock-renderer fixture.
kunchenguid/firstmate@1820316b66ac (1820316b66ac) fix: avoid duplicate AGENTS.md governance for marked projects adapted: Take explicit governance-marker recognition and route the fork's composed project-memory section to that owner.
kunchenguid/firstmate@64304b6b1604 (64304b6b1604) fix: protect primary checkout when spawning from linked homes adapted: Protect repository-primary checkouts from linked homes while retaining design and durable task-branch identity.
kunchenguid/firstmate@e075c964dfa5 (e075c964dfa5) fix(bin): stop reading an unanswered backend probe as a dead endpoint adapted: Use positive endpoint-death evidence while retaining fork degraded and abandoned-worker reconciliation.
kunchenguid/firstmate@8fd5575b1179 (8fd5575b1179) fix(bin): preserve subshell lock ownership on Bash 3.2 taken cleanly: Adopt current-frame PID capture and lock ownership under Bash 3.2.
kunchenguid/firstmate@af8c4b62182b (af8c4b62182b) fix(bin): resolve captain holds and legacy teardowns on non-markdown backends adapted: Adopt backend-aware holds and guarded legacy cleanup; retain fork design, manifest, branch and preserving-refusal gates.
kunchenguid/firstmate@a29cdcef1e77 (a29cdcef1e77) fix: reduce local ShellCheck source-analysis cost adapted: Adopt local source-analysis reduction; keep full CI lint and run new cases before the fork success marker.
kunchenguid/firstmate@d6660d75d0fc (d6660d75d0fc) fix(pi): route decision-owned wake batches to main adapted: Route decision-owned batches to main without dropping standby or run-progress behavior; test authored-resolution syntax without importing the detector.
kunchenguid/firstmate@f19efa69de36 (f19efa69de36) feat(bin): add opt-in worker launch environment allowlist adapted: Add opt-in launch environment filtering while preserving fork inherited configuration and launch-command ownership.
kunchenguid/firstmate@f9aca259487f (f9aca259487f) feat(bin): add rovo crewmate/scout adapter with home-path file access adapted: Add Rovo's staged launch and task-local grants through the shared launch owner; retain documented interoperability limits.
kunchenguid/firstmate@12fc10e16ecb (12fc10e16ecb) fix(bin): prevent false pipeline blocks after drive timeouts adapted: Adopt live-pipeline transport reconciliation while retaining fork DOD handoff, liveness and degraded state.
kunchenguid/firstmate@702004ed590d (702004ed590d) fix(bin): scope the worker role contract for ship and scout launches adapted: Apply launch-only worker role scope to design too, preserving authored-brief structural identity and secondmate charters.
kunchenguid/firstmate@c499f84e8b46 (c499f84e8b46) fix(bin): stop ringing steering doorbells into dead panes adapted: Suppress dead-pane typing and quote doorbells while retaining agy's harness-aware atomic path and scout reopen semantics.
kunchenguid/firstmate@51d2e8c902bb (51d2e8c902bb) fix(bin): wait out transient primary-checkout reads in the spawn worktree poll adapted: Wait for two valid isolated reads, retain design/work-item cases, and replace timing-based fixture expectations with actual read counts.
kunchenguid/firstmate@c562be1a9255 (c562be1a9255) fix: support stock macOS Bash 3.2 paths taken cleanly: Adopt empty-array and localized composer fixture compatibility for stock macOS Bash.
kunchenguid/firstmate@a91353942307 (a91353942307) fix(bin): read orphaned green ci monitor and daemon-down failed record as not failed adapted: Adopt orphaned green-CI and unavailable-daemon readings without discarding recorded-branch or newer-wait precedence.
kunchenguid/firstmate@85ad5e7d9b01 (85ad5e7d9b01) fix(spawn): verify preserved backlog state after interrupted spawn delivery adapted: Verify interrupted spawn preservation under bounded calls while retaining watermark-failure metadata preservation.
kunchenguid/firstmate@f3b7e74479d6 (f3b7e74479d6) docs: correct runtime-backend maturity labels for Herdr adapted: Correct Herdr maturity in its owners while keeping the fork's concise inventory and verification pointers.
kunchenguid/firstmate@f91a95097bc4 (f91a95097bc4) fix: restore intent-targeted no-mistakes validation adapted: Remove deterministic gate tests, keep evidence local, retain fork DOD behavior, and use an available YAML parser in the fixture.
kunchenguid/firstmate@b028e8b14a1f (b028e8b14a1f) fix: verify Treehouse slot ownership before teardown adapted: Take project locks and slot exclusivity; fix the reproduced remote-parent refusal without weakening local ownership checks.
kunchenguid/firstmate@2e65d2e24822 (2e65d2e24822) feat(bin): add verified omp (Oh My Pi) harness adapter for crew, secondmate, and primary adapted: Add OMP through the fork launch owner and carry legacy away-daemon standby; retain distinct lifecycle and unverified live limits.

Active-divergence survival

Active divergence Behavioral witness
Agy crew adapter tests/fm-agy-adapter.test.sh: passed; tests/fm-launch-lib.test.sh: passed
Pinned ShellCheck download retry budget tests/fm-lint.test.sh: passed
LLM quota sidecar tests/fm-quota-sidecar.test.sh: passed
Scout completion gate reopened by a firstmate steer tests/fm-send-strict.test.sh: passed
Watcher restart hand-over tests/fm-watcher-lock.test.sh: passed
Watcher stop-signal disposition tests/fm-backend-herdr.test.sh: passed; tests/fm-watcher-lock.test.sh: passed
Run-progress wedge hold tests/fm-daemon.test.sh: passed; tests/fm-watch-triage.test.sh: passed
Watcher live declared-wait routing and self-widening recheck cadence tests/fm-daemon.test.sh: passed; tests/fm-watch-triage.test.sh: passed
Herdr pre-Enter footer read on a native working baseline tests/fm-backend-herdr.test.sh: passed
Remote job worker descendant reaping tests/fm-remote-job-orphan-reap.test.sh: passed; tests/fm-remote-job.test.sh: passed
Bounded remote job stdin capture tests/fm-remote-job.test.sh: passed
Default per-script bound on every test sweep tests/fm-on.test.sh: passed; tests/fm-test-run.test.sh: passed
Locale-independent test coverage comparisons tests/fm-test-run.test.sh: passed
Queued wakes remain a supervision requirement tests/fm-guard-stale-banner.test.sh: passed; tests/fm-turnend-guard.test.sh: passed; tests/fm-wake-queue.test.sh: passed
No-mistakes run attribution tests/fm-crew-state.test.sh: passed; tests/fm-teardown.test.sh: passed
Definition-of-done owner carries this fork's ready-to-validate handoff tests/fm-trigger-validation.test.sh: passed
A preserving refusal withdraws the pending backlog close tests/fm-backlog-atomicity.test.sh: passed
A watermark-capture failure keeps the published task record tests/fm-spawn-dispatch-profile.test.sh: passed
Fleet snapshot per-task timeout and abandoned child work tests/fm-bearings-snapshot.test.sh: passed; tests/fm-fleet-snapshot-view.test.sh: passed; tests/fm-home-summary-refresh.test.sh: passed; tests/fm-dashboard-backlog.test.sh: passed
Pi and OMP away-mode supervision standby tests/fm-pi-watch-extension.test.sh: passed; tests/fm-omp-harness.test.sh: passed
Local lock scope for remotely parented homes tests/fm-spawn-worktree-settle.test.sh: passed; tests/fm-teardown-endpoint-safety.test.sh: passed
Fork-local no-mistakes compliance-gate event scope tests/fm-no-mistakes-required-gate.test.sh: passed
Live pull-request body refresh before the compliance gate tests/fm-no-mistakes-required-gate.test.sh: passed
Merge-proof contract: one divergence accepted, one retired tests/fm-pr-merge.test.sh: passed
Upstream tracking mechanism tests/fm-upstream-status.test.sh: passed
Repository-local validation evidence Parsed .no-mistakes.yaml: store_in_repo=false; no pipeline invoked.
Upstream-read-only posture in shared tracked docs tests/fm-agents-hard-rules.test.sh: passed
GBrain per-home knowledge memory tests/fm-bootstrap.test.sh: passed; tests/fm-brief.test.sh: passed; tests/fm-gbrain-capture.test.sh: passed; tests/fm-gbrain-health.test.sh: passed; tests/fm-gbrain-pin-check.test.sh: passed; tests/fm-gbrain-readonly-e2e.test.sh: gate skipped; tests/fm-recall.test.sh: passed; tests/fm-remote-secondmate-lifecycle-e2e.test.sh: passed
Fleet dashboard and agent-event instrumentation tests/fm-bearings-snapshot.test.sh: passed; tests/fm-dashboard-browser.test.sh: gate skipped; tests/fm-dashboard-events.test.sh: passed; tests/fm-dashboard-gbrain-ui.test.sh: passed; tests/fm-dashboard-gbrain.test.sh: passed; tests/fm-dashboard-history.test.sh: passed; tests/fm-dashboard-usage.test.sh: passed; tests/fm-dashboard.test.sh: passed; tests/fm-dashboard-backlog.test.sh: passed
Herdr presentation fixture ownership and cleanup tests/fm-backend-herdr-presentation-e2e.test.sh: passed; tests/fm-backend-herdr-recovery-e2e.test.sh: passed; tests/fm-test-fixture-cleanup.test.sh: passed

Changed contract files

File Contract reasoning
.agents/skills/bearings/SKILL.md Use structured hold buckets while retaining independent active and abandoned-child visibility.
.agents/skills/captain-hold-lifecycle/SKILL.md Route hold mutations through the timestamp-owning wrapper; preserve exact recorded-answer and completion policy.
.agents/skills/firstmate-coding-guidelines/SKILL.md Adopt intent-targeted no-mistakes test policy; keep historical timing evidence out of the agent contract.
.agents/skills/harness-adapters/SKILL.md Register Gemini, Rovo and OMP additively; retain agy restrictions and explicit crew-only boundaries.
.agents/skills/harness-adapters/references/common/dispatch.md Keep launch-library ownership and route role support through the catalog instead of a stale two-adapter list.
.agents/skills/harness-adapters/references/harness/gemini.md Retain credential-dialog hazard, hook ownership and unsupported-primary boundary; normalize skill-root pointers and launch owner.
.agents/skills/harness-adapters/references/harness/muse.md Point at the shared primary boundary while keeping Muse crew/scout scope.
.agents/skills/harness-adapters/references/harness/omp.md Document OMP's distinct lifecycle, overlay and discovery; add the existing away-owner pointer without claiming a Pi branch or new live coverage.
.agents/skills/harness-adapters/references/harness/rovo.md Retain launch-then-send, external-file grants, skill-schema and composer limitations; repair resource and launch-owner pointers.
.agents/skills/quota-array-dispatch/SKILL.md Add OMP's narrow helper mapping without replacing catalog-led provider identity or the fork quota sidecar.
.agents/skills/secondmate-provisioning/SKILL.md Use the inherited-item owner, distinguish remote prelaunch refusal, and retain brain and parent-channel safeguards.
.agents/skills/stow/SKILL.md Route deferred captain holds through their wrapper; retain fork memory and brain behavior.
.agents/skills/stuck-crewmate-recovery/SKILL.md Separate live pipeline transport failures from positive daemon-down evidence; never authorize shared-daemon restart.
.github/workflows/ci.yml Retain upstream CI coverage changes and remove the temporary 900-second Herdr override after both split default named paths passed; preserve the existing 20-minute step and 75-minute job limits.
.no-mistakes.yaml Remove deterministic commands.test; retain canonical lint, local-only evidence and existing instruction isolation.
.omp/extensions/fm-primary-omp-watch.ts Adopt OMP main-only watcher ownership and replacement replay, with fork legacy .afk standby and pending-wake retention.
.omp/extensions/fm-primary-turnend-guard.ts Adopt OMP session_stop continuation, startup delivery and pre-tool guards; keep its API distinct from Pi.
.omp/fm-worker-overlay.yml Pin only per-launch unattended-worker posture; never rewrite the user's OMP configuration.
.pi/extensions/fm-branch-supervision.ts Adopt awaited subprocess delivery and serial delivery queue; retain durable-before-visible ordering, generation checks and processed acknowledgements.
.pi/extensions/fm-primary-pi-watch.ts Route decision-owned trigger batches to main while retaining away standby, generation handoff and deadline-settlement protections.
.pi/extensions/lib/fm-async-exec.ts Provide bounded-output asynchronous subprocess results without claiming a general wall-time or descendant-kill guarantee.
.pi/extensions/lib/fm-branch-dispatch.ts Add decision-owned row classification and async grant operations; preserve task-scoped claims and independent heartbeat eligibility.
.pi/extensions/lib/fm-operational-input.ts Share command/answer semantics between synchronous and awaited encoding; keep existing envelopes unchanged.
AGENTS.md Preserve fork hard rules and concise inventory; register new role support, hold owner and reconciled validation behavior.
CONTRIBUTING.md Adopt targeted gate testing and local/full lint distinction while retaining fork publication and documentation discipline.
README.md Add supported OMP startup and accurate Herdr maturity; retain existing fork-specific navigation and deferred install-link policy.
bin/backends/tmux.sh Add structural Gemini argv liveness and OMP/Rovo process classes without granting identity from arbitrary arguments.
bin/fm-backlog-transition-lib.sh Address non-markdown backends without --file and bound locked tasks-axi calls; preserve atomic transition and replay ownership.
bin/fm-bearings-snapshot.sh Project structured hold buckets and exclusive decision gates while preserving active/abandoned child projections.
bin/fm-bootstrap.sh Union adapter profiles and repair reproduced Gemini omission; retain agy effort/backend guards and fork diagnostics.
bin/fm-brief.sh Adopt transport-error guidance and governance-owner pointer while retaining brain, design, work-item and continuation contracts.
bin/fm-busy-lib.sh Add Gemini/OMP semantic sources and Rovo-only positive busy fallback; retain agy's identity-gated native path.
bin/fm-captain-hold.sh Add hold lifecycle stamps and backend-aware resolution with interrupted-answer normalization; preserve durable exact answers and design completion.
bin/fm-classify-lib.sh Expose decision-owned signal classification alongside unchanged status bytes, including held and pending-reply events.
bin/fm-composer-lib.sh Add OMP TUI busy signals and status-row boundaries without broadening Rovo ghost stripping or agy composer classification.
bin/fm-config-inherit-lib.sh Add opt-in launch environment names and distinguish absence from inspection failure; retain GBrain and board inheritance.
bin/fm-control-lib.sh Add new adapter lifecycle/wiring rows while retaining agy role and interrupt semantics.
bin/fm-crew-state.sh Add positive-death fallback, live-run transport reconciliation and terminal CI/daemon cases; retain recorded branch, degraded and abandoned states.
bin/fm-dod-lib.sh Keep fork delivery fragments as sole owner, add worker role for design too, and adopt bounded drive-call guidance.
bin/fm-ensure-agents-md.sh Recognize the exact project-maintained governance marker without inferring equivalent prose.
bin/fm-fleet-snapshot.sh Add hold classification to the fork's one bounded row builder; preserve generation completeness, local-time since age, extra fields and read-only cache mode. Preserve legacy combined hold metadata and canonical comma-containing reasons.
bin/fm-gemini-lib.sh Own narrow process-script identity with NUL argv support; never probe a stranger's binary.
bin/fm-harness.sh Add Gemini/Rovo marker precedence and ancestry-gated OMP marker without equating model and harness identity.
bin/fm-home-summary-refresh.sh Require the current hold-classifier schema while retaining abandoned-child validation and atomic publication.
bin/fm-launch-lib.sh Keep the sole template/flag owner, add three adapters and combined Rovo grants, and substitute explicit adapter paths in one pass.
bin/fm-lint.sh Adopt bounded local source-analysis reduction while retaining complete pinned canonical lint under CI=true.
bin/fm-nm-run-lib.sh Integrate row validation into the relation-table owner; retain terminal exact-HEAD anchor and classify malformed input as inconclusive.
bin/fm-quota-choose.sh Map only OMP's established openai-codex/claude-bridge prefixes and preserve unknown-provider refusal.
bin/fm-remote-home-seed.sh Preserve empty-array behavior under stock Bash 3.2 without changing remote placement.
bin/fm-remote-inherit-push.sh Treat source inspection errors as errors, not deletion authority; retain fork special inherited planes.
bin/fm-remote-secondmate-control.sh Report dead-pane doorbell suppression while retaining the recorded harness for atomic agy delivery.
bin/fm-secondmate-restart.sh Resolve arrived persist replies before timeout handling and recheck at the deadline.
bin/fm-send.sh Keep durable enqueue and scout gate reopening; disclose dead-endpoint recovery without typing into a dead pane.
bin/fm-session-lock-lib.sh Recognize exact OMP process identity without claiming similarly named commands.
bin/fm-session-start.sh Add OMP extension-presence diagnostics while retaining fork brain and startup composition.
bin/fm-spawn.sh Combine new stateful adapter wiring, role overlay, environment opt-in and slot locks with fork launch owner, design/branch identity and trust/watermark preservation.
bin/fm-supervision-instructions.sh Render OMP's dedicated protocol and repair instruction; preserve per-harness ownership.
bin/fm-task-inbox-lib.sh Adopt quoted shell-no-op doorbells, control-byte refusal and positive-death checks while retaining harness-aware agy atomic transport.
bin/fm-teardown.sh Adopt exclusive-slot and guarded legacy-record checks; omit ledger-only abort per Firstmate and preserve manifests, trust, design and refusal rollback.
bin/fm-test-run.sh Keep fork timeout and coverage invariants; add new suites and ensure Gemini/OMP shared consumers remain selected. Register recovery in the existing real-Herdr family; ordinary --all selects both and the default 480-second timeout is unchanged.
bin/fm-wake-lib.sh Adopt Bash 3.2 frame identity, OMP ownership proof and project locks; stop local ancestry at a validated remote parent boundary.
bin/fm-watch-checkpoint.sh Give the Perl timeout path bounded retirement grace before escalation.
bin/fm-watch.sh Add decision-row sideband and unavailable-inbox recovery while retaining signal disposition, run-progress holds and paused cadence.
docs/agent-control.md Document new adapter capabilities through the shared control owner without changing cleanup authority.
docs/architecture.md Explain adopted state/slot/adapter behavior while retaining fork attribution, abandoned/degraded reporting and strict teardown.
docs/arm-pretool-check.md Add OMP's actual tool-call integration without generalizing another harness's hook surface.
docs/captain-hold-lifecycle.md Document stamp/retry and backend-migration behavior while retaining the design completion gate.
docs/cd-guard.md Record OMP's pre-tool integration under the existing guard owner.
docs/configuration.md Add adapter, hold-age and launch environment contracts; retain fork timeouts and correct the existing local-evidence setting drift.
docs/documentation-audiences.json Classify new references/evidence and bind the OMP away-owner pointer without dropping fork documentation.
docs/extension-bindings.md Preserve host-owned package loading independently of harness identity, replacing the incomplete runtime enumeration.
docs/fork-divergence.md Maintain all 30 active divergences and explicit exclusions; describe the independently owned Herdr split, ordinary timeout behavior, and unchanged production ownership guards.
docs/herdr-backend.md Keep the Herdr role/transport contract and point current presentation versus multi-home/recovery coverage at their separate, independently owned entrypoints.
docs/pi-supervision-branch.md Document async delivery and decision routing with exact outcomes, processed acknowledgements and the routine replay residual intact.
docs/scripts.md Catalog new Gemini helper and worker-role ownership while retaining design and fork tools.
docs/sessionstart-nudge.md Add OMP's verified startup tier and source derivation through its own extension.
docs/subagent-guard.md Record OMP's applicability without assuming Claude delegation tool names.
docs/supervision-protocols/omp.md Add dedicated extension-owned OMP wake protocol, not a Pi supervision-branch claim.
docs/supervision-protocols/pi.md Point decision-owned routing to the branch contract while preserving away ownership and processed-result duties.
docs/tmux-backend.md Document exact OMP and structural Gemini liveness and remove the stale closed harness enumeration.
docs/trace-context.md Preserve design/agy scope and refer role/backend coverage to the adapter owner instead of a stale enum.
docs/turnend-guard.md Add OMP's blocking session_stop integration while retaining existing primary limits.
docs/verification/lint-option-a.md Retain dated reusable evidence for the adopted local lint behavior.
docs/verification/rovo.md Retain dated Rovo core-runtime proof and explicit interoperability limitations; no local live rerun claimed.
docs/verification/runtime-backends.md Record current Pi verification and measured default-bound Herdr split timings; retain older monolithic command records as historical evidence and name both current refresh entrypoints.
docs/verification/supervision.md Adopt dated OMP/startup evidence without erasing fork watcher stop guarantees.
docs/watcher-continuity.md Preserve daemon standby and fork Pi/OpenCode deadline settlement, and describe OMP's separate generation path accurately.
tests/fm-backend-herdr-presentation-e2e.test.sh Retain default/opt-out, focus, move/abort negatives and all three concurrency waves in an independent default-bounded entrypoint; retire its own distinct anchor normally and finish through the guarded cleanup owner.
tests/herdr-presentation-cleanup.sh Single fixture cleanup owner joins operations, shuts down the named lab, verifies source and absence of task claims before ordinary returns, and retains failed sources and evidence with an idempotent verdict.
tests/fm-test-fixture-cleanup.test.sh Exercise real cleanup owner with real linked Git worktrees and local command doubles: deliberate return/lab failures, outstanding operations, recorded claims, foreign repositories, and double cleanup.
tests/fm-send-strict.test.sh Declare the queued-wake and scout positive endpoints in the mock inventory and expect the new shell-no-op doorbell prefix. Keep the new missing-endpoint suppression guard intact with a real send-path negative that preserves its durable inbox record and sends no keys.
tests/fm-spawn-worktree-settle.test.sh Keep the public remote-parent spawn reproduction and malformed/local-cycle refusal cases; quote the fixture task ID so full extended ShellCheck treats it as the literal identifier it is.
tests/fm-backend-herdr-recovery-e2e.test.sh Move the existing multi-home, registered ownership/lock, generation/restart, legacy/token and cleanup checks intact into an independent real-Herdr entrypoint; use separate source/home/lab/evidence and disjoint task IDs.
tests/herdr-presentation-fixture.sh Share only common setup, instrumentation, project/layout seed and guarded finish functions; keep entrypoint-specific helpers with their scenarios and never transfer fixture state.
bin/fm-test-isolation-proof.sh Keep the new recovery entrypoint explicitly in the real-Herdr serial isolation category, without granting parallel execution.

Fixture reconciliation

Positive fixtures retain valid intent/spec and authored-brief identity, while intentional raw-launch, role/backend, malformed metadata, ownership and unsafe-state negatives remain enforced.
The new tests cover Gemini profile reachability, single-pass bindings, combined Rovo grants, OMP away ownership, remote-parent lock scope, strict unfetched-run refusal, malformed-ledger degradation and tagged resolution compatibility.
The eight brief fingerprints were regenerated from the canonical renderer, not hand-edited.
Claude/config-writing fixtures retain scratch destinations; Pi SDK/TUI probes now clear ambient credentials and user extension discovery and clean their disposable state.

Old-to-new Herdr coverage inventory

The source before splitting is preserved at commit bd149b959b6f0ce85be634c94f80278040356d8a.
All 242 original assertion lines retain their multiplicities; all 25 success labels remain.

Original lines Coverage New owner
1-501 Shared instrumentation and helper functions tests/herdr-presentation-fixture.sh plus entrypoint-local functions
501-537 Independent project/anchor initialization presentation_fixture_seed_project plus per-entrypoint briefs
537-976 Presentation/focus/negative/concurrency scenarios tests/fm-backend-herdr-presentation-e2e.test.sh
976-1471 Multi-home/topology/generation/recovery scenarios tests/fm-backend-herdr-recovery-e2e.test.sh
1471-1482 Guarded teardown and cleanup presentation_fixture_finish invoked independently by both entrypoints

Both entrypoints call common setup, project/parent seeding, and guarded finish functions in their own processes.
No source, home, lab, evidence directory, slot, or task ID is handed between entrypoints.
The presentation and recovery anchor IDs are distinct because production task-temp paths contain the task ID.
The presentation entrypoint additionally retires its own anchor and verifies its task record is absent.
The cleanup-failure regression remains in tests/fm-test-fixture-cleanup.test.sh; its cleanup owner is unchanged.
The new recovery entrypoint is selected through the existing real-Herdr family and stays outside concurrent portable execution.
Every original concurrency wave, negative deadline path, registered ownership-tree check, retirement barrier, generation binding, ambiguous-token refusal, and cleanup assertion is retained.

Exclusions and ledger

All five parked branches listed in docs/fork-divergence.md remain excluded; none of their tips is an ancestor of either merge parent, and their additions beyond the fork base have no intersection with this prefix.
The unlanded detector remains read-only at d0630a7ed6c051dc324e1dda154fefd9af102613; only a compatible status-line fixture was added.
The ledger records all 30 active divergences, including strict abort omission, additive adapter ownership, Pi/OMP standby, the remote-parent local-lock boundary, and independently owned default-bounded Herdr fixtures.
All five parked tips and the detector tip are also excluded from the final head, and no later-prefix commit is an ancestor of it.

Forge state and expected red check

Observed 2026-09-11T18:14:30Z for #271.
Pushed head 14de8ecb36fd384925ad018ea1ee63ca0faf899f and base HelloWorldSungin/firstmate:main at f49a50d4f2cc1dcad6005c835a62d1e377419b71 were read back from the forge.
GitHub reports mergeable=true, mergeable_state=unstable, and merged=false.
All 16 non-compliance checks passed on this updated head, including the Herdr lane without the temporary 900-second override.
The sole failure is the expected PR must be raised via no-mistakes gate for this authorized direct-PR sync path.

Check Result Forge evidence
Behavior portable parallel 1 success check
Behavior portable parallel 2 success check
Behavior portable serial 1 success check
Behavior portable serial 2 success check
Behavior portable serial 3 success check
Behavior portable serial 4 success check
Behavior portable serial 5 success check
Behavior portable serial 6 success check
Behavior portable serial 7 success check
Behavior portable serial 8 success check
Behavior tests (Herdr) success check
Behavior timing aggregate success check
Lint success check
PR must be raised via no-mistakes failure check
Repo invariants success check
Stock macOS Bash snapshot compatibility success check
Test coverage guard success check

No no-mistakes pipeline was run because it rebases merge topology.
Firstmate owns landing and must use fm-pr-merge.sh with explicit --merge and an explicit body.
The worker has not merged this PR.

att430 and others added 30 commits September 4, 2026 00:00
* feat(harness): verify gemini as a crewmate runtime adapter

Adds Gemini CLI as a fourth dispatch target alongside claude, codex, and
grok, scoped to crewmate and scout work only. Every axis was proven against
gemini-cli 0.58.0 rather than inferred; docs/verification/runtime-backends.md
carries the dated evidence and names what stayed unverified.

Busy state is semantic, not rendered: BeforeAgent opens a turn and AfterAgent
and SessionEnd close it. AfterAgent also fires on a manual interrupt, so a
cancelled turn closes its own record.

Three findings shaped the wiring rather than a config line:

- --skip-trust and GEMINI_CLI_TRUST_WORKSPACE=true are presented by the CLI
  as equivalents and are not. A controlled A/B showed --skip-trust leaves
  project configuration unloaded, so workspace skills never load.
- The worktree's .gemini/settings.json is the PROJECT's committed settings
  file, unlike claude's settings.local.json. Firstmate's hooks therefore go
  to a firstmate-owned state/<id>.gemini-settings.json reached through
  GEMINI_CLI_SYSTEM_SETTINGS_PATH, which also works untrusted and merges
  with a project's own hooks instead of replacing them.
- The shipped CLI is a node bundle whose live process reports comm as
  MainThread, so ancestry cannot see it. GEMINI_CLI=1 is load-bearing and is
  tested before an inherited CLAUDECODE, and pane liveness identifies gemini
  from the script argument through the new bin/fm-gemini-lib.sh.

Gemini is refused for secondmates: it has no primary supervision protocol.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYdQkKfSEQrFUxtcTXZ66L

* test: clear gemini's marker in launch and detection expectations

Every non-gemini launch now clears GEMINI_CLI the way it already clears
cursor's markers, so the two tests that pin the exact launch prefix are
updated to match. The harness-detection tests that scrub foreign markers
before probing ancestry scrub GEMINI_CLI too, so running the suite from
inside a gemini session cannot produce a false verdict.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYdQkKfSEQrFUxtcTXZ66L

* docs: classify the gemini harness reference

The documentation inventory is the single classification owner for maintained
prose surfaces, and every surface must appear in it exactly once. The new
harness reference is agent-runtime, matching its siblings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GYdQkKfSEQrFUxtcTXZ66L

* no-mistakes(review): Narrow Gemini ancestry detection

* no-mistakes(review): Restrict Gemini hooks to canonical launches

* no-mistakes(document): Document Gemini adapter support boundaries

* no-mistakes(ci): Fixed Gemini process identity when interpreter or script paths contain whitespace. Tmux liveness now uses NUL-delimited /proc argv on Linux, with the existing flattened ps fallback elsewhere. Added a real-process regression test. Verified with the Gemini harness test suite, full fm-lint, ShellCheck, and git diff --check. The CI and Require no-mistakes runs were action_required/attestation outcomes rather than code failures

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…uid#3704)

* conclude parked runs the pipeline advanced past the task copy

A no-mistakes fix round commits in the daemon's own gate-repo clone, so a
run parked at a gate can carry a head whose object the task copy never
received. Teardown's strict object-local identity rule then declined to
conclude the run, and cleanup left it parked forever holding a fleet slot
(observed 2026-09-03; the same masking condition PR 3681 fixed on the
read path, now closing the teardown half its scope boundary deferred).

task_status_is_own_parked_run now falls back - only when the reported
head resolves to no local object - to the one shared runs-ledger
attribution rule fm_nm_runs_status_for_worktree (bin/fm-nm-run-lib.sh),
whose anchored continuation proof binds the branch's newest active row
to this worktree's exact submitted head. Foreign branches, stale
history, terminal rows, ancestor-only anchors, diverged newer rows, and
ambiguous multi-row shapes all still refuse, and runs that are actively
running, fixing, or in CI remain untouched: only the parked-at-a-gate
determination ever reaches the abort. No sqlite access, no fetches into
another task copy, no custody changes, no duplicated matching logic.

* tighten the parked-run ledger fallback and pin both judge corrections

The teardown ledger fallback now authorizes concluding this task's parked
run only when the shared runs-ledger rule's proved answer is the explicitly
active word (running): a terminal newest row - even anchored at exactly the
worktree's head - is finished history and never an abort authorization.
The read path may classify the same owner's answer; teardown's abort must
never fire for a run that already ended.

Two bounded pre-validation corrections from the implementation review:
- a fetched-object counterfactual pins the strict-rule path: a pipeline fix
  head fetched into the task copy aborts through object-local identity
  alone, with an empty ledger and a proof the runs query never fired;
- a negative fixture pins the tightened boundary: an unresolvable reported
  head with a terminal newest same-branch row anchored at the worktree head
  engages the ledger fallback and still refuses, so the refusal is the
  terminal-word boundary and not an earlier guard.

* no-mistakes(review): Bind teardown ledger fallback to validated run heads

* no-mistakes(review): Restore validated advanced-head ledger continuation

* no-mistakes(review): Reject invalid ledger dates and terminal statuses

* no-mistakes(document): Document teardown ledger scan limit
* Keep parked and aged undated captain holds off live Captain's Call.

Bearings was treating undated parked-style holds as live calls; mark those phrasings deferred and project holds older than a configurable 14-day since date as Charted Next gates instead.

* no-mistakes(review): Bound parked marker matching to lexical tokens

* no-mistakes(review): Age undated holds from durable hold-set dates

* no-mistakes(review): Reset re-held timestamps and scan full bodies

* no-mistakes(review): Preserve timestamp precision and prioritize parked suppression

* no-mistakes(document): Document undated captain-hold aging

* no-mistakes(ci): Fixed stock Bash CI test-count expectations (16 snapshot, 45 Bearings). Prevented fresh holds on old tasks from aging via stale `since` dates by aging only stamped holds. Added behavioral regressions and verified both suites plus Bash 3.2 parsing

* no-mistakes(ci): account for rebased snapshot regression

* no-mistakes(review): Restore legacy hold aging and mandate wrapper

* no-mistakes(review): Restrict hold stamps to canonical leading lines

* no-mistakes(review): Exclude historical answers and deduplicate revealed holds

* no-mistakes(document): Correct captain-hold projection documentation

* no-mistakes(ci): Rebased onto 8988af2 and resolved Bearings conflicts. Fixed the hold timestamp race by persisting and verifying the timestamp before publishing the captain hold; failures now leave the task unheld. Added behavioral coverage for ordering and failure handling. Preserved the required parked-phrase projection behavior. Relevant snapshot, Bearings, lifecycle, syntax, and ShellCheck validations pass

* no-mistakes(review): Bound current prose before historical resolutions

* no-mistakes(review): Preserve hold age across interrupted answers

* no-mistakes(review): Preserve leading hold stamps until answer closure

* no-mistakes(review): Normalize answer bodies on matching retries

* no-mistakes(review): Document concurrent re-hold age-basis limitation

* no-mistakes(document): Refresh captain hold lifecycle documentation

* no-mistakes(ci): Fixed both CI failures. Updated the macOS Bash snapshot expectation from 45 to 46 Bearings tests. Narrowed parked-style deferral matching to explicit hold-reason prefixes while preserving legacy explicit markers and preventing contextual prose from hiding active decisions. Added behavioral regression coverage. Verified with stock Bash 3.2: 17 fleet snapshot tests and 46 Bearings tests pass; full lint and workflow validation also pass

* no-mistakes(ci): Fixed Greptile’s P1 finding by restricting parked-style deferral phrases to complete hold-reason markers. Contextual reasons beginning with “not urgent,” “queued opportunity,” or “captain-gated” now remain visible decisions. Added behavioral coverage through the real fleet and Bearings snapshot paths and updated documentation. Verified both snapshot suites under Bash 3.2 (17 fleet tests and 46 Bearings tests), syntax checks, and git diff checks. The no-mistakes attestation failure is external/stale and requires the outer pipeline to refresh it for the new head

* no-mistakes(ci): Fixed parked-style undated captain holds disappearing from the default Bearings board. They now project to Charted Next with omitted[] disclosure, while --all-decisions reveals them and removes the safety gate. Added behavioral coverage for the reported “not urgent” case and aligned documentation. Verified fm-bearings-snapshot, fleet snapshot view, and captain-hold lifecycle tests; shellcheck, bash syntax, and git diff checks pass

* no-mistakes(test): Stabilize concurrency budget and provision timeout tests

* no-mistakes(document): Correct captain hold documentation details

* no-mistakes(ci): Fixed hold-reason parsing so commas in contextual reasons are preserved and do not incorrectly defer live Captain's Call decisions. Added end-to-end fleet/Bearings regression coverage. Reworked the flaky Herdr timeout test to assert observable late-launch behavior rather than process-ID liveness. Verified both snapshot suites, Herdr test 5 consecutive times, shell syntax, shellcheck, and git diff checks

* Restore the Herdr lab timeout test to its main version.

The stabilization rounds reworked tests/fm-herdr-lab.test.sh while chasing a
load-induced flake, replacing the fake server's wall-clock delay with a
SIGSTOP'd process and asserting that the blocked process is gone after a
timed-out provision. A stopped process does not die from SIGTERM, so that
assertion fails on Linux and the portable parallel shard stayed red.

That test is unrelated to the undated captain-hold projection this branch
delivers and was identical to main before these rounds, so restore main's
version exactly. It still proves that a timed-out provision cancels its late
launch before teardown.

* no-mistakes(review): Preserve metadata-like prose in captain hold reasons

* no-mistakes(review): Resurface due dated captain holds

* no-mistakes(review): Distinguish parked holds from explicit deferrals

* no-mistakes(review): Invalidate legacy secondmate summary caches

* no-mistakes(review): Keep blocked deferred holds in Charted Next

* no-mistakes(review): Count blocked deferred holds in omission disclosure

* no-mistakes(document): Correct captain-hold projection documentation

* no-mistakes(ci): Fixed both CI failures. Updated the macOS Bearings test count to 51. Preserved the v1 summary schema for compatibility while rejecting hold-bearing summaries missing the new aging fields, preventing stale caches from restoring noisy calls. Verified fleet snapshot, Bearings snapshot (51 tests), home-summary refresh, secondmate reconciliation, Bash 3.2 parsing, and diff checks

* no-mistakes(ci): Fixed Greptile’s valid finding: `--all-decisions` now reveals deferred/aged captain holds even when blocked, for both main and secondmate homes, and removes their duplicate Charted Next gates. Added behavioral regression coverage and updated documentation. The prose-classifier finding was not applied because exact complete-phrase matching is explicitly required by the author intent; contextual wording remains live. Verified with Bearings and fleet snapshot tests, `bin/fm-lint.sh`, Bash syntax checking, and `git diff --check`

* no-mistakes(ci): Fixed the actionable-state bug in Bearings: an arrived parked-style hold is live only when it is not explicitly non-actionable, so blocked due holds remain gated by default and are revealed by --all-decisions. Added behavioral regression coverage for that case. Preserved complete-reason parked-style classification as required by the author intent. Verified with tests/fm-bearings-snapshot.test.sh, bin/fm-lint.sh, and git diff --check

* Show why a revealed captain hold is deferred.

Under --all-decisions a deferred hold is revealed and its Charted Next gate
is removed, but the revealed row carried only the bare hold reason. A
date-deferred or blocked hold therefore read exactly like a genuine live
decision, because the until date, the age, and the blocking work only ever
appeared on the gate row that the reveal replaces.

Annotate a row that is revealed because it is deferred with the same
vocabulary the gate uses - until <date>, held <n>d, and the blocking work -
so the expanded view reads as deferred-but-shown. A genuinely live call is
left unannotated, and the default board is unchanged.

* Classify captain holds from structured fields alone.

Bucket membership was decided by several independent expressions, and two of
them matched hold reason or body prose. That produced a recurring class of
defects: holds that fell through every bucket and vanished from the board, and
live decisions silently suppressed because their wording happened to contain a
marker word - a reason of "non-deferred release choice" matched DEFERRED and
disappeared.

Replace all of it with one total classifier over structured fields only:
hold_kind, state, hold_until, unresolved_blocker_ids, and the machine-written
hold-set timestamp. Every captain hold gets exactly one hold_bucket - blocked,
dated, aged, or live - so no hold can fall through and none can match two.
captain_actionable is exactly the live bucket, and the --all-decisions reveal
is a property of the bucket rather than a second filter.

No hold reason or body prose is matched anywhere in the projection, so wording
can no longer hide, reveal, or reclassify a decision. A hold that is superseded
or no longer required is closed through the hold lifecycle instead of lingering
as an open hold flagged by a keyword.

* no-mistakes(review): Preserve working captain holds across bucket surfaces

* no-mistakes(review): Reject pre-classifier secondmate summary caches

* no-mistakes(review): Preserve complete live hold summaries

* no-mistakes(review): Clarify working hold decision bucket semantics

* no-mistakes(review): Reveal bounded remote holds and preserve blocker notes

* no-mistakes(review): Make blocker overflow explicit in hold summaries

* no-mistakes(document): Correct captain-hold projection documentation

* no-mistakes(ci): Updated the stock macOS Bash CI snapshot expectation from 17 to 18 tests. Verified the suite under Bash 3.2.57: all 18 tests pass. `git diff --check` also passes

* no-mistakes(ci): Updated the stock macOS Bash CI expectation from 51 to 53 Bearings tests. Verified all 53 pass under Bash 3.2.57; git diff --check passes
* 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>
…nguid#3763)

* fix(memory): honor explicit project maintenance guidance

* no-mistakes(test): Blocked by pre-existing Bash and Muse fixture failures

* no-mistakes(test): Remove accidentally tracked test attribution report

* no-mistakes(ci): Restricted the marker to the exact first line, preventing fenced examples from suppressing governance, and corrected the documentation. Regression failed before the fix; all 18 helper tests, focused ShellCheck, documentation validation, and diff checks pass. CI and Require no-mistakes report action_required with zero jobs executed; those external checks remain unresolved
…nguid#3783)

* fix(spawn): refuse repository primary from linked spawning homes

Compare the resolved task git directory with the spawning repository's
common git directory before refreshing a fresh copy or relaunching a task.
This protects the primary even when the spawning project is a linked home.
Keep pooled copies accepted and preserve recorded work on relaunch.

Fixes kunchenguid#3741.

Verification for the pipeline PR body:
- Red on origin/main 1820316 with the new
  regression and unchanged production code: bin/fm-test-run.sh
  tests/fm-spawn-pool-base-freshen.test.sh exited 1 with
  "linked spawning home accepted primary as a disposable copy".
- Green after the guard: the complete pool-base-freshen and control-relaunch
  suites passed through bin/fm-test-run.sh, covering primary and symlink
  refusal before fetch/reset, spawning-directory refusal, scout acceptance,
  and committed plus unfinished work preserved during linked-home relaunch.
- The worktree-settle suite passed on pristine main and the final branch.
  An earlier loaded-host run exceeded its five-second assertion (6s);
  the final retry passed without changing code or the assertion.
- Test fixture commits ran with GIT_CONFIG_COUNT=1,
  GIT_CONFIG_KEY_0=commit.gpgsign, GIT_CONFIG_VALUE_0=false.
- bin/fm-lint.sh and /bin/bash -n for all three changed scripts passed.

The upstream cwd-selection cause remains outside this change.

* no-mistakes(document): Clarify spawn isolation ownership and relaunch preservation
…kunchenguid#3785)

* fix: read a failed herdr CLI as unreachable, not a gone backend target

The no-run fallback in bin/fm-crew-state.sh collapsed every failed pane
capture into 'backend target gone', which downstream consumers treat as
positive death evidence - so a herdr CLI that errors or stalls under load
briefly scored dozens of live claims dead on a busy box. Only a successful
herdr answer proving the pane absent (fm_backend_agent_state's 'missing',
backed by pane get answering pane_not_found) may now read as gone; every
other verdict reports 'backend unreachable' with the endpoint state, which
is never positive death evidence. Adds a behavior test: an always-failing
fake herdr reads unknown/unreachable, never gone.

* test: pin the herdr suite's ambient home to a marker-free fixture

FM_HOME defaults to the suite's own root when unset, and any secondmate-
marked checkout (every treehouse crew home carries .fm-secondmate-home)
flips the default workspace label to 2ndmate-*, so the ambiguous-label
placement test found zero firstmate matches and fell into the create path
instead of refusing (expected exit 3, got 1) - deterministically green in
CI, deterministically red from a crew home. Export a marker-free ambient
FM_HOME fixture; per-test FM_HOME prefixes still override it.

* fix: classify herdr endpoint answers instead of every non-missing verdict

Review decision (firstmate, 2026-09-05): a failed pane capture is not
itself evidence of death, but neither is every non-missing classifier
verdict a failed answer. missing (pane get answered pane_not_found) and
dead (pane present, agent_not_found husk) keep gone-class text so a
stale-claim sweep may still reclaim them; an alive answer falls through
to the normal busy/state flow instead of being discarded when only the
heavy 200-line scrollback read failed; only when the cheap pane get /
agent get calls themselves fail to answer does the line read
'backend unreachable'. Adds the two missing cases: alive with a failed
scrollback read stays live, and a husk pane still reads gone.

* no-mistakes(review): route tmux through agent-state classifier; drop test stall

* no-mistakes(review): narrow inaccurate tmux socket and alive-arm fallback comments

* no-mistakes(document): document classifier-backed endpoint verdicts in crew-state contract
)

* fix: distinguish subshell wake-lock owners on stock Bash

Restore distinct process ownership for issue kunchenguid#3743 using the existing PID helper, consistently across lock publication, reclaim, release, role checks, and bounded handoff.

The existing wake-queue regression fails on pristine upstream Bash 3.2 with rc=13. The complete suite now passes on Bash 3.2.57 and Bash 5.3.15, with added coverage for ownership when BASHPID is unset. Canonical lint and stock-Bash syntax checks pass.

* no-mistakes(document): Correct lock grace-period documentation

* no-mistakes(ci): Captain, fixed all 14 SC2031 false positives with nine ShellCheck source-boundary annotations across three tests. Full CI-mode lint and the complete wake-queue suite on stock Bash 3.2 passed. Runtime behavior is unchanged
…backends (kunchenguid#3782)

* fix(bin): close legacy records on the Beads backend honestly

Two pre-Beads reads blocked honest closure of leftover records:

1. fm-captain-hold.sh complete/verify resolved attested legacy hold ids
   only against the live backend and the pre-collapse derived identity, so
   a home whose holds fm-hold-migration rehomed under fm- ids failed with
   an empty-name absence message (the resolve failure was swallowed by the
   command substitution feeding verify_hold_durable). Resolution now falls
   back, on the Beads backend only, to the legacy id under the configured
   beads prefix and to the row whose notes carry the exact marker line
   'migrated from data/backlog.md id <legacy id>'; every refusal names the
   id it could not resolve, and the markdown path is unchanged.

2. fm-teardown.sh refused any record without spawn_gen forever. A record
   that predates the field can now be torn down with an explicit
   --legacy-record flag once the recovery-grade endpoint classifier
   confirms the recorded endpoint dead or agent-less; the accepted
   incarnation is stamped into the record right before its close marker
   binds to it and named in the teardown line. Refusals leave the record
   byte-identical, the unlanded-work refusal is not relaxed, and a corrupt
   (multi-valued) spawn_gen is never accepted.

The companion repair this branch carries (follow-up commit) is the
backend-gated --file and markdown-file requirement in the mutate path and
lifecycle gates: fm_backlog_mutate passed --file and required the markdown
backlog file regardless of the resolved backend, and the transition gate
plus row probe required that file before any backend work, so a home on a
non-markdown backend could neither gate, probe, nor close its rows.

Behavior tests: self-contained beads fixtures over a scratch bd graph
(self-skipping on markdown-only tasks-axi installs), legacy meta fixtures
for every teardown gate, and the relocated markdown backlog coverage stays
green.

* no-mistakes(review): fix(review): report migrated-hold scan refusals and guard legacy spawn_gen stamp against newline-less records

* fix(backlog): address the configured backend for lifecycle writes

Completes the fm-backlog-transition-lib repair the first commit's message
claims: on this base fm_backlog_mutate passed --file and required the
markdown backlog file regardless of the resolved backend, and
fm_backlog_transition_applies plus fm_backlog_row_probe required that file
before any backend work, so a home on a non-markdown backend could neither
gate, probe, nor close its backlog rows. All three now gate the markdown
file on the resolved tasks-axi backend: markdown keeps exactly its explicit
<data>/backlog.md behavior, non-markdown homes address the backend their
own configuration selects with no markdown file requirement.
fm_backlog_row_show and fm_backlog_row_list already gated correctly and
are unchanged. docs/configuration.md owns the contract line.

Also extends the same backend gate to fm-captain-hold.sh's own mutation
wrapper - hold/add/update/answer/done append the markdown --file only when
the resolved backend is markdown, so a captain call on a Beads home reaches
the Beads store end to end - and applies the review round's two direct
remedies there: the [beads] graph path resolves against the backlog root
when relative (never the process CWD), and a failed bd graph read reports
bd's own trimmed stderr reason in the refusal.

Coverage: tests/fm-backlog-atomicity.test.sh gains a stub-driven Beads
completion case proving the transition gate applies, the row probe reads,
and done runs without any markdown file or --file override; the relocated
markdown backlog test stays green.

* no-mistakes(review): Document root-tasks.toml-only beads settings for migrated-hold resolution

* test(gotmp): stub fm_tasks_axi_backend so the fixture matches the backend-aware transition lib

The legacy-records change made fm-backlog-transition-lib.sh resolve the
configured backend via fm_tasks_axi_backend before the markdown-only skip.
The gotmp fixture's fm-tasks-axi-lib stub lacked that function, so the
markdown check fell through and teardown hit the incompatible-backend
error with unbound FM_TASKS_AXI_MIN under set -u. Stub the backend as
markdown and define the floor, restoring the intended no-backlog skip.

* fix(teardown): roll the legacy stamp back when the close marker fails

A legacy-record teardown stamps its accepted incarnation into the record
right before the close marker binds to it; when that marker write then
fails, the stamp survived, so a retried teardown sailed past the
dead-or-agent-less endpoint gate the stamp now proved unnecessary. The
failed marker write now truncates the record back to its exact pre-stamp
bytes (verified by size), restoring the byte-identical-refusal invariant;
when the rollback itself fails the operator is told to re-run with
--legacy-record after reconciling the endpoint.

Also completes the recorded review decision's coverage wording: the
beads stub test now drives the answer close end to end (update and done
through the gated wrapper), asserting no markdown file override reaches
either verb.

* fix(review): harden the legacy stamp rollback and resolve derived migrated ids

The legacy-record stamp rollback now uses perl (already in the teardown
curated PATH; truncate is not, and is absent on stock macOS), routes every
failure branch inside the stamp block through the same size-verified
rollback so the byte-identical-refusal invariant holds on those paths too,
and gains behavior coverage: an unrecordable close (an invalid pr= link)
fails the teardown, leaves the record byte-identical, keeps the backlog
row in flight, and a flag-less retry still refuses.

Migrated-hold resolution now probes the derived pre-collapse identity
(<origin>-decision-<entry>) alongside the raw entry - fm-hold-migration
recorded the DERIVED id in every migrated row's marker note - in both the
prefix and the migration-note forms, with the ambiguity refusal naming
every identity tried, plus behavior coverage for a bare decision key
resolved through its derived identity's marker.

Also aligns fm-backlog-transition-lib.sh's header ADDRESSING/SCOPE
paragraphs with the backend-gated contract, drops an unreachable FORCE
validity guard the parser rewrite left behind, and switches the new stub
fixture to the portable sed -i.bak idiom.

* no-mistakes(review): Name the configured backend in teardown's backlog reminder

* no-mistakes(review): Scan migration markers before the prefix guess

* no-mistakes(review): Document marker-first resolution and cover the prefix branch

* no-mistakes(document): Record prefix-attestation audit and marker-line forms

* no-mistakes(ci): Fixed the Greptile P1 on bin/fm-teardown.sh: a failed rollback of the synthetic legacy stamp let a retry bypass the dead-or-agent-less endpoint gate. Root cause: teardown minted `spawn_gen=legacy-<ts>-<pid>` into the task record before the close marker bound to it. When the close-marker write failed AND the rollback also failed, the record retained that token. On the next invocation `fm_backlog_meta_spawn_gen` succeeded, so `TEARDOWN_LEGACY_PENDING` stayed 0 and the endpoint gate was skipped entirely — even with `--legacy-record`. The script's own error text told the operator to "re-run teardown with --legacy-record", advice the code could not honor. Fix (bin/fm-teardown.sh): - A `legacy-*` spawn_gen is now recognized as a stamp this teardown path minted, never one a spawn published (fm-spawn.sh publishes `s<epoch>.<pid>.<random>`). Such a record still reads as the legacy record it is: it re-enters the endpoint gate, and a flag-less retry refuses naming `--legacy-record`. - Acceptance reuses the retained token instead of minting a second one; the append block is skipped when the record already carries it, so no duplicate spawn_gen is written. - The rollback attempt and its "could not be rolled back" message are guarded to runs that actually appended a stamp, so a run that appended nothing never claims a rollback it did not perform. - Usage header documents the retained-stamp rule. Test (tests/fm-teardown.test.sh): added `test_retained_legacy_stamp_still_faces_the_endpoint_gate`, an end-to-end reproduction — a `perl` stub that fails only the rollback's `truncate` (delegating every other perl call to the real interpreter) leaves the stamp behind, then the retry must still hit the gate, must not stamp a second incarnation, must not close the backlog row, and the flag-less retry must refuse. Verification: the new test fails against the pre-fix script on exactly the reported defect ("the retry skipped the dead-or-agent-less endpoint gate") and passes after. Full tests/fm-teardown.test.sh 80 ok / 0 failures / rc=0; tests/fm-backlog-atomicity.test.sh 80 ok / 0 failures / rc=0; bin/fm-lint.sh (pinned ShellCheck 0.11.0 + actionlint 1.7.12) clean
* fix(lint): drop source following on the local changed-file gate

The local lint step was inlining library closures through --external-sources
and peaking above 8 GB on a single root. Keep full analysis in CI, on main,
and without a merge-base; exclude the four cross-file codes from the local
pass so those findings still land in CI.

Co-authored-by: Cursor <cursoragent@cursor.com>

* no-mistakes(review): Run local ShellCheck per root and document measurements

* no-mistakes(review): Correct local source-following telemetry

* no-mistakes(document): Clarify context-sensitive lint documentation

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(pi): route needs-decision wakes and mixed batches wholly to main

Skip the supervision branch for every needs-decision status append, the
same way a check-kind wake already skips it. A coalesced signal/stale
trigger batch containing any needs-decision row is delivered wholly to
main, not split between the branch and a later main wake - the whole
batch, including any co-present routine rows for a different task,
travels together. Heartbeat and unread-status scans stay independent.

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

* test(pi): cover distinct-file mixed batches and heartbeat independence

Add a regression using two distinct files (not the same status file
twice) in one coalesced trigger so a some-vs-every regression on the
file-list cross-reference cannot hide behind a degenerate same-key
case, and a heartbeat/needs-decision co-presence test proving a
needs-decision row neither vetoes nor rides along with an otherwise
eligible heartbeat scan.

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

* no-mistakes(document): Clarify needs-decision and heartbeat routing

* no-mistakes(ci): Fixed captain-held stale reminders so they bypass supervision and wake main, while unrelated unread rows and heartbeats remain independent. Added routing regressions and updated documentation. Pi watcher tests, strict TypeScript checks, lint, and diff checks pass. The no-mistakes attestation failure was pipeline-state related, not a source defect

* no-mistakes(ci): Fixed CI lint by narrowly suppressing false-positive SC2031 diagnostics where background PIDs are captured immediately in the same shell. Verified with `CI=true bin/fm-lint.sh` and `git diff --check`. The no-mistakes attestation failure is pipeline-state-related (`test` was skipped), not a source defect

* no-mistakes(review): Route stale open decisions directly to main

* no-mistakes(review): Honor configured verbs in stale decision routing

* no-mistakes(review): Route second-mate escalations and configured decisions to main

* no-mistakes(review): Ignore trailing whitespace after captain holds

* no-mistakes(review): Cache stale decision classification per status file

* no-mistakes(review): Document unread decision precedence for later task wakes

* no-mistakes(review): Cache unchanged stale decisions across scope scans

* no-mistakes(review): Resolve decision aliases and reject symlinked statuses

* no-mistakes(review): Route surfaced captain-held signals directly to main

* no-mistakes(document): Document decision-owned main routing

* no-mistakes(ci): Fixed captain-held spans to remain actionable while crew working evidence is positive, ensuring the watcher delivers their main-only marker. Updated the executable regression test to cover this case. Verified with the full fm-watch-triage suite, bash syntax checks, and git diff checks. Shellcheck reported only pre-existing test harness warnings (SC1091/SC2034)

* no-mistakes(ci): Fixed the CI regression: captain-held transfers now retain their established non-actionable stale classification while the signal-routing side-band still surfaces them main-only. Verified with tests/fm-daemon.test.sh, tests/fm-watch-triage.test.sh, bash syntax checks, and git diff --check

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…d#3802)

* feat(spawn): add an opt-in worker environment allowlist

Honor a home-local launch-env-allowlist at the shared worker command
boundary and inherit it into secondmate homes. Preserve the existing
launch behavior when the file is absent. Keep the operational environment
and explicit launch assignments, and account for filtered Muse credentials.

Refs kunchenguid#3742

Verification:
- Red on origin/main 1820316:
  the new enabled-allowlist regression observed synthetic-unrelated in
  the worker; the absent-file control passed.
- Green: fm-test-run.sh on fm-spawn-dispatch-profile, fm-muse-harness,
  and fm-trace-context-spawn; all three passed without skips.
- Synthetic emitted-command probes ran through sh, stock Bash, and zsh.
- Canonical lint, documentation audience checks, and stock Bash syntax
  checks passed.

* no-mistakes(review): Reject inaccessible launch environment configuration

* no-mistakes(review): Preserve inherited allowlists on source inspection errors

* no-mistakes(document): Clarify worker environment grants and inheritance documentation

* no-mistakes(lint): Fix inheritance test ShellCheck source boundary
…kunchenguid#3575)

* feat(bin): add rovo as a verified crewmate/scout worker harness

Wire the Atlassian Rovo CLI (202609.1.2) into the TUI-under-tmux/herdr
adapter contract: detection with marker-precedence ordering, one-shot
positional launch with --startup-receipt readiness polling instead of
composer scraping, model/effort flags, a screen-scrape busy fallback
scoped like grok's, and crew/scout-only lifecycle control that refuses
secondmate launches. Ships with a portable regression suite, a live PTY
guard against the real binary, a per-harness reference doc, and a dated
verification record covering the silent OAuth refresh, the interrupt-ack
divergence from the originating scout report, and the still-open
composer-ghost and tmux/herdr pane-liveness gaps.

* no-mistakes(review): revert rovo launch to positional brief, drop startup-receipt

* no-mistakes(test): rewire rovo adapter to kimi-style launch-then-send shape

* no-mistakes(document): add rovo to stale worker-harness enumerations in docs

* docs(verification): close the rovo herdr-liveness gap with live isolated-lab evidence

Placement, launch-then-send, and busy/idle rendering are now verified live
in an isolated non-default Herdr lab session (bin/fm-herdr-lab.sh), driven
directly through fm-spawn.sh's/fm-backend.sh's own shared primitives since
the cross-session launcher-identity guard refuses this task's own ambient
Herdr identity for a full fm-spawn.sh run.

fm_backend_agent_state reported dead for a live, responding rovo pane at
every point checked, because herdr's own agent-integration registry has no
rovo entry (herdr integration status), so herdr agent get returns
agent_not_found regardless of whether rovo is actually running. This is
recorded as a Herdr-side integration gap rather than a firstmate bug, left
unpatched to avoid a false-positive alive verdict for other idle shells.

Updates docs/verification/rovo.md's backend-liveness section and its two
cross-references (docs/verification/runtime-backends.md, docs/configuration.md)
accordingly.

* fix(bin): close rovo's failed-spawn leak and busy-scrape false idle

Greptile P1s on PR kunchenguid#3575: a failed rovo readiness/submission/delivery gate
exited without tearing down the just-created endpoint, leaving the launched
--yolo rovo process running as an orphaned agent outside task control.
Separately, the busy classifier's rendered-tail fallback returned definitive
idle whenever the "Rovo is thinking" marker scrolled out of the last 12
nonblank lines of a long turn, which could make supervision wrongly conclude
a still-working worker had gone idle.

fm-spawn.sh: rovo_spawn_fail now calls rovo_endpoint_cleanup, which kills the
created endpoint (tmux/herdr/zellij/cmux) via the same generic fm_backend_kill
dispatch fm-spawn.sh's own orca-abort path already uses; orca's worktree and
terminal remain owned by the separate ORCA_ABORT_CLEANUP trap.

fm-busy-lib.sh: the rovo classifier arm now reports "unknown rovo-regex"
instead of "idle rovo-regex" when the marker is absent, matching how muse and
cursor already express "can't tell" for their own fallbacks. The positive
busy match is unchanged.

Extends tests/fm-rovo-harness.test.sh: the readiness and delivery failure
tests now assert the endpoint is torn down (and the success test asserts it
is not), and a new test drives the busy marker out of the tail window to
confirm the verdict is unknown, never idle. bin/fm-lint.sh is clean on both
changed files.

* test(rovo): align spawn fixture with the launch-brief validation contract

Upstream main now requires a brief's ## Captain's intent and
## Firstmate spec subsections (or a nonempty legacy # Task body)
before spawn, and rewrites ship+no-mistakes briefs into
launch-brief.md. Update the rovo harness fixture and pointer
assertions to match, mirroring the kimi harness fixture.

* no-mistakes(review): align rovo.md delivery-gate note with live herdr evidence

* fix: prevent stale supervision wake loops (kunchenguid#3672)

* fix(bin): stop the supervision branch's stale-ack and ghost-report loops

Clean-slate implementation of the four authorized recommendations from the
supervision-ghost-retrigger analysis (items 1, 2, 3, and 7), in their minimal
form, superseding PR kunchenguid#3604:

- fm_branch_report refuses a task the wake being handled never named. The
  extension fixes the reportable task set from the eligible rows before each
  prompt (signal and stale rows resolve to their tasks, a heartbeat allows any
  task with a live record, fleet is always allowed), so a report typed from
  memory about a task whose records teardown already removed is never stored
  or delivered.
- An acknowledgement that consumes nothing says "nothing was acknowledged
  through N" and prints the exact --ack-through / --recovery-generation
  command for the current presented wake, instead of "re-run the drain",
  which re-fed the same stale acknowledgement in a loop.
- bin/fm-guard.sh no longer tells the branch actor to drain queued wakes
  while it is handling them; it names the granted rows instead.
- Teardown removes state/.<task>.branch-outcome-index for ordinary tasks and
  descendants; the index rebuild and the append-side index write both skip a
  task with neither a live record nor a status log, so the branch's report of
  a teardown it just performed is stored without recreating the index.

No new locking, no spawn-generation binding, and no retired-task refusal: the
branch can still report the outcome of a task it just tore down, and the
teardown test now proves that path end to end.

* fix(bin): narrow the branch report scope and guard silence to the minimal form

Apply the four review decisions on the clean-slate branch:

- A signal or stale prompt may report only the tasks its own rows resolve
  to; fleet is refused there too. A heartbeat review is not scoped by task
  at all, so the extension no longer tracks live task records and refuses
  nothing by task id during a fleet review.
- The outcome-index rebuild no longer skips retired tasks; the append-side
  skip alone keeps a torn-down task's index from being recreated.
- bin/fm-guard.sh keeps the queued-wakes warning silent for the branch actor
  instead of printing a replacement note.

* no-mistakes(document): Align supervision docs with scoped wake handling

* fix(bin): grant rovo the per-task home paths its standard crewmate flow needs

rovo confines every file-tool operation to its worktree by default, and its
bash tool independently refuses the same external paths regardless of any
grant (confirmed live), so a rovo worker could not read its own brief or
steering messages or write its status/report - all of which live in the
firstmate home outside the worktree - without hand-feeding it. Grant
toolPermissions.allowedExternalPaths for exactly the task's brief directory,
steering inbox, and status file at launch time via --config-override,
merged with agent.efficiencyLevel into one JSON object since that flag is
single-value and silently discards a second occurrence.

Extends the live PTY guard to prove, against the real binary, that the
grant lets rovo read an external brief and append to an external status
file, and that the same flow is blocked without the grant.

* no-mistakes(document): align rovo reference Effort row with merged single --config-override

* no-mistakes(document): document rovo file-access grant in harness reference

---------

Co-authored-by: PUNEET PATWARI <ppatwari@atlassian.com>
Co-authored-by: Kun Chen <3233006+kunchenguid@users.noreply.github.com>
…guid#3813)

* fix(bin): read a crew's pipeline-death claim against the live run

A crew's no-mistakes drive call blocks until the next gate or outcome,
routinely far longer than its harness lets one command live, so the call
gets killed or times out while the daemon runs the fix round on in the
background. Crews read that as daemon death and block on it, and firstmate
had nothing that contradicted them.

Rule 7 of every generated brief now says a drive-call error or a harness
command timeout is not a daemon error, requires `no-mistakes daemon status`
plus `no-mistakes axi status` before a pipeline `blocked:`, and reserves
that report for a refused socket or a run record failed with a daemon
error. The no-mistakes definition of done adds the harness command limit
and the background-and-poll shape that fits inside it.

fm-crew-state gains one classification case: a `blocked:` line blaming the
daemon, a timeout, or unreachability, while the run is running or fixing
AND the pipeline reports fresh activity, now reads as superseded because
the run is alive. Recency comes from the client's own `quiet` marker on
active_steps.last_activity rather than a threshold invented here, and
positive evidence is required, so a run record that outlives a genuinely
dead daemon keeps the plain reading.

stuck-crewmate-recovery gains the inverse-of-a-dead-endpoint playbook:
firstmate reads both statuses itself, steers a reattach, never restarts the
shared daemon on a crew's claim, and escalates only a refused socket.

Nothing here depends on an unshipped no-mistakes capability.

* no-mistakes(review): Prioritize daemon socket failure and narrow unreachable matching

* no-mistakes(review): Honor socket refusal across coarse status and crew guidance

* no-mistakes(test): Replace flaky settle timing assertion with pane-read count

* no-mistakes(document): Document daemon timeout recovery contract

* no-mistakes(ci): Fixed daemon socket failures being suppressed by terminal attributed runs. Positive refused/missing socket evidence now remains blocked regardless of run status. Added a behavioral regression test for terminal failed runs. Verified with fm-crew-state tests, project ShellCheck lint, and git diff checks
…unchenguid#3797)

* fix(brief): scope Firstmate workers to their launch contract

* no-mistakes(document): Clarify supervisor scope and worker contract ownership

* no-mistakes(ci): Removed the heading-based bypass so every ship/scout launch receives the current worker-role contract. Added a regression that failed before the fix and passes afterward. Dispatch, brief, and delivery suites, focused ShellCheck, and git diff --check all passed

* no-mistakes(review): make launch overlay sole owner of worker role contract

* no-mistakes(review): narrow heading test dimension and fix publish error wording

* no-mistakes(review): gate role supersession, fix render guard, drop AGENTS twin

* no-mistakes(document): align architecture AGENTS.md scope and spawn launch-brief header
…d#3823)

* fix(bin): stop ringing steering doorbells into dead panes

The steering-inbox doorbell was a plain sentence plus Enter typed into a
worker's pane, and the watcher re-rang it on the assumption that a ring is
free. In a pane whose agent has exited that line is a shell command, and the
re-ring ladder kept typing it into a shell that can never acknowledge it.

- Prefix the doorbell with the shell no-op `: ` so a bare shell executes
  nothing while a live worker still reads the same self-describing line.
  `#` is not used because interactive zsh does not treat it as a comment by
  default and the claude harness binds it to memory mode.
- fm_task_inbox_ring skips the pane (return 3) when the backend positively
  classifies the agent as dead; missing, ambiguous, unreadable, and unverified
  endpoints still ring so a blind classifier never starves a live worker.
- The watcher caps the ladder for a dead pane: one stale wake for recovery,
  no ring, no ladder walk, and the durable record stays for
  stuck-crewmate-recovery. fm-send and the remote steer leg report the skip.

Tests cover the no-op in real shells, the dead/live/unclassifiable ring
verdicts, and the single-surfacing watcher path.

* no-mistakes(review): Quote doorbell paths against shell injection

* no-mistakes(review): Reject terminal-control paths before ringing

* no-mistakes(review): Document accepted partial doorbell delivery race

* no-mistakes(review): Skip unavailable endpoints before busy-state handling

* no-mistakes(test): Respect shell startup PATH in environment allowlist test

* no-mistakes(test): Fix doorbell test fixtures for endpoint liveness

* no-mistakes(test): Prioritize confirmed restarts and clean shell test syntax

* no-mistakes(document): Document dead and missing doorbell recovery

* no-mistakes(ci): Fixed the persistence-reply timeout race by rechecking for a correlated reply immediately before falling back to a nudge. Added a deterministic regression covering replies arriving between the preliminary resolution pass and timeout handling. Verified with the targeted restart suite, project lint, coverage guard, bash syntax checks, and diff checks
…tree poll (kunchenguid#3834)

* fix(spawn): keep the worktree poll from adopting the repository primary

After `treehouse get` is sent, the worktree-discovery poll reads the pane's
foreground-process cwd. While treehouse is still fetching and checking a slot
out, the foreground process is treehouse itself and it reports the repository's
PRIMARY checkout as its cwd for several seconds. The poll accepted any path
that merely differed from the spawning project, so from a linked spawning home
- whose project is itself a worktree of that repository - it adopted the
primary, and the isolation guard then refused a launch whose slot treehouse
went on to create normally.

Screen every candidate with the isolation guard's own conditions, extracted as
spawn_worktree_isolated, so a read the guard would reject stays a transient the
poll keeps waiting through. The two-consecutive-reads rule and the guard as
final backstop are unchanged; a pane that never reaches an isolated worktree
still fails at the existing 60s deadline, now naming the last path it reported.

The already-settled timing assertion counted whole-spawn wall time against a
5s budget and failed on unmodified HEAD on slower machines; it now counts pane
reads, which is what "one confirming read, not an extra cycle" actually means.

* fix(spawn): say which path the worktree wait rejected, and why

Screening every discovery-poll candidate means a host that never reaches an
isolated worktree spends the whole 60s window before refusing. That wait is
deliberate - separating a transient from a terminal misconfiguration needs
machinery this path does not want - so the refusal explains itself instead:
the isolation check records why a candidate failed, and the deadline names the
last path seen together with that reason. Message and diagnostics only; the
poll's control flow is unchanged.

Two suites asserted the guard's wording on paths the poll now rejects rather
than adopts, so their refusal arrives from the deadline instead: realign
fm-tangle-guard's non-git and subdirectory-of-primary cases (each now also
asserting the stated reason, and the second the metadata absence it was
missing) and the herdr projection e2e's forced non-worktree cwd.

* no-mistakes(review): stub poll sleep in tangle-guard spawn isolation test

* no-mistakes(document): document spawn poll isolation screen in fm-spawn header

* test(spawn): make the non-git isolation case non-git anywhere

The refusal-reason assertion for a path outside any repository assumed TMPDIR
is not inside a git repository. Where it is, git walks up from the temporary
directory, finds that repository, and the spawn reports the subdirectory cause
instead - so the case passed or failed on a property of the host rather than on
the behaviour under test.

Build the path under a directory the test then names in GIT_CEILING_DIRECTORIES,
which git documents as not chdir-ing up into a listed directory while looking
for a repository. Git never excludes the directory being searched, so the
ceiling is the parent of the path handed to the spawn.

The assertions pin which cause fired rather than the sentence that explains it,
leaving the operator wording free to improve.

* no-mistakes(document): point spawn poll comment at the isolation screen's comparison

* no-mistakes(ci): Fixed the "Behavior portable serial 2" failure in tests/fm-tangle-guard.test.sh ("non-worktree spawn did not say why the path was rejected (missing: 'not inside a git worktree')"). Root cause, in this PR's code: bin/fm-spawn.sh's spawn_worktree_isolated resolved the git toplevel with `wt_top_real=$(cd "$SPAWN_WT_TOP" ...)`. For a path in no repository, `git rev-parse --show-toplevel` yields empty, and `cd ""` is a SUCCESSFUL no-op on bash before 5.3 (CI's ubuntu-latest ships bash 5.2). The empty toplevel therefore resolved to fm-spawn's own cwd — the CI checkout — so the poll reported "it is a subdirectory of worktree root '/home/runner/work/firstmate/firstmate'" instead of the correct "it is not inside a git worktree". Dev machines with bash 5.3 fail `cd ""`, which is why the suite passed locally and only failed on CI; it is a genuine shell-portability defect in the reason vocabulary this change added, not a test-environment artifact. Fix (smallest root-cause change, 1 line + comment, bin/fm-spawn.sh:2168-2173): guard the empty value so it never reaches `cd` — if [ -n "$SPAWN_WT_TOP" ] && ! wt_top_real=$(cd "$SPAWN_WT_TOP" 2>/dev/null && pwd -P); then No change to the poll's timing or deadline behavior (respecting the recorded refusal-latency and spawn-wt-reason-vocabulary decisions), no new tests, no other files touched. Verification: - Reproduced the exact CI failure locally by putting bash 3.2 (same `cd ""` semantics as CI's 5.2) first on PATH: fails before the fix with the identical message shape, passes after. - tests/fm-tangle-guard.test.sh passes under both bash 3.2 and bash 5.3. - tests/fm-spawn-worktree-settle.test.sh and tests/fm-spawn-pool-base-freshen.test.sh pass; shellcheck -x bin/fm-spawn.sh clean. - bin/fm-test-run.sh --changed: 46 suites completed, every FM_TEST_END exit=0, 1076 passing assertions, 0 "not ok" (including fm-tangle-guard, fm-control-relaunch, fm-lint). The run ended on my own 900s wall-clock cap (rc=124), not on any test failure
Co-authored-by: Talon Stark <talonstark@gmail.com>
…d as not failed (kunchenguid#3846)

* fix(bin): read an orphaned green ci monitor as held-for-merge, not failed

A no-mistakes run held for a captain merge decision keeps its ci step
polling until merged or closed; when the shared daemon restarts under
that poll, the run is recorded failed although every substantive step
completed and GitHub reports the PR green. A monitor whose only
remaining job is to observe a human decision must not convert the
absence of that decision into a failure verdict.

fm-crew-state.sh now reclassifies a terminal failed run as done
(held-for-merge), surfacing the run's PR URL, when the steps table
shows every step completed except exactly ci failed and the ci log's
last recognized marker reads checks green. A genuinely red check, an
unreadable ci log, or a second failed step keeps the failure.

* no-mistakes(review): Read daemon-down coarse failed ledger as unknown, not failed

* no-mistakes(document): docs: align AGENTS.md failed-verdict guidance with crew-state reclassification
…livery (kunchenguid#3852)

* fix(bin): read preserved spawn state back before the interrupted exit claims it

The deferred-signal exit path asserted the paired task record and
In-flight backlog state were preserved without reading either back,
exactly when a reader is least able to check (fm-yi4j evidence,
2026-09-05). The commit's exit status alone has been observed to agree
with a row that did not actually move.

The exit path now re-reads the record and the row under the same
per-task lock as the commit, repairs a row the commit believed it
moved, and phrases the error as exactly what was verified or attempted
- verified preserved, repaired and verified, or an explicit
preservation-could-not-be-verified with the reason and hand-closeout
instruction. Two behavior tests drive a lying tasks-axi start through a
real interrupted spawn and assert the printed claim and the real
backlog state agree.

* no-mistakes(test): Fix calm suite for Pi 0.85 and pin test umask

* no-mistakes(document): Document interrupted-spawn preservation claim in backlog gate owner

* no-mistakes(ci): Fixed the Greptile P1 in bin/fm-spawn.sh's deferred-signal exit path: during preservation verification, the no-op HUP/INT/TERM re-trap combined with an unresponsive `tasks-axi show`/`start` (bash cannot run traps while a foreground child runs) held the per-task meta lock - and every lifecycle operation waiting on it - indefinitely. Root-cause fix: bound every tasks-axi invocation made under the lock. bin/fm-backlog-transition-lib.sh gains fm_tasks_axi, an exec-based wrapper (GNU timeout, gtimeout fallback) used by fm_backlog_row_show and fm_backlog_mutate that preserves the exact process placement of the plain tasks-axi call; bin/fm-spawn.sh sets FM_TASKS_AXI_TIMEOUT (default 30s) at the commit point so both the commit and the read-back verification are bounded. A timed-out call fails through the existing error plumbing and probe/mutate name the timeout as the reason, so the interrupted exit path prints honest 'preservation could not be verified ... (reason)' wording - never intent phrased as outcome, matching the author's intent. Added a behavior test in tests/fm-backlog-atomicity.test.sh that drives a real interrupted spawn through a lying tasks-axi whose repair start never answers; it asserts the spawn exits promptly (self-bounded by an outer timeout), the attempted wording names the timeout, and the printed claim agrees with the real record/backlog state. Confirmed the test fails on the unfixed tree and passes with the fix. Verified: fm-backlog-atomicity (83 ok), fm-transition-lib, fm-backlog-handoff, fm-captain-hold, fm-teardown, fm-fleet-snapshot-view, fm-secondmate-reconcile, fm-spawn-batch, fm-spawn-dispatch-profile, fm-task-delivery, fm-control-relaunch all pass; bin/fm-lint.sh clean. The fm-bootstrap 'unsplit run lost its local diagnostic' failure reproduces on the pristine base commit and is unrelated to this change

* no-mistakes(ci): Fixed the Greptile P1 in bin/fm-backlog-transition-lib.sh: fm_tasks_axi bounded tasks-axi only through GNU timeout/gtimeout and fell through to an unbounded exec on hosts with neither (stock macOS), so an unresponsive call could hold the per-task meta lock forever during interrupted-spawn verification. Root-cause fix: the bound now has no unbounded path. GNU timeout is preferred, gtimeout next, then a small perl watchdog (fork + waitpid WNOHANG polling at 50ms, TERM on expiry, one bound of grace, then KILL, exit 124 so the callers' existing timeout plumbing reports it; exit statuses and output pass through unchanged). Polling was chosen over alarm+die to avoid perl's platform-dependent syscall-restart semantics. When a bound is requested but no bounding mechanism exists, the call fails closed (exit 127 with a diagnostic) rather than running unbounded, so the interrupted exit path prints honest attempted wording, never intent as outcome. The unbounded exec remains only for the no-bound plain-call case. Added three behavior tests in tests/fm-backlog-atomicity.test.sh driving fm_tasks_axi through a PATH with no timeout binary: a hanging stub must exit 124 within the bound (verified to fail on the pre-fix code), a failing stub's status/output must pass through, and a tool-less PATH must fail closed with the diagnostic. Verified: fm-backlog-atomicity 86/86 ok, fm-transition-lib, fm-backlog-handoff, fm-teardown, fm-spawn-batch, fm-task-delivery, fm-fleet-snapshot-view, fm-secondmate-reconcile, fm-control-relaunch, fm-spawn-dispatch-profile all pass; bin/fm-lint.sh clean

* no-mistakes(ci): Fixed the Greptile P1 on bin/fm-backlog-transition-lib.sh: fm_tasks_axi's GNU timeout and gtimeout paths sent TERM at the bound but had no kill-after, so a tasks-axi that ignores SIGTERM kept the bounded call - and the per-task meta lock - held indefinitely during interrupted-spawn verification. Root-cause fix: both GNU execs now carry -k "$bound" (TERM at the bound, KILL after one further bound of grace), giving every bounded path the same forced-termination contract the perl watchdog already had. Because GNU timeout exits 137 (128+SIGKILL) when the kill-after fires - versus 124 for a TERM expiry - the probe/mutate timeout detection now goes through a new fm_tasks_axi_timeout_expired helper that treats 124 and 137 alike, so the interrupted exit path still names the timeout as the reason; the helper keeps the bound check in one place. Added a behavior test in tests/fm-backlog-atomicity.test.sh that drives fm_tasks_axi through a real GNU timeout with a tasks-axi stub that traps and ignores TERM (the ignored disposition survives exec into sleep) and asserts a bound-expiry status plus completion within bound+grace; on the pre-fix code the suite hangs until killed, confirming the reproduction. Verified: fm-backlog-atomicity 87/87 ok, fm-transition-lib, fm-backlog-handoff, fm-spawn-batch, fm-task-delivery, fm-teardown, fm-secondmate-reconcile, fm-control-relaunch, fm-spawn-dispatch-profile, fm-captain-hold-lifecycle all pass; bin/fm-lint.sh clean
…3821)

* docs: correct stale tmux/herdr backend maturity claims

Herdr now has 21 test files, its own required CI job (tests-herdr)
that installs a pinned build and hard-fails on "skip: herdr not
found", while tmux has 3 test files and is only required as a
dependency of the portable-serial e2e lane. zellij, orca, and cmux
still have no CI lane at all. AGENTS.md and docs/herdr-backend.md
still called Herdr merely "experimental" alongside those three,
misleading every session and reader about actual coverage.

Update AGENTS.md's config/backend entry, the opening lines of
docs/herdr-backend.md and docs/tmux-backend.md, the runtime-backend
section of docs/configuration.md, and the matching claims in
docs/architecture.md, CONTRIBUTING.md, and README.md so they agree
and distinguish tmux (default), herdr (own required CI lane, largest
suite, Windows still spike-only), and zellij/orca/cmux (still
experimental, no CI lane). No behavior, selection order, or
dispatch logic changes.

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

* no-mistakes(review): docs: fix stale herdr label and CI-lane wording

* no-mistakes(document): docs: align tmux adapter label in scripts.md

* no-mistakes(review): docs: drop duplicated herdr CI claim from tmux page

* no-mistakes(review): docs: drop windows claim, align contributing backend wording

* no-mistakes(review): docs: trim duplicated CI claim from herdr opening line

* no-mistakes(review): docs: drop unguarded largest-test-suite superlative

* no-mistakes(review): docs: restore tmux verified label and README experimental scope

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* fix: delete deterministic no-mistakes test baseline, restore intent-targeted Test

PR kunchenguid#3644 pinned commands.test to a fm-test-run.sh --changed walk of the
repository's 75-162 tests/*.test.sh scripts. no-mistakes runs commands.test
verbatim and unconditionally after every fix round, so that walk multiplied
by round count: measured at 32.7 minutes per validation versus 3.6 minutes
intent-targeted. Delete the pin and restore the 3.6-minute posture.

Add tests/fm-nm-test-contract.test.sh as a regression guard, parsing
.no-mistakes.yaml as YAML (ruby's bundled Psych, matching the parser
tests/fm-test-run.test.sh already uses for ci.yml) rather than grepping its
text, restoring in legal form what PR kunchenguid#823 added and PR kunchenguid#1282 removed.

Record the rule in docs/configuration.md's "Gate defaults" section (the
authoritative owner CONTRIBUTING.md already points at) and strengthen
CONTRIBUTING.md's existing local-Test guidance to state it plainly: never
configure commands.test to a deterministic test command, complete or partial.

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

* no-mistakes(review): Centralize no-mistakes test policy and narrow guard

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* fix(bin): verify pool-slot ownership before returning a worktree slot

Workers were killed when cleanup returned a Treehouse pool slot that a
different, live task had already taken. Teardown now proves the slot is
genuinely this task's before releasing it: it refuses when another task
record claims the same live worktree path, or when the endpoint's working
directory contradicts the recorded slot, and that refusal holds under
--force. Slot allocation, metadata publication, ownership verification,
and slot return are serialized across linked firstmate homes, and forced
secondmate cleanup verifies descendant slot ownership before returning
any child worktree.

Regression coverage drives the scripts with two task records naming one
slot path and asserts the live worker survives and its slot is not reset.

* no-mistakes(review): Protect slots across cloned Firstmate homes

* no-mistakes(test): Gate teardown locking on genuine Treehouse slots

* no-mistakes(test): Clarify pooled descendant slot gating

* no-mistakes(test): Synchronize watcher re-arm test on process exit

* no-mistakes(test): Wait for watcher cleanup before timeout escalation

* no-mistakes(document): Document pool-slot ownership safeguards

* no-mistakes(ci): Fixed all reported CI issues: normalized bare local Git origins to the same Treehouse project-lock identity as absolute clone origins; resolved ShellCheck SC1091 with explicit conditional sourcing; and taught concurrent Herdr teardown coverage to retry expected Treehouse lock contention. Added behavioral regression coverage for bare/absolute origin lock identity. Verified endpoint-safety tests, watcher tests, full CI lint, and the previously failing Herdr teardown assertion

* fix(bin): resolve relative origins from repository root

* no-mistakes(ci): Fixed teardown so an exact recorded endpoint may change cwd without falsely vetoing cleanup. Removed cwd-based ownership refusal while preserving cross-home record exclusivity and project locking. Updated behavioral coverage for both foreign slot ownership refusal and moved-cwd teardown success. Endpoint-safety, backend, watcher, checkpoint, and targeted lint checks pass. Real Herdr presentation E2E progressed successfully but exceeded the 600s local timeout
…ndmate, and primary (kunchenguid#3867)

* feat: add verified omp (Oh My Pi) harness adapter for crew, secondmate, and primary

Add omp as a verified harness: anchored process-name detection with a
Firstmate-owned FM_OMP_HARNESS launch marker that needs real omp ancestry,
the fm-spawn launch template with foreign-marker clearing, the tracked
.omp/fm-worker-overlay.yml posture overlay, --auto-approve, --cwd, and
pre-launch model validation scoped to providers 'omp models --json' lists.
Workers get a state-resident busy-state extension keyed on agent_end
without willContinue (omp has no agent_settled). The primary gets two
tracked .omp/extensions: a turn-end guard that answers omp's blocking
session_stop hook by compelling one continuation per turn, with the
pre-tool seatbelts and Run-tier session-start delivery, and a watcher
extension ported from the Pi one with fm_watch_arm_omp. Control tables,
composer busy footers, omp's status row as a bare-composer boundary, the
extension supervision model with an omp-keyed ownership proof, the
session-start diagnostic, and the supervision protocol snippet follow.

Verified live on omp 18.1.11 with openai-codex/gpt-6-astra: a Herdr scout
through spawn, busy state, steer, interrupt, exit, and teardown, and the
isolated rpc primary lab through extension auto-discovery, digest
delivery, lock identity, watcher arm, successor and wake delivery, and
the compelled guard continuation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012AMyYaHU42Ltotn6fauPAh

* test: prove the omp guard continuation through a guard spy

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012AMyYaHU42Ltotn6fauPAh

* fix(spawn): clear the gemini marker at the omp launch boundary

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012AMyYaHU42Ltotn6fauPAh

* test(omp): force the guard stage by freezing the watcher and clear lint findings

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012AMyYaHU42Ltotn6fauPAh

* test(omp): reap the live lab by path and record omp's rpc shutdown as a note

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012AMyYaHU42Ltotn6fauPAh

* test(omp): spawn a real secondmate for the discovery rule and classify the omp surfaces

Replace the template-extraction check with a genuine --secondmate launch
pinned to the fake tmux backend, assert the worker extension's handler set
through the executable rather than its bytes, classify the two new omp
surfaces in the documentation inventory, and record the Herdr worker
evidence in the runtime-backends verification doc.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012AMyYaHU42Ltotn6fauPAh

* no-mistakes(review): omp: unverify remote routes, narrow busy regex, drop overlay approval pin

* no-mistakes(review): omp: validate config-pinned model, correct remote and marker docs

* no-mistakes(review): omp: pin config-model validation with a test, trim overlay

* no-mistakes(review): omp: sync guard evidence, drop dead param, map quota family

* no-mistakes(review): omp quota: refuse unmapped prefixes, match bare model scopes

* no-mistakes(document): docs: cover omp in cd-guard, quota, continuity, tmux

* no-mistakes(document): docs: add omp subagent-guard row, fix live test header

* no-mistakes(ci): Fixed both failing behavior shards and the Greptile P1 in bin/fm-composer-lib.sh. Root cause of "Behavior portable serial 1" and "Behavior portable parallel 2": the omp busy regex (FM_DELIVERY_OMP_BUSY_REGEX_DEFAULT) and omp status-row furniture regex (FM_COMPOSER_OMP_STATUS_RE_DEFAULT) used the bracket range [⠁-⣿]; BSD grep on macOS accepts it but GNU grep on Linux CI aborts with "Invalid collation character", failing every omp busy/furniture read (3 assertions across fm-omp-harness, fm-tmux-submit-busy, fm-composer-lib). Replaced the range with one shared explicit alternation FM_OMP_SPINNER_FRAMES_RE of omp 18.1.11's unicode-preset spinner frames (status set ⣾⣽⣻⢿⡿⣟⣯⣷ + activity set ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏, read from the installed binary), the same pattern the Kimi busy regex already uses in CI. For Greptile's finding (the harness-agnostic furniture rule's first alternative matched any 1–4-byte token + ' · ', so wrapped typed input like 'fix · tests' with the cursor on it regressed from pending to unknown; reproduced locally vs base), pinned that alternative to omp's identity cell (π|󰵗|pi, the icon.omp of each preset in the 18.1.11 binary). Tests: fm-composer-lib.test.sh asserts 'fix · tests' is not furniture, a status-set spinner row is furniture, and the wrapped composer screen reads pending under both locales (CAPS_TMUX cursor 3); fm-omp-harness.test.sh asserts a status-set frame reads busy. New negative cases fail against the pre-fix lib and pass after. Verified: fm-omp-harness, fm-tmux-submit-busy pass via bin/fm-test-run.sh; fm-composer-lib passes all cases except one pre-existing, unrelated local failure (Herdr half-block test uses printf '▀', unsupported by macOS bash 3.2; fails identically on a pristine HEAD export, passes on CI bash 5); shellcheck and bin/fm-lint.sh clean. Caveat: GNU grep is unavailable locally, so the Linux compile was not run directly; the fix uses only constructs already proven on CI's GNU grep (multibyte literal alternations, incl. under LC_ALL=C). Files changed: bin/fm-composer-lib.sh, tests/fm-composer-lib.test.sh, tests/fm-omp-harness.test.sh. No docs needed changes (they describe the rule generically)

* no-mistakes(ci): Greptile Review: fixed. The omp status-row furniture regex FM_COMPOSER_OMP_STATUS_RE_DEFAULT in bin/fm-composer-lib.sh still accepted a literal `pi ·` opening, so wrapped composer input beginning with `pi ·` was truncated and misclassified. Read the installed omp 18.1.11 binary: the ascii preset's `icon.omp` is `pi` but its `sep.dot` separator is ` - ` (unicode/nerd use ` · `), so a real ascii status row never contains `pi ·` and that alternative could only ever match typed text. Removal-first fix: dropped `pi` from the identity alternation (now `(π|󰵗)`) and updated the comment to record why the ascii preset is excluded. Tests (tests/fm-composer-lib.test.sh): added a negative furniture case for 'pi · e · phi as the three constants' and a wrapped-screen assertion (CAPS_TMUX, cursor 3) that a continuation row opening `pi ·` reads pending in both locales; the new case fails against the unfixed lib and passes after. Verified: composer test with the half-block case skipped passes all 33 cases including the omp matrix; bin/fm-test-run.sh tests/fm-omp-harness.test.sh passes; shellcheck -x clean on both files; bin/fm-lint.sh clean. The full composer test via the runner fails locally only on the pre-existing half-block case (bash 3.2 printf cannot emit ▀; passes on CI bash 5), identical to before this change. Docs unchanged (they describe the rule generically and never mention the ascii identity cell). PR must be raised via no-mistakes: not caused by code. attestation.head_sha is cdddc60 while the PR head is cd51cf4 because the pipeline's ci-phase push moved the head; the outer executor's re-push will re-bind the attestation. No file change for that check. Files changed: bin/fm-composer-lib.sh, tests/fm-composer-lib.test.sh

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Integrate the next contiguous upstream prefix with additive Gemini, Rovo, and OMP support, asynchronous Pi delivery, structured holds, and guarded lifecycle updates.

Preserve fork launch ownership, agy atomic delivery and trust, daemon-owned away supervision, snapshot and attribution protections. Firstmate retained strict local commit identity for teardown, so ledger-only unfetched-run abort remains excluded. Keep remote-parent lock scope local and isolate runtime verification fixtures.
Retain existing combined metadata annotations alongside canonical standalone hold reasons. Preserve canonical commas and reject unparenthesized title prose. Cover both forms through the real dashboard Backlog endpoint.
@HelloWorldSungin
HelloWorldSungin merged commit 668b61f into main Sep 11, 2026
16 of 17 checks passed
@HelloWorldSungin
HelloWorldSungin deleted the fm/fm-upstream-sync-2026-09-08-round-3 branch September 11, 2026 18:26
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.

10 participants