Skip to content

Merge upstream round 1 through 88fb3c0a - #269

Merged
HelloWorldSungin merged 21 commits into
mainfrom
fm/fm-upstream-sync-2026-09-08-round-1
Sep 9, 2026
Merged

Merge upstream round 1 through 88fb3c0a#269
HelloWorldSungin merged 21 commits into
mainfrom
fm/fm-upstream-sync-2026-09-08-round-1

Conversation

@HelloWorldSungin

@HelloWorldSungin HelloWorldSungin commented Sep 8, 2026

Copy link
Copy Markdown
Owner

This merges the first contiguous upstream prefix through kunchenguid/firstmate@88fb3c0ae9ddca1cfd58acf87308f0d1d4b73ccb into fork parent ab9f96fa20bee46b4b0a13e00ac06ae97a344530.
The measured merge base is 0866a770234502364c268a768cb7c66cc321c629, and the round contains exactly 20 upstream first-parent changes.
The ledger TRACK strategy governs same-capability collisions, with compatible fork behavior retained.

Applicability

Upstream change Classification Resolution
4ad8cbae - kunchenguid#3221: refactor(quota): extract mid-task polling and candidate selection into dedicated scripts adapted with a reason Keep the fork sidecar eligibility policy and quota-axi 0.1.32 compatibility floor; add quota helpers under their fixed-order/primary-provider limit, adapt the new polling fixture version, and preserve fork timeout/test routing.
6c1d2db1 - kunchenguid#3371: fix: surface comments on Lavish annotations conflicted with fork work and resolved Keep fork dynamic help extraction so the added Lavish annotation comments appear without a stale fixed header range.
a5f3cbee - kunchenguid#3420: fix: support first public-followup registration on Bash 3.2 conflicted with fork work and resolved Take the Bash 3.2 first-registration fix and CI probe while retaining fork Node 22, eight shards, and completion marker placement.
355f46fe - kunchenguid#2792: fix(bin): isolate new Herdr server environments taken cleanly New named servers drop inherited home/harness context; existing-server reuse and all fork Herdr behaviors remain intact.
41d0ab39 - kunchenguid#3442: fix: surface inbound Relay media to responding agents taken cleanly Retain and inspect media across the full Relay payload under upstream exact-host fetch rules; preserve fork outward-consent boundaries.
f2ee922a - kunchenguid#3480: fix(bin): defer inactive reconciliation during startup conflicted with fork work and resolved Defer inactive reconciliation while retaining the fork complete bootstrap sweep inventory and aggregate timeout hand-down.
f42a6291 - kunchenguid#3475: fix(bin): bound wake drain presentation lock waits adapted with a reason Bound presentation-lock waits through the existing wake owner; adapt the new deadline assertion to require the retained fork queued-wake advisory while still rejecting helper diagnostics, and retain watcher signal/handover contracts.
ee58e39b - kunchenguid#3479: fix(bin): retire public follow-ups in remote homes adapted with a reason Take guarded remote legacy-link retirement; retain fork public-follow-up test completion evidence after every new case.
7d4b5177 - kunchenguid#3484: fix(bin): support process events under symlinked homes taken cleanly Canonicalize trusted process-event homes and test symlinked paths without weakening package or state permissions.
54663948 - kunchenguid#3312: fix(pi): deliver captain outcomes as deterministic transcript entries adapted with a reason Take exact transcript entries and sequence-bound processing; keep AGENTS concise owner pointers and all fork private-state records.
3b891c81 - kunchenguid#3481: feat: add bounded concurrent Bearings ledger collection conflicted with fork work and resolved Take concurrent cached remote ledgers and deferred reconcile requests; preserve local task bounds, abandoned children, dashboard fields, read-only dashboard caching, and parent-owned scratch cleanup. Adapt the new reconcile remote-ledger fixture to the fork abandoned_children schema.
1459c4dd - kunchenguid#3489: ci: rebalance portable serial test shards conflicted with fork work and resolved Refresh upstream shared timings and adopt the 20-minute job cap; retain eight fork shards, fork-only weights, the 480-second default script bound, and opt-in exclusions. Extend the fork C-collation invariant to the new unhinted-script set comparison.
714da649 - kunchenguid#3491: fix(pi): fall back on incomplete supervision branch prompts taken cleanly Incomplete branch prompts settle through watcher-owned fallback, with typed pending delivery preserved.
1c410299 - kunchenguid#3497: fix(pi): re-probe supervision branch after cooldown taken cleanly After the cooldown, retry branch supervision through the existing settlement handshake; successful work clears the provider-error streak.
521de54c - kunchenguid#3501: fix(bin): remove legacy remote snapshot reads conflicted with fork work and resolved Remove legacy remote/computed summary reads; preserve abandoned-child data and update the fork fixture to publish its real ledger before reading.
84c01b40 - kunchenguid#3498: fix(pi): preserve watcher continuity across session replacement conflicted with fork work and resolved Adopt tokenized pending-actionable serialization as the single owner, retaining fork away-mode guards and deterministic readiness/retirement settling.
d9771284 - kunchenguid#3495: fix(bin): resurface task statuses missed by wake handling adapted with a reason Add missed-status backstop and four-field cursor support while preserving fork state classifiers and the concise AGENTS handling pointer.
56b4c15c - kunchenguid#3503: fix(bin): collect follow-up results from remote work homes adapted with a reason Take confined remote work-home result collection and retirement; keep fork docs/tools and run all new cases before the success marker.
763f5979 - kunchenguid#3504: fix(bin): exclude secondmates from home-summary validity conflicted with fork work and resolved Exclude persistent secondmate metadata from child validity while retaining fork dashboard/abandoned-child behavior and extensible CI count guards.
88fb3c0a - kunchenguid#3509: fix(bin): self-heal outcome indexes on first drain taken cleanly Self-heal outcome indexes during first drain while preserving durable queue and acknowledgement semantics.

Validation

Both exact parents were tested in independent temporary clones before the upstream merge was committed.
The complete inventory was run as bin/fm-test-run.sh --all --exclude-family real-herdr-gated --json <artifact>, followed by every script selected by --list --family real-herdr-gated serially.
Firstmate approved the same outer cleanup/tripwire wrapper for the unchanged fm-afk-launch fixture on both parents and the merge; every other Herdr fixture used its reviewed named-session cleanup.

Tree Umask Scripts Passed, excluding gate skips Failed Gate skips Real Herdr Canonical lint
fork-parent 002 220 182 8 30 12/12 passed passed
upstream-parent 002 176 134 18 24 12/12 passed passed
merge complete sweep, before follow-ups 022 223 188 5 30 12/12 passed passed

The original parent sweeps inherited this host's 002 umask.
Every failing parent script was then rerun on that same unmodified parent with only the umask normalized to 022; the final complete sweep uses 022.
The isolated extension-binding control also reproduced the private-directory refusal at 002 and passed at 022.
The following table preserves every original parent failure and distinguishes those reruns from the original baseline.

Script Fork original Fork 022 recheck Upstream original Upstream 022 recheck Merge sweep 022, before follow-ups
fm-bearings-board-render.test.sh pass not rerun FAIL (1) pass pass
fm-bearings-board.test.sh FAIL (1) pass FAIL (1) pass pass
fm-bootstrap-network-parallel.test.sh pass not rerun FAIL (1) pass pass
fm-bootstrap.test.sh pass not rerun FAIL (1) FAIL (1) pass
fm-captain-hold-lifecycle.test.sh FAIL (1) pass FAIL (1) pass pass
fm-extension-binding.test.sh FAIL (1) pass FAIL (1) pass pass
fm-on.test.sh pass not rerun FAIL (1) FAIL (1) pass
fm-procevent-quota.test.sh absent not rerun FAIL (1) pass FAIL (1)
fm-procevent-when.test.sh FAIL (1) pass FAIL (1) pass pass
fm-procevent.test.sh FAIL (1) pass FAIL (1) pass pass
fm-recall.test.sh pass not rerun absent not rerun FAIL (1)
fm-remote-doctor.test.sh pass not rerun FAIL (1) FAIL (1) pass
fm-remote-reply.test.sh FAIL (1) pass FAIL (1) pass pass
fm-remote-secondmate-lifecycle-e2e.test.sh FAIL (1) pass FAIL (1) pass pass
fm-remote-secondmate-parent-binding.test.sh pass not rerun FAIL (1) pass pass
fm-remote-secondmate-trace-context.test.sh pass not rerun FAIL (1) pass pass
fm-secondmate-reconcile.test.sh pass not rerun pass not rerun FAIL (1)
fm-session-start.test.sh pass not rerun FAIL (1) FAIL (1) pass
fm-test-run.test.sh pass not rerun FAIL (1) FAIL (1) FAIL (1)
fm-wake-queue.test.sh pass not rerun pass not rerun FAIL (1)
fm-watch-triage.test.sh FAIL (1) pass FAIL (1) pass pass

Original diagnostic attribution:

  • Private-directory or process-event registration failures affected Bearings board, hold lifecycle, extension binding, process-event quota/when/core, remote reply/lifecycle/parent binding/trace context, and watcher triage.
  • Upstream bootstrap-network-parallel reported a duplicated bravo liveness line; the table records whether normalizing permissions cleared that symptom.
  • Upstream bootstrap and session-start lost their expected MISSING: node fixture diagnostic on this installed host.
  • Upstream fm-on observed the Nix profile directory in its composed child PATH, and remote-doctor did not create the expected first harness wrapper.
  • Upstream fm-test-run required absent Ruby for its YAML inspection; the fork retains its existing per-case optional-interpreter handling.

These parent failures were recorded separately and were not quietly fixed inside the sync.
The full merge sweep above is preserved verbatim, including its five separately explained failures; follow-up results are not substituted into its counts.

Merge-sweep finding Attribution and follow-up
New quota polling fixture The upstream stub advertised quota-axi 0.1.29, below the retained fork floor 0.1.32. A controlled public poll reports exhaustion on the upstream parent, incompatibility on the merge with 0.1.29, and exhaustion on the merge when only the stub version changes to 0.1.32. The polling fixture is adapted to that supported version; its complete targeted rerun exits 0. The chooser reads an already captured snapshot and needs no fixture change.
New reconcile remote-ledger fixture Its ledger omitted the fork's required abandoned_children array/count, so the retained reader rejected the warm cache input. The fixture now includes empty abandoned_children and a zero count; validation remains strict. The complete reconcile suite rerun exits 0.
New unhinted-script set comparison The same public coverage command under en_US.utf8 passes on the fork parent but fails on the upstream parent and initial merge because the new comm operation did not use its inputs' C collation. Applying the existing fork LC_ALL=C invariant to that operation preserves both intents. The complete runner suite rerun, including its locale-divergence case, exits 0.
New presentation-deadline assertion A diagnostic-only fixture replay captured the fork's deliberate queued-wake supervision banner and pending-queue advisory, with no helper-process diagnostics. The new case now requires that advisory and permits its known renderer lines while still rejecting other stderr. The production guard remains unchanged; the complete wake-queue rerun exits 0.
Unchanged recall fixture This reused task copy already contains ignored data/, contradicting the fixture's source-only-root assumption. Creating only an empty ignored data/ on the unchanged fork parent reproduces the exact expected-2/observed-0 failure, then rmdir removes that control directory. Existing task data is preserved. The complete unchanged recall suite exits 0 in a clean copy of the merged tree.

The canonical lint command was CI=true bin/fm-lint.sh, using pinned ShellCheck 0.11.0 and actionlint 1.7.12.
The final coverage guard reports total=223 parallel=24 serial=161 serial_shards=8 serial_unhinted=5 herdr=12 optin=26.
Documentation checks pass: 126 classified surfaces and 726 local links; pointer check reports 35 checked, 19 valid, 0 broken, and 16 skipped.
All real-Herdr runs use installed Herdr 0.8.2/protocol 20, with unchanged-default tripwires checked separately; CI independently uses its pinned Herdr release.

Supplemental scope and limitations:

  • Strict TypeScript 5.9.3 with installed Pi SDK 0.84.2 passes on the fork parent but fails with the same upstream-owned TS7006 callback in stopSessionGeneration on the pinned upstream parent and final merge (line 423 upstream, line 445 final). The original inventory runs report the repository-defined missing-tsc skip. No type fix was hidden in this sync.
  • The credential-free real Pi SDK 0.84.2 probe exercises watcher-owned fallback, exact transcript persistence, and model/effort precedence without provider requests; all five final SDK cases pass (exit 0), including reopened-session precedence and transcript persistence outside model context.
  • Live GBrain capture passed all four cases on both the unmodified fork parent and the final merge (exit 0). The live read-only-share guard refused this host's inherited hosted-provider credential before starting its fixture server; no credential override or bypass was used. The portable routing, refusal, capture, presence-gating, and inheritance results remain separate survival evidence.
  • Opt-in browser and vendor-agent guards remain explicit skips in the complete inventory. The shared Chrome review session was not commandeered for an unchanged dashboard UI. Bash 3.2 and absent-interpreter cases are checked independently in CI where configured.

Deliberate divergences

Every active entry in the ledger is accounted for below.

Active divergence Survival evidence
Agy crew adapter Crew-only/Herdr-only dispatch, restricted raw launch, atomic inbox doorbell, and distinct typed-plane unverifiable verdict. fm-agy-adapter.test.sh: pass, fm-backend-herdr.test.sh: pass
Pinned ShellCheck download retry budget Pinned checksum/platform behavior and wall-time download retry budget. fm-lint.test.sh: pass
LLM quota sidecar Separate provider eligibility evidence, explicit stale/unknown outcomes, and no ranking or synthesis by the sidecar. fm-quota-sidecar.test.sh: pass
Scout completion gate reopened by a firstmate steer Scout completion reopens on confirmed typed delivery or durable enqueue and restores on proven failure. fm-send-strict.test.sh: pass
Pre-move crash fixture does not perform the move it simulates crashing before The pre-move crash fixture leaves the source item in place rather than allowing a delayed move. fm-backlog-handoff.test.sh: pass
Watcher restart hand-over Restart hands off ownership without a watcher gap or overlapping lock owner. fm-watcher-lock.test.sh: pass
Watcher stop-signal disposition Inherited stop disposition, watcher lock/fd ownership, and helper/FIFO cleanup remain correct. fm-watcher-lock.test.sh: pass, fm-backend-herdr.test.sh: pass
Run-progress wedge hold Only progressing runs earn a bounded wedge hold; stranded, dead, and unknown states still escalate. fm-run-progress.test.sh: pass, fm-watch-triage.test.sh: pass
Watcher live declared-wait routing and self-widening recheck cadence Live declared waits route through bounded widening cadence and stop masking real wedges after the declaration clears. fm-daemon.test.sh: pass, fm-watch-triage.test.sh: pass
Herdr pre-Enter footer read on a native working baseline A native working baseline reaches the guarded pre-Enter footer check without false delivery. fm-backend-herdr.test.sh: pass
Remote job worker descendant reaping Worker cleanup reaps descendants while preserving unrelated processes. fm-remote-job-orphan-reap.test.sh: pass, fm-remote-job.test.sh: pass
Bounded remote job stdin capture Remote stdin capture is bounded and kills the whole timed-out reader tree. fm-remote-job.test.sh: pass
Default per-script bound on every test sweep The 480-second default bound, explicit opt-out, exit distinctions, signal relay, eight-shard partition, and safe fixture cleanup survive. fm-test-run.test.sh: pass after the reviewed integration correction, fm-on.test.sh: pass
No-mistakes run attribution Branch/code identity relations, degraded state replay, and abandoned work remain attributable to the correct task. fm-crew-state.test.sh: pass, fm-teardown.test.sh: pass
Definition-of-done owner carries this fork's ready-to-validate handoff Ordinary validation handoff remains ready-to-validate; this task uses its explicit direct-PR override. fm-trigger-validation.test.sh: pass, fm-brief.test.sh: pass
A preserving refusal withdraws the pending backlog close Preserving teardown refusals withdraw pending backlog closure instead of leaving a stale close. fm-backlog-atomicity.test.sh: pass
A watermark-capture failure keeps the published task record Watermark failure preserves the published task record for recovery. fm-spawn-dispatch-profile.test.sh: pass
Fleet snapshot per-task timeout and abandoned child work Local task bounds/fan-out, degraded rows, and actionable abandoned children survive ledger-only collection. fm-fleet-snapshot-view.test.sh: pass, fm-home-summary-refresh.test.sh: pass, fm-bearings-snapshot.test.sh: pass
Pi away-mode supervision standby Away mode owns one cycle, suppresses ordinary wake delivery, and carries an unconsumed replacement wake until return. fm-pi-watch-extension.test.sh: pass
Fork-local no-mistakes compliance-gate event scope Fork compliance event scope and per-PR coalescing remain enforced. fm-no-mistakes-required-gate.test.sh: pass
Live pull-request body refresh before the compliance gate The compliance gate reads the live PR body rather than stale event payload text. fm-no-mistakes-required-gate.test.sh: pass
Merge-proof contract: one divergence accepted, one retired A failed merge command with independently proven landed state still completes; the retired merge-queue refusal stays retired. fm-pr-merge.test.sh: pass
Upstream tracking mechanism Drift detection remains inert without upstream, measures only in a disposable repository, and self-update remains fast-forward-only. fm-upstream-status.test.sh: pass, fm-update.test.sh: pass
Repository-local validation evidence The effective tracked setting remains test.evidence.store_in_repo=false, and the PR introduces no tracked validation evidence. Tracked .no-mistakes.yaml still sets test.evidence.store_in_repo: false; no validation artifact is tracked.
Upstream-read-only posture in shared tracked docs The upstream write boundary and numbered hard-rule references remain intact. fm-agents-hard-rules.test.sh: pass
GBrain per-home knowledge memory Per-home routing, redaction, presence gating, inheritance, and best-effort capture survive; supplemental live capture passes and live share limitations are explicitly reported. fm-gbrain-lib.test.sh: pass, fm-gbrain-capture.test.sh: pass, fm-gbrain-health.test.sh: pass, fm-recall.test.sh: pass in clean merged copy; workspace limitation attributed above, fm-remote-secondmate-lifecycle-e2e.test.sh: pass
Fleet dashboard and agent-event instrumentation Read-only dashboard behavior, disabled-by-default event wiring, brain UI, usage accounting, and durable completion records survive; dashboard refresh cannot publish the new fleet cache. fm-dashboard.test.sh: pass, fm-dashboard-events.test.sh: pass, fm-dashboard-gbrain.test.sh: pass, fm-dashboard-gbrain-ui.test.sh: pass, fm-dashboard-history.test.sh: pass, fm-dashboard-usage.test.sh: pass, fm-usage.test.sh: pass, fm-teardown.test.sh: pass
Locale-independent test coverage comparisons The new unhinted-script set comparison uses the same C collation as its inputs, preserving the fork non-C-locale coverage guarantee. fm-test-run.test.sh: pass after the reviewed integration correction
Queued wakes remain a supervision requirement A pending queue alone still requires supervision and reports that cause, including during bounded presentation-lock contention. fm-wake-queue.test.sh: pass after the reviewed integration correction, fm-guard-stale-banner.test.sh: pass, fm-turnend-guard.test.sh: pass

Contract-file reasoning

File Reason
.agents/skills/bearings/SKILL.md Take upstream bounded remote-ledger observation and durable reconcile-request publication; retain the fork single-snapshot ownership and deferred fleet-action boundaries.
.agents/skills/fmx-respond/SKILL.md Take complete-payload media inspection and exact-host attachment rules; fork outward-consent and promised-final routing remain authoritative.
.agents/skills/process-event-sources/SKILL.md Add upstream recurring quota adapter and its typed wake route; preserve the existing source registration, durability, acknowledgement, and public-follow-up owners.
.agents/skills/quota-array-dispatch/SKILL.md Keep the fork additive sidecar eligibility policy and spendPriority ranking; the upstream chooser is expressly limited to an already fixed order and primary-provider candidates, so it does not replace fleet intake judgment.
.github/workflows/ci.yml Keep fork eight serial shards, and take the upstream 20-minute job tripwire, Node 22, and extensible fork test-count guards; add upstream real Bash 3.2 first-registration regression and adopt refreshed timing hints in the runner.
.pi/extensions/fm-branch-supervision.ts Take upstream exact transcript outcome entries, sequence-bound processing acknowledgement, incomplete-turn fallback, cooldown reprobe, and watcher-owned settlement; fork away-mode eligibility and Calm consumers are exercised alongside the watcher integration.
.pi/extensions/fm-primary-pi-watch.ts Use upstream tokenized pending-actionable delivery and replacement persistence as the single serialization mechanism, replacing the fork promise-tail implementation while retaining its serial restoration intent. Preserve fork event-loop retirement/readiness settling and away-mode guards at both delivery doors, the pending processor, arm/retry, and return-to-active processing.
.pi/extensions/lib/fm-branch-dispatch.ts Take upstream delivery-token settlement and branch-listener handshake as the shared transport owner; the watcher retains responsibility for pending delivery across replacement.
AGENTS.md Keep the fork one-owner session-start summary and private GBrain/board records; add upstream recovered-status handling and accept the cleanly merged deferred inactive-scan instruction and new outcome record formats.
README.md Describe bounded remote-ledger Bearings reads while retaining fork sync, tool update, fast-forward self-update, and GBrain stow entries.
bin/backends/herdr.sh Take upstream environment scrubbing only when starting a new named server; retain fork explicit session routing, atomic agy prompts, native-working footer checks, and inherited stop-signal handling.
bin/fm-bearings-snapshot.sh Take upstream live-versus-cached ledger provenance and bounded remote-read disclosures; keep fork abandoned-child projections and all dashboard snapshot fields in the canonical producer.
bin/fm-branch-outcome.sh Take sequence-bound processed-state commands for exact outcome handling; existing fork-owned outcome manifests are a separate durable record and remain intact.
bin/fm-classify-lib.sh Take bounded latest-status reads and the fourth presentation-cursor field while retaining fork current-state reconciliation, run-progress holds, and declared-wait routing.
bin/fm-dashboard-server.mjs Force the snapshot cache-read-only mode so adopting upstream remote-ledger collection cannot make a dashboard refresh create or update fleet-owned cache files.
bin/fm-fleet-snapshot.sh Adopt the upstream bounded concurrent remote-ledger collector/cache and remove legacy remote live/computed-summary reads. Retain the fork local per-task timeout/fan-out, degraded-row reconciliation, model/usage/dashboard fields, open-decision policy, and abandoned-child contract; validate abandoned_children at the new ledger reader owner. Preserve both private scratch lifetimes through one EXIT cleanup, and expose read-only cache consumption for the existing dashboard contract.
bin/fm-inactive-reconcile.sh Take upstream bounded inactive scanning under the deferred startup worker; the fork lifecycle refusal and teardown owners are unchanged.
bin/fm-procevent-lavish.sh Retain the fork dynamic help extraction, which already includes the new annotation-comment and canonical-path header without a fixed line range.
bin/fm-procevent-lib.sh Take upstream physical-home canonicalization for trusted process-event paths without changing the fork event instrumentation or source lifecycle boundaries.
bin/fm-procevent-quota.sh Take the new recurring quota adapter with existing process-event ownership, fail-closed input validation, and known-quota/runway wake semantics.
bin/fm-procevent.sh Take upstream canonical-home registration and source execution changes; registration, private bindings, and durable acknowledgements remain with this existing owner.
bin/fm-public-followup-collect.sh Take the new remote work-home collection command, bounded transport, confined staging, and idempotent owning-home intake.
bin/fm-public-followup-emit.sh Take upstream remote staging and local direct emission according to the registered work-home route; no outward reply is sent by collection.
bin/fm-public-followup-lib.sh Take Bash 3.2 first-registration compatibility and guarded remote collection/retirement records under the existing single public-follow-up owner.
bin/fm-public-followup.sh Take remote work-home reporting instructions and guarded legacy-link retirement; uncertain remote completion retains the promise for reconciliation.
bin/fm-quota-axi-lib.sh Take upstream shared schema validation and bounded compatibility probes while retaining the fork quota-axi 0.1.32 floor. Adapt the new upstream quota polling stub to that supported version; sidecar evidence remains independent.
bin/fm-quota-choose.sh Take the optional fixed-order, primary-provider chooser as documented upstream; it is not a second owner of fleet eligibility or ranking policy.
bin/fm-secondmate-reconcile.sh Take durable local request coalescing and later cooldown-limited delivery; target identity checks and failed-request retention preserve home ownership.
bin/fm-session-start.sh Retain the complete fork bootstrap sweep inventory while documenting upstream inactive reconciliation in the deferred startup worker.
bin/fm-startup-network.sh Adopt upstream aggregate bounded inactive-scan/bootstrap child while retaining the fork budget hand-down to bootstrap.
bin/fm-test-run.sh Retain eight shards, fork-only timing rows, opt-in coverage and fork changed-file routing; refresh shared timing rows from upstream, expose unhinted serial coverage, and add new quota tests to their existing dependency owners. Apply the retained fork C-collation rule to the upstream unhinted-script comm operation; the existing non-C-locale regression exercises it.
bin/fm-wake-drain.sh Take bounded presentation-lock waits and missed-status backstop with first-drain outcome-index self-healing; fork keyed decisions and post-handling acknowledgement are preserved.
bin/fm-wake-lib.sh Take bounded presentation locking through the existing queue owner, leaving fork watcher signal disposition and restart handover in their original owners.
bin/fm-watch.sh Take later processing of durable reconcile requests without changing fork watcher restart, stop-signal, progress-hold, declared-wait, or instrumentation policy.
bin/fm-x-followup.sh Take guarded remote legacy-link clearing for the existing public-follow-up retirement path, with unknown transport outcomes remaining unresolved.
bin/fm-x-lib.sh Take inbound attachment retention across the Relay payload and conversation chain; existing request identity and fork outward-consent rules remain intact.
docs/architecture.md Take pointers to quota polling, deferred inactive scanning, remote-ledger cache/request ownership, outcome processing, and remote follow-up collection; preserve fork GBrain, dashboard, instrumentation, and outcome-manifest architecture.
docs/calm-mode-feasibility.md Add the new processed-outcome tool to the existing Calm rendering audit and update deterministic outcome entry behavior; no second visibility policy is introduced.
docs/configuration.md Retain fork durable records, recall state, and the single FM_SNAPSHOT_TASK_TIMEOUT contract; add upstream remote-ledger cache, aggregate budget, and reconcile-request configuration.
docs/dashboard.md Document the dashboard-specific read-only cache setting at its runtime-behavior owner.
docs/fm-test-portable-shards.md Document upstream refreshed shared timing hints together with preserved fork-only measurements, recompute all eight fork shard estimates, retain fork artifact-download target and opt-in exclusion, and describe the adopted upstream 20-minute cap.
docs/fork-divergence.md Update four active entries for adopted shard weights/cap, local-vs-remote snapshot bounds and scratch ownership, Pi replacement serialization with away-mode survival, and dashboard cache-read-only enforcement; retire no active intent and leave the parked list unchanged. Add the locale-independent coverage entry for the retained fork invariant extended to the upstream unhinted-script comparison. Also record queued wakes as a supervision requirement, whose deliberate advisory the new deadline fixture must preserve.
docs/herdr-backend.md Document upstream new-server environment scrubbing next to the existing named-session startup owner; fork native-working and agy semantics remain present.
docs/pi-supervision-branch-poster.svg Take the upstream companion illustration for exact outcome processing and watcher settlement; the prose contract remains in pi-supervision-branch.md.
docs/pi-supervision-branch.md Take upstream sequence-bound outcome processing, incomplete-provider-turn fallback, cooldown reprobe, and replacement-safe watcher settlement while retaining existing away-mode eligibility.
docs/scripts.md Retain all fork-only tooling and fleet-sync guarantees; update existing startup and snapshot rows and add the upstream quota chooser beside the additive sidecar.
docs/sessionstart-nudge.md Take the upstream deferred inactive-scan startup routing clarification; the fork session-start composition owner remains the script header.
docs/supervision-protocols/pi.md Take automatic replacement-session arming and explicit processed-outcome acknowledgement; retain the fork away supervisor ownership and no-duplicate-arm rules.
docs/verification/public-followup.md Take upstream Bash 3.2 and remote retirement/collection evidence with version and transport scope stated; fork local completion markers do not replace those behavioral cases.
docs/verification/runtime-backends.md Preserve the fork dated observations byte-for-byte, add a dated scope annotation for superseded fallback/provider-conversion probes, and take upstream new dated SDK outcome/settlement evidence; preserve agy coverage and installed-surface limitations. Append the observed 2026-09-08 Linux/Pi 0.84.2 replacement and real-SDK results, explicitly distinguishing the inherited strict TypeScript failure.
docs/verification/supervision.md Keep the original dated Pi transition observation intact and append upstream replacement-session evidence as a separate dated entry, honoring the fork append-only verification owner.
docs/watcher-continuity.md Combine upstream session-replacement delivery guarantees with fork away-mode ownership and deterministic event-loop stall coverage.

Collision test-file reasoning

The contract-file table above and this test-file table account for every reached collision-risk path.

Test file Review
tests/fm-backend-herdr.test.sh Add the upstream new-server environment proof while retaining fork atomic-prompt, native-working footer, blocked-baseline, and cleanup cases.
tests/fm-bearings-snapshot.test.sh Keep oversized-backlog coverage, add upstream concurrent remote/cache cases, and union actual tool dependencies in the timeout-free fixture PATH. Include fork abandoned_children in new upstream ledger fixtures and prove read-only cache no-create/no-overwrite/fallback behavior and both scratch lifetimes through public snapshot execution.
tests/fm-bootstrap-network-parallel.test.sh Take the bounded fixture rendezvous that proves the fetch and doctor workers overlap without depending on equal-sleep scheduling.
tests/fm-extension-binding.test.sh Add capture through a symlinked home ancestor while retaining fork isolated section scheduling, trust, and descendant cleanup cases.
tests/fm-fleet-snapshot-view.test.sh Retain all fork dashboard, bounded-reader, abandoned-child, enrichment, and collector-cost cases; add upstream exclusion of persistent secondmate metadata from child inventory.
tests/fm-home-summary-refresh.test.sh Keep the fork per-task timeout name and remove the legacy cross-home timeout upstream no longer uses.
tests/fm-on.test.sh Retain fork shared descendant-safe worker cleanup rather than reintroducing upstream raw whole-group stop; the production change is taken independently.
tests/fm-pi-watch-extension.test.sh Retain deterministic spawn/retirement observations and upstream consumption handlers; run the unconsumed-follow-up replacement scenario both while active and while away, proving no wake delivery or extra watcher until return.
tests/fm-pr-check-security.test.sh Use upstream zombie-aware process observation for watcher/child retirement while retaining fork guarded PR identity and deletion authority cases.
tests/fm-procevent.test.sh Take symlinked-home execution and all Lavish annotation-comment cases; preserve the fork process-event fixture and lifecycle coverage.
tests/fm-public-followup.test.sh Run every upstream remote follow-up case before the fork success marker, preserving meaningful completion evidence.
tests/fm-remote-secondmate-lifecycle-e2e.test.sh Publish local and remote fixture ledgers through the real owner before snapshot reads, and test no-ledger transport loss without a liveness probe or local respawn; retain fork inheritance and GBrain cases.
tests/fm-secondmate-reconcile.test.sh Keep the fork lock-held behavioral proof and generous hang bound instead of restoring upstream 2-second scheduling sensitivity; take new request/deferred-delivery cases and include the fork abandoned_children array/count in the new remote-ledger fixture.
tests/fm-session-start.test.sh Take deferred inactive-scan and exact-outcome delivery-barrier cases while retaining fork complete startup, lock-refusal, and recovery coverage.
tests/fm-startup-network.test.sh Take phase-aware single-flight and deferred invalid-marker cases while retaining the fork timeout budget hand-down proof.
tests/fm-test-run.test.sh Take quota dependency-selection and unhinted-share coverage; retain fork default timeout, locale independence, opt-in inventory, and per-case optional-interpreter behavior.
tests/fm-wake-drain-open-decisions.test.sh Use a resolved fixture event to isolate empty-open-decision output from the new terminal-status backstop; retain the fork durable keyed-decision cases.
tests/fm-wake-queue.test.sh Add bounded lock handoff, deadline/retry, and malformed-lock refusal without weakening queue durability or acknowledgement atomicity. Require and permit the intended fork queued-wake advisory while still rejecting unexpected helper diagnostics.
tests/fm-watch-triage.test.sh Canonicalize only the process-event fixture home paths, preserving all fork run-progress, declared-wait, cadence, and stale-state policy cases.
tests/fm-x-mode.test.sh Add complete inbound-media payload preservation and prove that polling does not fetch attachment URLs; retain fork Relay lifecycle coverage.
tests/lib.sh Take physical TMPDIR canonicalization for symlinked homes while retaining fork event configuration, store, and credential isolation.

Collision audit and ledger changes

The first prefix reaches 50 of the detector collision-risk paths and has 20 textual conflict paths.
The 50-path set was independently checked against both the net upstream diff and the union of every first-parent change in the prefix; both sets match.
The silent-collision audit includes the new remote cache versus the fork read-only dashboard, local task bounds and abandoned-child summaries versus ledger-only collection, and upstream replacement delivery versus fork away-mode standby.

Four active ledger entries are updated: the per-script validation bound and shard timing/cap; local snapshot bounds, abandoned children, and scratch ownership; Pi away-mode standby under upstream tokenized replacement serialization; and read-only dashboard cache consumption.
Two active entries are added: locale-independent coverage comparisons and queued wakes as a supervision requirement.
They record retained fork guarantees that the new upstream comparison and presentation-deadline case must preserve.
No active divergence intent is retired.

The parked-branch list remains unchanged.
All five parked branch tips were resolved from fetched origin references, and none of their commits unique to the fork base intersects the incoming upstream ancestry.
No parked branch was merged, resurrected, used as a rebase base, or cherry-picked.

CI observation and retry

The first CI attempt passed lint, coverage, repository invariants, both parallel shards, seven serial shards, real Herdr, macOS Bash compatibility, and timing aggregation.
Serial shard 4 failed only the existing fm-dashboard.test.sh cadence assertion: a poll arriving mid-snapshot queued an immediate catch-up run (2 runs).
The original local full sweep passed this suite on both the fork parent and merge.
A controlled replay of that exact case against each tree's unchanged dashboard server passes with the original 20 ms observation delay and reproduces the same failure on both trees when only that delay becomes 140 ms.
Observed snapshot starts are 252 ms apart on both trees, consistent with the configured 150 ms timeout plus 100 ms poll interval; this disproves an immediate catch-up loop in the replay.
The merge changes only the snapshot child's read-only cache environment, and the cadence function and production scheduling are unchanged from the fork parent.
This is retained fork fixture timing sensitivity, recorded separately from merge adaptations; no tracked fix or assertion relaxation was added for it.
The complete unchanged dashboard suite was rerun on the fork parent and merge after this CI observation; both pass (exit 0).
The failed job was rerun once at the same head and passed.
CI attempt 2 is successful, with all 16 validation checks passing and only the intentional no-mistakes compliance check red.
This retry does not erase the first-attempt failure or its fork-parent attribution above.

Delivery and landing

This ships direct-PR, as instructed by Firstmate.
The expected red PR must be raised via no-mistakes check is intentional: no-mistakes rebases onto origin/main, which would linearize this merge-only round.
All 16 other checks pass: lint, test coverage, repository invariants, two portable parallel shards, eight portable serial shards, real Herdr, stock macOS Bash compatibility, and timing aggregation.

Pushed head: 1f0c113c88d68bd4bb45475b49eebafdd1f02ef0.
Mergeability checked at 2026-09-09 00:03 UTC: GitHub reports mergeable: true at the exact pushed head and unchanged base ab9f96fa20bee46b4b0a13e00ac06ae97a344530; mergeable_state: unstable reflects the intentional compliance red after all other checks pass.

Do not squash this PR.
The landing handler must use:

bin/fm-pr-merge.sh fm-upstream-sync-2026-09-08-round-1 https://github.com/HelloWorldSungin/firstmate/pull/269 -- --merge

The explicit --merge preserves upstream parentage and advances the merge base for subsequent rounds.

0x7067 and others added 21 commits August 31, 2026 07:50
…o dedicated scripts (kunchenguid#3221)

* Add quota exhaustion detection and safe fallback helpers

- bin/fm-procevent-quota.sh: generic procevent adapter that arms a
  recurring quota-axi --json poll and wakes firstmate when a tracked
  provider's effectivePercentRemaining drops below a threshold or its
  runway.status becomes exhausted_now.
- bin/fm-quota-choose.sh: worker-side helper that picks the first ranked
  harness:model candidate with positive effectivePercentRemaining.
- AGENTS.md and .agents/skills/quota-array-dispatch/SKILL.md: document
  the new helpers and the mid-task quota-exhaustion wake path.
- tests/fm-quota-choose.test.sh: unit tests with a mocked quota-axi JSON
  source.

* no-mistakes(review): Fix quota polling and scope bounds

* no-mistakes(review): Enforce safe default quota selection

* no-mistakes(review): Handle decimal quota values safely

* no-mistakes(review): Fail closed on invalid quota inputs

* no-mistakes(review): Reject empty quota candidate segments

* no-mistakes(review): Harden quota parsing and timeout ownership

* no-mistakes(review): Reuse captured quota snapshots consistently

* no-mistakes(review): Match quota using explicit candidate providers

* no-mistakes(review): Centralize fail-closed quota schema validation

* no-mistakes(review): Reject out-of-range quota percentages

* no-mistakes(review): Validate quota runway status enum

* no-mistakes(review): Tighten quota scope and status contracts

* no-mistakes(review): Preserve unknown quota and exact product bounds

* no-mistakes(review): Preserve provider-level unknown quota

* no-mistakes(review): Reuse canonical verified harness validation

* no-mistakes(document): Document mid-task quota handling

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* fix(docs): restore default routing contract, keep quota helper optional

Restore the AGENTS.md section 4 always-loaded routing paragraph the PR
had deleted, so the standing TOON-first intake, spendPriority ranker,
every-candidate accounting, and load-trigger contract stay exactly as
before this PR. The mid-task quota wake is optional and must not alter
default routing.

Restore the quota-array-dispatch skill ownership line to section 4 as
the always-loaded intake boundary owner; keep the worker-side helper
section as an addition only, without rewiring ownership or load
triggers to section 13.

* fix(bin): use harness-keyed quota matching in optional helper

Revert fm-quota-choose.sh from harness:provider:model tuples back to
harness:model candidates with harness-keyed provider matching, per the
resolved ask-user finding. The helper is optional; authoritative
multi-provider routing (provider discovery from the harness catalog and
quota matching by that explicit provider) stays owned by AGENTS.md
section 4 and the quota-array-dispatch skill intake procedure, not the
helper.

Document the multi-provider limitation in the helper header and the
quota-array-dispatch skill: the helper maps each harness to one primary
provider family only, so a candidate whose established provider differs
from that primary family is checked against the wrong quota row. Use it
only when the brief fixed the candidate order and every candidate's
provider is the harness's primary family.

The helper still consumes one already-captured default-TOON or JSON
snapshot via stdin or --snapshot and never calls quota-axi itself, so
it selects from the same quota state as the intake.

* no-mistakes(review): Fix Muse quota mapping and helper contract docs

* no-mistakes(review): Reject known-empty quotas and map quota tests explicitly

* no-mistakes(review): Preserve unmeasured candidates and enforce snapshot reuse

* no-mistakes(review): Fix quota retirement and dependent regression coverage

* no-mistakes(review): Accept zero-row quota TOON snapshots

* no-mistakes(review): Enforce quota semantics status consistency

* no-mistakes(review): Veto dispatch on any exhausted applicable scope

* no-mistakes(review): Record exhausted quota scope in wake details

* no-mistakes(review): Fix quota help and control dependency coverage

* no-mistakes(review): Decode quoted TOON fields and document quota wakes

* no-mistakes(review): Validate zero-row TOON and map timeout coverage

* no-mistakes(review): Reject multi-value JSON and malformed TOON envelopes

* no-mistakes(review): Validate complete nonzero TOON envelopes

* no-mistakes(review): Accept producer-shaped quota TOON envelopes

* no-mistakes(review): Support empty quota arrays and validate counted rows

* no-mistakes(review): Harden TOON completion, scopes, and quoted fields

* no-mistakes(review): Preserve unknown-headroom exhaustion and reject trailing fields

* no-mistakes(review): Allow unknown headroom under known semantics

* no-mistakes(review): Reject noncanonical quota identities

* no-mistakes(review): Preserve empty quota polling and validate attention identities

* no-mistakes(review): Reject noncanonical provider watches

* no-mistakes(review): Validate all candidates before quota selection

* no-mistakes(document): Correct quota helper safety documentation

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes
* fix(bin): keep typed Lavish comments when an element is also annotated

read preferred element text over prompt, so an annotate-and-comment
item dropped the captain's words. Surface prompt as its own field.

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

* no-mistakes(review): Filter non-comment prompts from Lavish reader output

* no-mistakes(document): Clarify Lavish comment presentation contract

* no-mistakes(ci): Fixed Lavish reader comment provenance: non-choice prompts are now emitted even when identical to element text. Added observable regression coverage for identical selector+comment input while retaining pure annotation/message coverage. Reader cases, bash syntax, and diff checks pass. Full fm-procevent suite stops earlier at unrelated “reconcile never claimed” setup failure

* no-mistakes(ci): Fixed duplicate pure-annotation prompts by emitting `prompt:` only when it differs from captured element text. Updated behavioral coverage for selector+comment, pure annotation, and pure message cases. Focused reader regressions, syntax checks, and diff checks pass. Full suite remains blocked by the pre-existing “reconcile never claimed the registered source” failure

* fix(bin): always emit Lavish comments and use real annotation fixtures

Stop inferring comment provenance from prompt==text. Real pure
annotations have no prompt, so always-emit does not duplicate.

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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…uid#3420)

* Fix public-followup register crashing on empty lock arrays under bash 3.2.

bash 3.2 with set -u treats "${arr[@]}" on an empty array as unbound, so the first register in a fresh home aborted before taking the registry lock.
The empty-lock regression also runs under the existing stock macOS Bash CI lane so pre-fix code would fail there.

* no-mistakes(document): Document stock Bash registration coverage

* no-mistakes(ci): Pinned the stock macOS Bash CI lane to tasks-axi@0.2.5, eliminating dependency drift. Verified workflow YAML parsing, git diff checks, and the focused regression under /bin/bash 3.2.57 with tasks-axi 0.2.5

* no-mistakes(ci): Fixed the flaky portable CI test: it treated exited zombie processes as live because `kill -0` succeeds for zombies. The watcher and descendant assertions now check process state and regard zombies as exited. Verified `tests/fm-pr-check-security.test.sh`, ShellCheck, `git diff --check`, and the focused Bash public-followup regression
* fix(herdr): isolate server launch environment

* no-mistakes(review): Clear inherited supervision model from Herdr launches

* no-mistakes(document): Document Herdr server launch environment isolation
* fix: surface inbound Relay attachments to the responding agent

A Discord support thread's screenshots were never seen by the agent
handling the mention. The relay delivered them and the poll stashed
them: the reporter's images arrived on the `thread_starter` entry of
`in_reply_to_chain` while the mention's own media list was empty. The
gap was in the responder's playbook, which enumerated a fixed field
list (`request_id`, `text`, `in_reply_to`, `in_reply_to_chain`) and so
made every other field, attachments included, invisible.

Fix it where the gap is, in prose:

- Read the complete payload object rather than a fixed field list, so
  media and later relay fields are never skipped again.
- Fetch and view attached media with the agent's own tools, on the
  mention and on every chain entry, and call out the common shape where
  only the thread starter carries the screenshots.
- Restrict those fetches to known-good platform media hosts over https
  (Discord: cdn.discordapp.com, media.discordapp.net,
  images-ext-1.discordapp.net, images-ext-2.discordapp.net; X:
  pbs.twimg.com, video.twimg.com), report a blocked host instead of
  working around it, and treat everything fetched as untrusted public
  input on the same terms as the surrounding thread text.

The poll stays out of it and downloads nothing, so no third-party bytes
are pulled on the polling path.

The new test pins the contract the playbook depends on: a mention in the
incident's shape, with an empty top-level media list and screenshots on
the thread starter, must reach the inbox with the payload intact and its
media URLs unfetched.

* no-mistakes(review): Preserve media authority and enforce poll-only fetching

* no-mistakes(document): Clarify Relay attachment safety prose
)

* Defer inactive startup reconciliation

* no-mistakes(review): Queue deferred inactive reconciliation diagnostics durably

* no-mistakes(review): Require worker phases to cover startup requests

* no-mistakes(review): Make diagnostic wakes safely acknowledgeable

* no-mistakes(document): Document deferred startup phase coverage
* fix: bound status presentation lock waits

* no-mistakes(review): Distinguish malformed presentation locks from live contention

* no-mistakes(review): Bound no-ack drain queue lock acquisition

* no-mistakes(document): Document bounded presentation-lock drain behavior

* no-mistakes(lint): Annotate bounded lock output global

* no-mistakes(ci): Added deterministic regression coverage for successful bounded-lock acquisition after live contention, verifying helper-to-caller PID ownership handoff and caller release. Verified with bash syntax checks, git diff checks, and the full fm-wake-queue test suite
* fix(relay): close a public loop whose work lives in a remote secondmate home

A public-followup loop bound to a REMOTE secondmate could never be closed.
`clear_public_followup_link` (bin/fm-public-followup.sh:701) required an
absolute recorded `work_home_path` for a `secondmate:*` work home, but a remote
route has no local path on this machine, so registration records that field
empty (bin/fm-public-followup.sh:291). Every close ran that clear first, so
`retire` died with "could not clear the legacy X link ... retained for
reconciliation" forever, and `deliver` posted the public reply and then stranded
the loop at `posted`. `--force` never covered that step.

The clear now goes to the remote home over that route's SSH transport, running
`fm-x-followup.sh --clear <work-id>` through `bin/fm-on.sh`. The route is decided
from `data/secondmates.md` before any local path is consulted, so a same-named
local directory can never stand in for a remote home, and registrations already
on disk retire without needing a new field. `fm-on.sh` passes ssh's status
through, so 255 stays the established "delivered but completion unknown" result
this codebase already reconciles: the close is refused, the registration and the
remote link are left exactly as they were, and the message names the unknown
completion instead of claiming a definite failure.

Local secondmate and `main` work homes are untouched, and `--force` still
governs only the unresolved-obligation refusal.

Three regression cases drive a remote route end to end, faking only the ssh
binary at the FM_SSH_BIN seam and then running the real remote entrypoint
against a local checkout, so the clear that must reach the remote home actually
happens there.

* no-mistakes(review): Guard remote link clears by request identity

* no-mistakes(review): Fail guarded clears on unreadable remote state

* no-mistakes(review): Reject guarded clears on non-writable remote state

* no-mistakes(review): Allow no-link retirement in non-writable remote state

* no-mistakes(document): Correct public-followup verification guarantee count

* no-mistakes(ci): Fixed the guarded link-clear race by ensuring absence is decided under the metadata lock whenever publication is possible. Added a behavioral concurrency regression test. Verified with fm-x-mode and fm-public-followup suites, Bash syntax checks, diff checks, and bin/fm-lint.sh

* no-mistakes(ci): Fixed the guarded link-clear race by refusing an unlocked absence decision when a publisher already owns the metadata lock in a non-writable directory. Added a behavioral concurrency regression test. Verified with fm-x-mode, fm-public-followup, syntax/diff checks, and fm-lint

* no-mistakes(ci): Fixed the guarded-clear race by refusing all guarded clears when the metadata parent is non-writable, including apparent link absence. Added a behavioral regression with a publisher waiting to create the lock, updated remote-retirement expectations and verification docs. Passed fm-x-mode, fm-public-followup, fm-lint, documentation audience, Bash syntax, and diff checks

* fix(relay): bound the guarded remote link clear so it refuses instead of hanging

The guarded clear checks that the remote state directory is writable before
taking the metadata lock, but that check cannot close the window: the parent can
turn non-writable between the check and lock creation, and a lock held by a live
holder is indistinguishable from that at the acquire. `fm_lock_acquire_wait` is
an unbounded `while ! try; do sleep 0.1; done`, so either case retried forever
and `deliver` or `retire` wedged with nothing reported, instead of returning the
retained-for-reconciliation refusal the guard exists to produce. This path runs
unattended over the secondmate transport, where a wedge is worse than either
outcome the guard defines.

The guarded clear now acquires through `fm_lock_acquire_wait_bounded`
(FMX_LINK_CLEAR_LOCK_TIMEOUT, default 10 seconds) and refuses on timeout through
the existing failure path. Unguarded local callers keep the ordinary unbounded
wait, so local behavior is unchanged.

The bounded primitive's header no longer claims presentation-only scope, since
this is a second authorized caller; nothing else in the shared lock
infrastructure changed.

The regression holds the metadata lock with a genuinely live process while
leaving the state directory writable, so the refusal can only come from the
bound and never from the writability precondition. Against the unbounded wait it
does not terminate at all; with the bound it refuses, retains the registration,
writes no receipt, and leaves the remote link untouched.

* no-mistakes(review): Harden lock-timeout regression with independent deadline

* no-mistakes(review): Restore no-op guarded clears on read-only state

* no-mistakes(document): Clarify remote public-followup cleanup contract
)

* fix(bin): resolve process-event state roots before validating them

The process-event module validated the caller's spelling of a home's state
root instead of the directory it operates on: it required the supplied path
to equal its own lexical normalization, which rejects any path reached
through a symlinked ancestor. On macOS both /tmp and $TMPDIR are symlinks,
so an operator home under either could never claim a source. Reconcile still
reported the runner started, while the detached runner died writing "cannot
claim source" to the discarded stderr, and the source silently never fired.

Resolve the state root to its physical directory once, then apply the
existing private-directory validation to that resolved directory and derive
every path, recorded claim identity, and later confinement check from it.
This keeps the confinement contract for the directory actually operated on
rather than only for callers that already spelled it physically, and removes
the window where an ancestor symlink could be repointed between check and
use. Homes already spelled physically behave identically.

This was the single cause of both deterministic macOS failures in
tests/fm-procevent.test.sh ("reconcile never claimed the registered source")
and tests/fm-procevent-when.test.sh ("the winning concurrent arm did not
produce an outcome"). The new case pins the behavior with an explicit
symlinked-ancestor home, so it fails without the fix on any platform rather
than only where the temp root happens to be a symlink.

* fix(bin): pin the external capture staging boundary to its physical path

The extension capture path pinned its registry staging boundary by comparing
`pwd -P` against the caller-spelled registry directory, so a home reached
through a symlinked ancestor still refused to start an extension-backed
source after the state root itself resolved correctly. That left such a home
half working: built-in sources ran while external ones failed.

The staging preparer now prints the physical registry directory it validated,
matching the inbox and reservation preparers beside it, and the start path
pins on that returned path. The new end-to-end case drives the shipped
file-signal package from a symlinked home spelling.

* no-mistakes(review): Propagate canonical process-event state roots

* no-mistakes(review): Propagate canonical state to process-event adapters

* no-mistakes(document): Document physical process-event state roots
…kunchenguid#3312)

* fix(pi): persist captain outcomes visibly

* no-mistakes(review): Recover captain outcomes after cold-start lock acquisition

* no-mistakes(document): Document cold-start captain-outcome recovery

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes(review): Prove immediate Pi captain-outcome transcript delivery

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* no-mistakes: apply CI fixes

* fix(pi): process captain outcomes through a sequence-keyed turn

PR kunchenguid#3312 made every captain-facing supervision outcome a durable, exact-once
visible transcript entry with the read cursor advancing only after that entry
exists. That is the display half of the delivery contract. Left alone it turns
a probabilistic silent loss into a deterministic one: the captain sees an
anchor line, and firstmate never acts, because nothing opens a turn and
nothing records whether main ever processed the outcome.

The 2026-08-31 timeline showed the two shapes this must survive on the
previous hidden-turn path: seven delivered decision outcomes each answered by
an empty assistant message (cursor advanced, no retry, unanswered for close
to three hours), and two answered by an unrelated prior reply. Both happened
because delivery advanced the cursor at enqueue and accepted whatever the
next assistant message was.

Add the processing half on top of the persistence half:

- bin/fm-branch-outcome.sh keeps a processed marker separate from the read
  cursor (`unprocessed`, `mark-processed --through`, `processed-init`). It
  only advances through an explicit sequence-bound acknowledgement, never
  past the read cursor and never backwards; an absent marker reads as zero
  and `processed-init` migrates delivered history once so an upgraded home
  is not re-presented its past.
- After the visible entry for a captain outcome exists, the extension hands
  every still-unprocessed captain row to main as one hidden, typed
  `fm-branch-process` request listing each `[seq N] task: summary`, opening
  exactly one main turn. Main closes it only by calling the new
  `fm_branch_processed` tool with the highest sequence listed. An unrelated,
  empty, or paraphrased answer leaves the sequence open, and the same request
  is presented again at the end of the next main run and at session start.
  The first two presentations of a sequence set open a turn of their own;
  after that the request rides the captain's next prompt so an ignored
  request cannot loop, and a session replacement resets that budget.
  Routine outcomes stay turn-free.
- The regressions cover exactly those incident shapes against the real store
  scripts: an empty answer and an unrelated prior answer neither advance the
  marker nor stop re-presentation, the acknowledgement is refused beyond the
  read cursor and outside lock ownership, a partial acknowledgement keeps the
  newer sequence open, and kunchenguid#3312's own assertions now forbid an unkeyed turn
  rather than any turn. The store suite pins the marker's bounds and the
  migration; the real-SDK guard for appendEntry persistence and model
  exclusion is unchanged.

Docs move the protocol from "no model turn" to "one sequence-keyed processing
turn closed only by its acknowledgement", and the verification record carries
the dated run against Pi 0.84.4.

* no-mistakes(review): Harden outcome listing and sequence-bound acknowledgements

* no-mistakes(review): Harden outcome state validation and request pacing

* no-mistakes(review): Reject unsafe sidecars and unterminated outcome stores

* no-mistakes(review): Validate canonical mark-read cursor state

* no-mistakes(review): Guard cursor advancement against corrupt processed state

* no-mistakes(review): Bind acknowledgements to active processing requests

* no-mistakes(review): Reset pacing when processing sequence membership changes

* no-mistakes(review): Enforce silent outcome invariants at storage boundary

* no-mistakes(document): Document hardened captain outcome processing contracts

---------

Co-authored-by: kunchenguid <kun@kunchenguid.com>
…3481)

* feat: bound Bearings remote ledger collection

* no-mistakes(review): Clarify default remote-ledger collection behavior

* no-mistakes(review): Detach reconcile delivery from watcher loop

* no-mistakes(review): Enforce bounded snapshot and request captures

* no-mistakes(review): Bound legacy summary capture before parsing

* no-mistakes(review): Bound primary remote ledger captures

* no-mistakes(document): Correct snapshot and reconcile documentation

* no-mistakes(lint): Fix ShellCheck quoting in bounded collector

* no-mistakes(ci): Fixed all three CI failures: updated the macOS Bearings assertion to 44 tests, made the home-summary test deterministic and aligned with default ledger consumption, and increased the asynchronous reconcile retirement wait for loaded CI. Verified both focused suites, all 44 Bearings tests, ShellCheck, actionlint, Bash parsing, and git diff checks

* test: await reconcile request retirement

* no-mistakes(review): Avoid empty reconcile queue process churn

* no-mistakes(review): Read ledger summaries from immutable snapshots

* no-mistakes(review): Reject multi-document home ledger streams

* no-mistakes(review): Coalesce durable reconcile requests per target

* no-mistakes(review): Unify reconcile keys and reject snapshot streams

* no-mistakes(review): Key reconcile requests by stable target ID

* no-mistakes(document): Document per-target reconcile request coalescing

* no-mistakes(lint): Remove unused snapshot summary file variable

* no-mistakes(ci): Adjusted the concurrent collector regression’s end-to-end timing ceiling to account for stock macOS process/jq overhead outside the three-second remote collection budget, while remaining below the 15-second serial-read floor. Verified with stock /bin/bash 3.2: all 44 Bearings tests pass; bash syntax and git diff checks pass

* no-mistakes(ci): Fixed legacy summary validation to require exactly one top-level JSON document and added behavioral regression coverage. Stabilized CI by conditionally waiting longer for durable reconcile delivery and synchronously stopping the fm-on worker tree before fixture cleanup. Removed a redundant flaky healthy-path timing assertion; the wedged-reader test still proves concurrent bounded collection. Verified fm-bearings-snapshot, fm-secondmate-reconcile, and fm-on tests, plus project ShellCheck, bash syntax, and git diff checks
* fix(ci): rebalance the portable serial shards on measured durations

The "Behavior portable serial 3" shard ran 17-20 minutes against its
20-minute job cap and intermittently timed out seconds after a passing
test, on branches and on main alike.

Shards are packed longest-processing-time from per-script duration hints,
and those hints were last measured on 2026-08-21 at 116 scripts. The lane
has since grown to 139 scripts and from ~42 to ~63 minutes: 17 scripts had
no hint at all and fell back to the 20 s default, and several existing
hints were low by 2-5x (fm-watch-triage 142 s hinted vs 263 s measured,
fm-public-followup 36 s vs 197 s). The partition therefore looked
perfectly balanced in hint space, 734.6 s per shard, while really running
11.5, 13.6, 18.8 and 16.5 minutes. Script-count balance, which is what the
tests asserted, stayed normal throughout and hid it.

Refresh the hints from the timing artifacts of three green runs, taking
the slowest measurement of each script so the balance holds on a slow
runner, and split the lane across five shards instead of four. Replayed
against those runs' real per-script durations the worst shard is now
12.54 minutes, 63% of the unchanged 20-minute cap, and the serial lane's
wall clock drops from ~20 to ~12.5 minutes.

Bound the drift that caused this rather than relying on the hints being
refreshed by hand: the coverage guard now reports the unmeasured share as
serial_unhinted= and refuses past PORTABLE_SERIAL_MAX_UNHINTED_PERCENT,
which leaves room for newly added tests while making a stale table fail
the guard instead of silently pushing one shard into its cap.

No test changes what it asserts and no test stops running; only the
partition across shards changes.

* no-mistakes(document): Clarify conservative shard timing aggregate
…uid#3491)

* fix(pi): fall back after settled branch errors

* no-mistakes(review): Detect provider errors across prompt compaction

* no-mistakes(review): Preserve in-flight branch state across selection changes
* fix(pi): recover supervision branch after cooldown

* no-mistakes(review): Defer branch recovery until prompt settlement

* no-mistakes(document): Clarify supervision cooldown recovery contract
* refactor: remove legacy remote summary reads

* no-mistakes(document): Document ledger-only snapshot reads

* no-mistakes(ci): Fixed the snapshot test fixture so ledger refreshes use the same fake executable PATH as the snapshot consumer. This preserves observable endpoint freshness after removing legacy summary computation. Verified stock Bash parsing and all 44 Bearings tests pass under /bin/bash; git diff checks pass

* no-mistakes(ci): Fixed the CI-only snapshot fixture failure by ensuring the bounded-ledger refresh uses its fake tmux backend. This removes host tmux availability as a source of nondeterminism. Verified all 44 Bearings tests pass, Bash syntax passes, and git diff checks are clean

* no-mistakes(ci): Fixed CI nondeterminism in the Bearings fixture: all local ledger refreshes now use the fixture’s fake tmux backend when available, instead of depending on host tmux state. Verified stock /bin/bash syntax, git diff checks, and all 44 Bearings tests with a deliberately failing host tmux
…henguid#3498)

* fix(pi): rearm watcher after session replacement

* no-mistakes(review): Queue actionable closes across Pi session replacement

* no-mistakes(review): Stop replacement arm when handoff persistence fails

* no-mistakes(review): Preserve actionable wakes through branch and late child races

* no-mistakes(review): Surface late handoff failures without crashing Pi

* no-mistakes(review): Coordinate replacement delivery settlement and unique handoff tokens

* no-mistakes(review): Retry stale deliveries and release settled claims

* no-mistakes(review): Distinguish branch settlement and retry handoff cleanup

* no-mistakes(review): Deduplicate persistent handoff cleanup alerts

* no-mistakes(review): Acknowledge watcher follow-ups only when consumed

* no-mistakes(review): Persist idle follow-ups until agent consumption

* no-mistakes(review): Preserve pending outcomes when handoff persistence fails

* no-mistakes(review): Arm replacement before awaiting prior delivery settlement

* no-mistakes(review): Adopt pending handoffs after lock reclamation

* no-mistakes(review): Prevent stale generations from adopting replacement handoffs

* no-mistakes(review): Scope replacement handoffs by watcher state

* no-mistakes(document): Clarify replacement handoff documentation

* no-mistakes(ci): Fixed the failing branch-extension tests to model the new settlement-promise contract. Failure cases now assert that delivery ownership returns to the watcher instead of expecting direct extension fallback. Verified the updated branch suite, Pi watcher suite, shell syntax, and diff checks

* no-mistakes(review): Update branch settlement tests and preserve chunked outcomes

* no-mistakes(document): Document watcher-owned replacement handoffs

* no-mistakes(document): Verify replacement handoff documentation

* test(pi): cover watcher-owned branch fallback

* no-mistakes(document): Refresh watcher-owned fallback documentation
…d#3495)

* fix(bin): resurface terminal statuses lost after branch handling

* test(watch): canonicalize process-event fixture homes

* no-mistakes(review): Index branch outcomes by causal status position

* no-mistakes(review): Recover outcome indexes and deduplicate resurfaced statuses

* no-mistakes(review): Handle legacy ambiguity and oversized status diagnostics

* no-mistakes(review): Keep unclassifiable oversized statuses silent

* no-mistakes(document): Document lost-wake outcome backstop

* no-mistakes(document): Update outcome backstop documentation

* no-mistakes(ci): Fixed CI regressions in wake-drain: parseable reserved-key decisions can no longer bypass the durable decision-fold guard, and status output is prepared and receipt-committed before presentation to prevent repeated one-shot outcomes after later failures. Added a behavioral regression for receipt commit failure and retry. Targeted backstop, correlation-token, decision-cursor, open-decision, unread-status, syntax, and diff checks pass locally. Shard-4 failures appeared unrelated/flaky; the network-parallel test passed locally

* no-mistakes(ci): Fixed the Greptile P1 data-loss issue by committing presentation receipts only after prepared output reaches stdout. Added behavioral coverage proving output failure leaves the backstop retryable and receipt failure may duplicate but never lose a presentation. Relevant wake-drain suites and syntax/diff checks pass. The shard-4 Pi extension failure is unrelated to this PR and did not warrant changes

* no-mistakes(ci): Stabilized tests/fm-bootstrap-network-parallel.test.sh by replacing scheduler-sensitive equal-sleep timing with bounded synchronization between mocked fetch and remote probes. This preserves detection of real serialization while avoiding false failures under CI load. Verified with five consecutive test runs, bash syntax validation, ShellCheck, and git diff checks. The separate Pi stock-rendering failure reproduces locally but is unrelated environment/version drift

* no-mistakes(ci): Fixed Behavior portable serial 4 by adding fm-classify-lib.sh and fm-timeout-lib.sh to the broken-root Pi test fixture; fm-branch-outcome.sh now depends on them. Verified the full Pi branch-extension suite with real-Pi checks skipped, the wake-drain outcome-backstop suite, Bash syntax, and git diff checks. Greptile findings are already addressed at HEAD; the no-mistakes attestation failure is external head-SHA state
…id#3503)

* fix(bin): deliver typed terminal results from remote work homes

A public commitment whose work is bound to a REMOTE secondmate home could
never receive its typed terminal result. `fm-public-followup.sh brief`
printed an emit command carrying this home's own absolute path and this
checkout's own script path, neither of which exists on the machine the
worker runs on, so the worker had nothing it could write to that the
owning home would ever read - and `consume` kept finding nothing while
the promise stayed open.

The brief is now route-aware: for a remote work home it prints that
route's own code root and home with `--stage-in`, so the typed event is
staged in the home where the work actually runs, and the closing
paragraph names the owning home as the one on the other machine instead
of pointing at the path above it. The owning home collects those staged
results over the same SSH route it reaches that secondmate on, because
the transport only runs outbound: `consume` pulls them into its own
inbox and reconciles them exactly as it reconciles a local report.
Collection is non-destructive until the result is durably held, so a
dropped connection cannot lose a terminal result, and a route that could
not be reached is named in `consume`'s output with the promise left open
rather than reported as an empty inbox.

A local work home is untouched: the brief still prints `--home` with this
home and this checkout's script, and the event still lands directly in
this home's typed terminal-result inbox.

This is the emit-side counterpart of the retire/clear fix in kunchenguid#3479 and
reuses the remote-route resolution that landed with it. Reconciling a
loop bound to a remote route now reaches that route, so the existing
remote cases drive `consume` through the same faked transport their
other steps already use.

* no-mistakes(review): Fail loudly on unresolved routes and invalid staging homes

* no-mistakes(review): Fail collection when remote outbox is unreadable

* no-mistakes(review): Surface reassigned remote routes during empty collection

* no-mistakes(review): Fail remote collection on invalid registrations

* no-mistakes(review): Reject unsafe registration entries during remote collection

* no-mistakes(review): Restore healthy empty remote collection behavior

* no-mistakes(review): Skip remote collection for delivered registrations

* no-mistakes(review): Skip delivered registrations before route validation

* no-mistakes(document): Document remote follow-up collection semantics
…#3504)

* fix(bin): exclude secondmates from home-summary child inventory

kind=secondmate meta records never have backlog rows, so counting them in unowned_children or terminal_in_flight made a clean main home look invalid once earlier ledger checks passed.

* no-mistakes(review): Cover terminal secondmate in-flight exclusion

* no-mistakes(ci): Updated the stock macOS Bash CI snapshot expectation from 15 to 16 tests. Verified all 16 snapshot/fleet-view tests pass under Bash 3.2.57 and `git diff --check` succeeds
* fix(bin): self-heal status-outcome indexes on every drain

Missing ready markers were skipping the lost-wake backstop on non-Pi homes because only the Pi branch ran processed-init. Drain now rebuilds those indexes under the outcome lock and fails closed only on a real store fault.

* no-mistakes(review): Guard held-lock initialization and fail marker writes

* no-mistakes(document): Document cross-harness outcome-index self-healing
Take the complete contiguous upstream prefix requested by Firstmate.
Preserve fork divergences while adopting the upstream capabilities.
Keep upstream parentage for the next sync round.
@HelloWorldSungin
HelloWorldSungin merged commit 83f4a40 into main Sep 9, 2026
31 of 33 checks passed
@HelloWorldSungin
HelloWorldSungin deleted the fm/fm-upstream-sync-2026-09-08-round-1 branch September 9, 2026 01:40
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.

5 participants