Skip to content

Reconcile upstream 888871de (September 17, 2026) - #68

Merged
timbarreto merged 21 commits into
mainfrom
reconcile/upstream-2026-09-17-888871de
Sep 18, 2026
Merged

timbarreto merged 21 commits into
mainfrom
reconcile/upstream-2026-09-17-888871de

Conversation

@timbarreto

@timbarreto timbarreto commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

Frozen upstream reconciliation

Normal merge of 18 canonical commits, followed by a test-only verification fix and a merge of fork main after PR #69.
Use a merge commit, not squash or rebase. Merge commits are enabled; this non-draft PR stays unmerged with auto-merge off until separately approved.
All 20 automatic checks passed on the current base-update head, with one verified producer each. Known incoming limitations below are not claimed fixed.
GitHub Actions owns the complete cross-platform matrix.

Identity Full SHA
Original frozen fork 332c1dc320c689c7b096c7a0eccb290621a5195c
Actual PR target base (after #69) 6e220fcb3ad2eaf2a469ac2f4556a0544f7d4afe
Proven prior upstream 7111081cc10ad8cafcd5a8c7eef75d2b1f724026
Frozen upstream 888871de5cdf875ba4f4c0d231da6efdf7bad9a8
Final published head 460aca84d171cc64a1132fece6228910150d4456
Reviewed tree dce299f9920d553b4b08168d2e9fc8a8750af0f0

Firstmate-Upstream-SHA: 888871d

The latest valid reachable prior trailer is on bc6720ddee8931803c04c44edb1186bf670fb9c9, whose second parent is the proven prior upstream.
That object exists and is an ancestor of both frozen inputs; merged fork PR #58 records the exact head/tree/snapshot.
The matching merge base is supporting ancestry evidence, not the sole synchronization proof.
Upstream was fetched exactly once.
Reconciliation merge 7384915341171f7895a823db165e08b6c2064051 retains both frozen parents and remains reachable; no reconstruction or ancestry-only anchor was needed.
Git's trailer formatter, tree, parents, clean state, modes and unchanged 102-path manifest were verified after the base-update merge too.

All maintained work is in C:/src/firstmate2; local main still points at 332c1dc320c689c7b096c7a0eccb290621a5195c.
No other project checkout or live Firstmate home was used.
Rerere was initially unset and is now local enabled=true/autoupdate=false; global Git settings and repository policy are unchanged.
Evidence lives outside the repository under %TEMP%/firstmate2-reconcile-20260917T233944Z.

Fork-base update and fresh verification

Fork PR #69 advanced main after this PR's previous green run.
Only origin/main was fetched; canonical upstream was not advanced.
The two content conflicts, bin/fm-pr-check.sh and bin/fm-watch.sh, now compose metadata-locked publication/snapshot capture with upstream's publication lock, strict remount repair and contribution arming.
Read locks are released before lifecycle acquisition; remount recovery orders control → metadata → publication, and both snapshot attempts are protected.
Both publication locks are released before contribution or parent-channel work.
Incoming missing-terminal recovery and both sides' regressions remain intact.

All four repository gates, source-aware lint and five focused cases pass on the current committed tree.
The cases cover re-registration during publication, tamper refusal, watcher remount recovery, native privacy and missing-terminal recovery.
Every fresh command, result, duration, prerequisite, fixture-only timeout setting and limitation is recorded here.
The base-update work touched exactly its 11 incoming paths; refreshed selection is byte-identical at 205 scripts, and unchanged workflow/catalog/runner/proof bytes retain all 20 CI producers.
Documentation now checks 108 surfaces / 478 links.

PR #69 fixes the PR-poll publication race, not the capped no-mistakes rerun-selection race disclosed below; neither run-selection owner changed in this base merge.
The original local ledger is preserved: cumulative 3,849,341 ms, including 1,411,919 ms for this update, with no new timeout.
The registration fixtures explicitly left contribution observation unarmed because their restricted PATH lacks jq; contribution behavior remains CI-owned.

Original conflict and owner decisions

All 13 conflicted paths were resolved from saved base/fork/upstream stages, path history and originating PRs.
Rerere recorded reviewed resolutions with autoupdate disabled; none was accepted automatically.

Surface Resolution / primary evidence
bin/fm-bootstrap.sh, bin/fm-control-lib.sh Compose canonical kunchenguid#4692 with fork #44: typed enumeration and profile validation use the Copilot/Pi capability owners; missing adapters remain explicit failures. The no-key bootstrap baseline stays narrower, while typed activation admits upstream's additional verified harness. The new resolver retains explicit provider requirements rather than inferring a Copilot provider.
bin/fm-classify-lib.sh, bin/fm-fleet-snapshot.sh Compose kunchenguid#3753 with fork #54/#55: kind-aware ship/scout terminal closure, declaration guards, latest events and cursor v8 retain in-process destinations, the cheap candidate filter, fresh batched file facts and single-JSON row assembly. New PR-head/contribution fields use the existing batched metadata owner.
bin/fm-pr-lib.sh Compose kunchenguid#4656 with fork #42/#51/#57: strict content/device proof and publication locks retain Azure identity, phase-local batch validation and fresh file facts. Secure re-record staging before payload through the native/POSIX private-path owner. New contribution staging follows that owner too; no authorization verdict is cached.
bin/fm-spawn.sh The complete upstream semantic delta is kunchenguid#4689's Codex worker/scout --disable hooks flag and rationale. Apply it to the fork template without restoring inline pilots, changing signed Pi, manufacturing hook trust or disabling primary/secondmate hooks.
bin/fm-test-run.sh Every upstream delta is metadata. Move registrations, two serial hints and routes to the catalogs (#40); runner algorithms and independent proof admission remain fork-exact. Explicit Grok/capture/Python-fixture mappings preserve unknown-source refusal.
Bootstrap/GOTMP tests Preserve the fork's native jq normalization, pilot/private-path fixture closure and upstream .env/secret probes. Explicit legacy modes keep no-key expectations separate from typed activation.
Inactive-reconcile/dispatch-profile/PR-security tests Keep every fork case and named registry, add every upstream case, retain Azure/Windows coverage, and adapt native remount privacy and combined-stat fault injection without weakening negatives.
Pi primary-types fixture Preserve fork #43's repository-shaped process/declaration fixture and add the physical Claude-owned preservation helper reached by Pi's new symlink (kunchenguid#4788).

Unconflicted intent is retained at its real owner: task-owned contribution freshness/failure episodes/terminal settlement (kunchenguid#4627/kunchenguid#4661/kunchenguid#4710); structured remote document offers and documented legacy/retry limits (kunchenguid#4658); pending-reply retirement (kunchenguid#4680); composite Orca identity (kunchenguid#4677); run selection (kunchenguid#4476); Claude foreign-owner Stop through native identity (kunchenguid#4777/kunchenguid#4783); Bash empty-array repair (kunchenguid#4778); shared Calm text preservation (kunchenguid#4655/kunchenguid#4788); and complete final responses (kunchenguid#4738/kunchenguid#4779).
The contribution observer remains GitHub-only; unsupported forges stay unmeasured there, while Azure completion/retirement remains intact.
Maintained prose was reviewed for audience, owner, anchors and safety facts; the initial documentation gate reported 108 surfaces / 477 links.

Earlier local evidence and limits (through f1640f0)

This section preserves the pre-base-update history; fresh current-head evidence is linked above.

PR readiness is not merge readiness. GitHub Actions owns the complete cross-platform matrix.
The initial 2,400-second window charged 1,337,275 ms and hit two timeouts.
The maintainer explicitly authorized ignoring token and other aggregate budgets; cumulative accounting was retained, not reset.
At that prior head, the local ledger charged 2,437,422 ms, with the same two initial timeouts and 14 subsequent successful focused behavior invocations.
Individual commands remained cancellable; runtime deadlines, live-test gates, frozen inputs, repository scope and no-merge authority were not changed.

  • All four repository gates passed on that prior reviewed tree, including the final fixture changes. Source-aware lint also passes for the composed implementation roots and both follow-up test files.
  • Initial inventory failed on unmapped GROK_BOT.md; explicit catalog routes and executable routing coverage fix it. Final selection is unchanged at 205 scripts. Coverage passes: 239 = 24 parallel + 199 serial + 16 Herdr, five serial shards, 20 unhinted serial scripts, zero missing parallel hints.
  • Initial lint SC2030/SC2031 on dynamic contribution destinations was fixed by explicit initialization, without exclusions. The first published head then passed 19 of 20 CI checks: full-source lint alone found SC2034 on the new private fixture's home/state. Exporting that isolated context fixes it; the exact source-aware roots and native privacy case pass again locally. That prior head received all 20 automatic checks successfully before main advanced.
  • Initial classifier/startup suite invocations timed out at 180/240 seconds after 15/17 successful assertions; those attempts remain timeouts. Their unchanged production cases pass when isolated: long-history closure 60,585 ms, kind-aware transition cost 41,039 ms, snapshot invocation count/freshness 100,067 ms. All five remaining classifier cases pass, and the supported case registry preserves all 20 cases in original order. This supports cumulative local suite overhead, not an assertion regression; no frozen-upstream differential or baseline-failure claim was necessary.
  • Full pilot/typed-dispatch contracts, native private re-recording and tamper refusal, both Codex launch roles, new-owner routing, PR parsing/observation freshness and source-aware lint pass. tsc remains absent locally; strict types are CI-owned (portable parallel 1 / Harness package compatibility, both successful on the first head, also successful on that prior head). Preflight and partial output are never credited as suite passes.
  • Cache disabled; no dependency install, live runtime/vendor prompt, global Git policy change or production timeout increase. Scoped MSYS/native inspection found no remaining timed-suite/validator process. No baseline/synthetic repository worktree was created.
  • Existing live/capability gates remain. CI does not promise installed/credentialed Claude or Codex for every guard; absent capable vendor coverage remains an explicit gap.

Known incoming limitation: canonical #4476 retains a capped-overview rerun race that can report an older cancellation while its replacement becomes live, plus up to three sequential bounded status calls.
Upstream rates the race high risk and does not claim fresh live no-mistakes validation.
This snapshot does not fix it; portable parallel 2 owns deterministic selection coverage, not proof that the race is gone.

Verification surface and retained boundaries

Shared paths were compared with frozen upstream; fork-only owners with frozen fork.
Runner, catalog loader, independent proof owner, pilot/native/process/path implementations, timeout library and pinned remote doctor retain fork bytes.
New test registration grants no concurrency; existing hints/weights/caps remain, with only two incoming serial hints added.
Shared CI adds upstream's stock-Bash churn case; Fork CI adds native private re-recording to the existing PR-completion job.
All triggers, permissions, matrix members, pins, deadlines and artifact dependencies remain; 20 automatic producers are expected and the Windows Herdr experiment stays manual.

Pins/prerequisites: ShellCheck 0.11.0, actionlint 1.7.12; checkout v6, setup-node v7, upload v7/download v8; tasks-axi 0.2.5; portable Pi/TypeScript 5.9.3 with required typecheck prerequisites, full history, tmux and C compiler where used.
Herdr retains 0.7.4/protocol >=16, Treehouse 2.0.1, Node 24/Pi 0.84.3, isolated labs, default-server tripwire, 20-minute family bound, always-run cleanup and timing artifacts feeding the always-run aggregate.
macOS retains Bash 3.2.57, 19 snapshot/59 Bearings cases, startup/busy/path/recovery/public-followup and new churn coverage.
Windows retains core/launch/rollback/Azure/management contracts with FM_LIVE=0; PR completion keeps its 600-second main case and adds remount at 180 seconds.
Package compatibility retains Node 24, Pi 0.84.3, OpenCode 1.18.23 and TypeScript 5.9.3 without vendor credentials.

Retained patches follow docs/fork/architecture.md removal conditions: pilot calls/errors need equivalent upstream capabilities; native/process/path wrappers need equivalent identity/privacy/transport and lifecycle bounds; Azure consumers need equivalent canonical identity/freshness/replay/cleanup; startup/reporting/management needs output, freshness, safety and comparable Windows cost proof; catalogs need equivalent loading/routing with independent admission; fixtures/lint need complete dependency closure; workflows need every unique producer/gate/pin/artifact; signed-Pi/remote-doctor exceptions need separately reviewed migration/integrity work; guidance needs equivalent anchors and safety ownership.
No reduction in apparent divergence is treated as behavior or cost proof.

Earlier exact local checks (through f1640f0)

The following 36 outcomes are historical, not substituted for the fresh base-update checks linked above.

All commands used the recorded Git-for-Windows Bash, FM_LIVE=0, serial selected behavior execution and cache=false.
No interrupted, failed, skipped, preflight-only or prior-head result is reused as a pass.
Observed: Bash 5.3.15, Git 2.55.0.windows.5, Node 24.19.0, jq 1.8.2, Perl 5.42.3, Python 3.13.15, PowerShell 5.1.26100.9444, ShellCheck 0.11.0 and actionlint 1.7.12.

Exact command notation (not a new runner):

B = C:/Program Files/Git/usr/bin/bash.exe
T(subject, case) = FM_TEST_ONLY=<case> "$B" bin/fm-test-run.sh --jobs 1 tests/<subject>.test.sh
T(subject, FULL) omits FM_TEST_ONLY; LIST adds FM_TEST_LIST_CASES=1 (listing only, not behavior).
T uses FM_TEST_BASE_PATH=/mingw64/bin:/usr/bin:/bin:/usr/sbin:/sbin.
L(paths) = "$B" bin/fm-lint.sh <paths>; L(default) has no path arguments.
D = "$B" bin/fm-doc-audience-check.sh
C = "$B" bin/fm-test-run.sh --check-coverage
Invocation Command Outcome ms
02-gates I failed 21614
02-gates S passed 21479
02-gates L(default) failed 90152
02-gates D passed 5192
02-gates C passed 151883
03-refresh I passed 167618
03-refresh S passed 28083
03-refresh L(default) passed 137295
03-refresh C passed 215515
05-focused T(fm-classify-decision-key, FULL) timeout 183598
05-focused T(fm-startup-performance, FULL) timeout 242936
05-focused T(fm-harness-contract, FULL) deferred: timeout circuit breaker not run
05-focused T(fm-pr-check-security, test_device_rerecord_preserves_private_policy) deferred: timeout circuit breaker not run
05-focused T(fm-pi-primary-types, FULL) deferred: timeout circuit breaker not run
07-continuation LIST T(fm-classify-decision-key, FULL) passed 30120
07-continuation T(fm-classify-decision-key, test_closing_verb_filters_unrelated_history_without_subshell_growth) passed 60585
07-continuation T(fm-startup-performance, test_transition_history_stays_in_process_and_keeps_open_keys) passed 41039
07-continuation T(fm-startup-performance, test_snapshot_projection_bounds_json_tool_launches) passed 100067
07-continuation T(fm-harness-contract, FULL) passed 123711
07-continuation T(fm-pr-check-security, test_device_rerecord_preserves_private_policy) passed 80790
08-launch-routing-lint T(fm-spawn-dispatch-profile, test_codex_crewmate_launch_disables_the_hook_layer) passed 64310
08-launch-routing-lint T(fm-spawn-dispatch-profile, test_codex_secondmate_launch_keeps_the_hook_layer) passed 48996
08-launch-routing-lint T(fm-test-run, test_reconciled_modules_select_their_consumers) passed 84953
08-launch-routing-lint T(fm-pr-local-cost, FULL) passed 15925
08-launch-routing-lint L(bin/fm-bootstrap.sh bin/fm-classify-lib.sh bin/fm-control-lib.sh bin/fm-fleet-snapshot.sh bin/fm-pr-lib.sh bin/fm-dispatch-resolve.sh bin/fm-contributions.sh tests/fm-pi-primary-types.test.sh tests/fm-bootstrap.test.sh) passed 58856
09-classifier T(fm-classify-decision-key, test_closing_verb_honors_overridden_transition_verbs) passed 11585
09-classifier T(fm-classify-decision-key, test_closing_verb_filter_preserves_terminal_chronology) passed 14886
09-classifier T(fm-classify-decision-key, test_bare_prose_cannot_impersonate_a_terminal_declaration) passed 29464
09-classifier T(fm-classify-decision-key, test_bare_prose_cannot_open_or_close_a_decision) passed 16430
10-final L(tests/fm-pr-check-security.test.sh tests/fm-classify-decision-key.test.sh) passed 8516
10-final S passed 7460
10-final L(default) passed 68088
10-final D passed 2285
10-final C passed 112176
10-final I-final passed 20795
10-final T(fm-pr-check-security, test_device_rerecord_preserves_private_policy) passed 49923

Preflight-only runs: 19,857 ms and 16,886 ms, exit 75; they executed probes only, not the planned gates/tests.
The second proved tsc absent; no dependency was installed and the subsequent package prerequisite/check was not credited.
The initial two timeouts are retained above; no frozen-upstream differential was needed after the representative cases passed unchanged.

S:

set -e
inventory=$(bin/fm-lint.sh --list-files)
while IFS= read -r script; do
  [ -z "$script" ] || /bin/bash -n "$script" || exit
done <<< "$inventory"

I is inspection only:

# Read-only routing inventory of the resolved firstmate2 tree; no suites execute.
set -euo pipefail
out=$EVIDENCE/inventory
mkdir -p "$out"
bin/fm-test-run.sh --list --changed --base 332c1dc320c689c7b096c7a0eccb290621a5195c | tee "$out/changed.txt"
bin/fm-test-run.sh --list-lanes | tee "$out/lanes.txt"
for lane in portable-parallel-1 portable-parallel-2 portable-serial-1of5 portable-serial-2of5 portable-serial-3of5 portable-serial-4of5 portable-serial-5of5 real-herdr-gated; do
  bin/fm-test-run.sh --list --lane "$lane" > "$out/$lane.txt"
done
bin/fm-test-isolation-proof.sh --list > "$out/proven-parallel.txt"
bin/fm-test-isolation-proof.sh --list-family-admissions > "$out/family-admissions.tsv"
printf 'FM_RECONCILE_INVENTORY_COUNT %s\n' "$(wc -l < "$out/changed.txt")"

I-final repeats bin/fm-test-run.sh --list --changed --base 332c1dc320c689c7b096c7a0eccb290621a5195c into inventory/changed-final.txt, requires byte identity with the original selection via cmp, and prints its 205-line count with wc -l.
The lane/catalog/runner inputs are unchanged by the two-file follow-up.

Prerequisite commands

Successful probes establish capability, not test passes.
Signing/hooks/safe.bareRepository were inspected without host changes; fixture Git isolation remains with the existing helper.
All actual per-invocation probe logs and environment/context digests are retained.

"C:/Program Files/Git/usr/bin/bash.exe" "--version"
"git" "--version"
"C:/Program Files/Git/usr/bin/bash.exe" "-c" "set -e; for tool in awk grep sort find xargs perl stat realpath mktemp cmp tail head tr wc cut date; do command -v \"$tool\"; done; perl -e 'print qq($^V\\n)'"
"C:/Program Files/Git/usr/bin/bash.exe" "-c" "for key in commit.gpgsign core.hooksPath safe.bareRepository; do printf \"%s=\" \"$key\"; git config --show-origin --get \"$key\" || test \"$?\" = 1 || exit; done"
"shellcheck" "--version"
"actionlint" "--version"
"python3" "--version"
"C:/Program Files/Git/usr/bin/bash.exe" "-c" "set -e; printf \"Bash %s\\n\" \"$BASH_VERSION\"; git --version; jq --version; perl -e 'print qq($^V\\n)'; for tool in awk grep sort find xargs stat realpath mktemp cmp tail head cut wc; do command -v \"$tool\" >/dev/null; done"
"node" "--version"
"powershell.exe" "-NoProfile" "-NonInteractive" "-Command" "$PSVersionTable.PSVersion.ToString()"
"tsc" "--version"
"C:/Program Files/Git/usr/bin/bash.exe" "-c" "set -e; node --version; command -v npm; test -f /c/.tools/.npm-global/node_modules/@earendil-works/pi-coding-agent/package.json"

No-renames divergence and locality

Comparison Modified Added Deleted Paths + -
prior-upstream-to-frozen-fork 181 69 2 252 23952 4968
frozen-upstream-to-base-before 213 69 23 305 24980 12060
frozen-upstream-to-head-after 184 69 2 255 24641 5104
actual-base-to-head 81 21 0 102 7327 710

50 incoming files are upstream-exact in bytes/mode: 31 existing paths and 19 additions.
The other 45 incoming paths compose intentional fork behavior or catalog/fixture integration.
All 21 branch additions originate upstream; resolver pilot integration and contribution staging's native privacy make two non-equivalent.
Fork-only additive paths remain 69 and intentional deletions remain two; renames are disabled.
Calm preservation is physically Claude-owned with a Pi symlink, and environment parsing moves to its shared upstream owner; relocation is not vanished behavior.
Before/after inventories, moved implementation, retained caller hunks and owner/removal conditions are archived for the actual base and head above.

The final path-manifest SHA-256 remains b53808985415e2f0617ae45739e26216923712f56d90df97d1ae48746f5f8cd2: exactly 102 paths, with no existing-mode change or broad line-ending renormalization.
The source manifest had 95 paths; the runner returns to fork bytes and eight explicit integration paths yield the final 102.

git diff --no-renames --name-status 888871de5cdf875ba4f4c0d231da6efdf7bad9a8 6e220fcb3ad2eaf2a469ac2f4556a0544f7d4afe
git diff --no-renames --name-status 888871de5cdf875ba4f4c0d231da6efdf7bad9a8 460aca84d171cc64a1132fece6228910150d4456
git diff --no-renames --numstat 6e220fcb3ad2eaf2a469ac2f4556a0544f7d4afe 460aca84d171cc64a1132fece6228910150d4456

Expected automatic CI producers

Check Workflow / job Matrix Runner Minutes
Lint CI / lint - ubuntu-latest 25
Test coverage guard CI / test-coverage - ubuntu-latest 5
Behavior portable parallel 1 CI / tests-portable-parallel-1 - ubuntu-latest 10
Behavior portable parallel 2 CI / tests-portable-parallel-2 - ubuntu-latest 10
Behavior portable serial 1 CI / tests-portable-serial shard=1 ubuntu-latest 30
Behavior portable serial 2 CI / tests-portable-serial shard=2 ubuntu-latest 30
Behavior portable serial 3 CI / tests-portable-serial shard=3 ubuntu-latest 30
Behavior portable serial 4 CI / tests-portable-serial shard=4 ubuntu-latest 30
Behavior portable serial 5 CI / tests-portable-serial shard=5 ubuntu-latest 30
Behavior tests (Herdr) CI / tests-herdr - ubuntu-latest 75
Behavior timing aggregate CI / tests-timing-aggregate - ubuntu-latest 5
Stock macOS Bash snapshot compatibility CI / macos-stock-bash - macos-latest 10
Repo invariants CI / invariants - ubuntu-latest 5
Windows self-update entry point Fork CI / windows-update - windows-latest 5
Windows reconciliation (core) Fork CI / reconciliation-windows subject=core windows-latest 10
Windows reconciliation (copilot-launch) Fork CI / reconciliation-windows subject=copilot-launch windows-latest 10
Windows reconciliation (legacy-rollback) Fork CI / reconciliation-windows subject=legacy-rollback windows-latest 10
Windows reconciliation (pr-completion) Fork CI / reconciliation-windows subject=pr-completion windows-latest 15
Windows Copilot management Fork CI / windows-management - windows-latest 15
Harness package compatibility Fork CI / harness-package-compatibility - ubuntu-latest 10

The manual-only Windows Herdr automation spike (workflow_dispatch, measure, windows-latest, 20 minutes, unpinned official preview installer plus jq) was not dispatched.
Skipped/cancelled required lanes, missing or duplicate producers, unresolved regressions and missing native coverage are not passes.
PR creation used gh-axi after its live help; the initial oversized-body client error created nothing, and the compact retry created this PR.
For the completed failed Lint job only, the installed underlying gh api retrieved the complete log after gh-axi refused in-progress-workflow logs and truncated the direct job response; no dependency/auth change was made.
History, PR mutations, mergeability and check status otherwise remain through gh-axi.

Exact-head status

At 2026-09-18T04:22:40.544574+00:00: 20 successful, 0 pending, 0 failed, 0 absent; duplicate/unexpected producers: 0.

Complete changed-script routing

Each entry expands to tests/<name>.test.sh with the named existing primary Linux producer.
Untagged subjects are CI-only for the current context; earlier local outcomes remain historical above.
Native/macOS/package contracts retain their additional producers, and live subjects retain their capability gates.
The 205-script inventory was never a local full-suite execution plan.

All selected scripts and current local disposition

Behavior tests (Herdr) (16)

fm-afk-inject-herdr-e2e
fm-afk-launch
fm-backend-autodetect-smoke
fm-backend-herdr-agent-exit-shell-e2e
fm-backend-herdr-eventwait-smoke
fm-backend-herdr-focus-flash-e2e
fm-backend-herdr-launcher-workspace-e2e
fm-backend-herdr-presentation-e2e
fm-backend-herdr-prune-safety-e2e
fm-backend-herdr-respawn-idem-e2e
fm-backend-herdr-smoke
fm-backend-herdr-stale-active-tab-e2e
fm-backend-herdr-workspace-per-home-e2e
fm-control-herdr-smoke
fm-herdr-attached-viewer-live-e2e
fm-herdr-session-cleanup-e2e

Behavior portable serial 5 (33)

fm-afk-pi-herdr-return-e2e
fm-backend-tmux-smoke
fm-backend
fm-backlog-handoff
fm-bearings-board-lavish-live-e2e
fm-bootstrap
fm-claude-stop-autoarm-live-e2e
fm-claude-stop-autoarm
fm-codex-hook-layer-live-e2e
fm-gate-refuse
fm-gotmp
fm-harness-liveness-drift-live-e2e
fm-harness-precedence
fm-herdr-pi-stale-registration-live-e2e
fm-herdr-submit-confirm-live-e2e
fm-home-summary-refresh
fm-kimi-harness
fm-lint-inventory
fm-mail
fm-opencode-primary-live-e2e
fm-pi-primary-live-e2e
fm-pr-local-cost
fm-pr-state-live-e2e
fm-reconcile-validation
fm-remote-job-wait
fm-secondmate-harness
fm-secondmate-lifecycle-e2e
fm-send-inbox
fm-session-start
fm-test-isolation-proof
fm-trace-context-spawn
fm-turnend-guard
fm-watcher-lock

Behavior portable serial 2 (36)

fm-agy-harness
fm-backend-herdr-treehouse
fm-bearings-board-render
fm-calm-claude-mod-live-e2e
fm-composer-codex-idle-live-e2e
fm-control-relaunch
fm-copilot-harness
fm-cursor-primary-live-e2e
fm-dispatch-resolve
fm-fleet-sync
fm-grok-continuity-live-e2e
fm-guard-stale-banner
fm-home-summary-request
fm-lint-workflows
fm-lock-fast
fm-muse-signals-live-e2e
fm-omp-harness
fm-omp-primary-live-e2e
fm-operational-input
fm-pi-windows-shell-invocation
fm-pr-state
fm-remote-job
fm-remote-secondmate-lifecycle-e2e
fm-remote-transport-lanes
fm-secondmate-reconcile
fm-send-secondmate-marker
fm-session-lock-ancestry
fm-sessionstart-nudge
fm-startup-memory-budget
fm-subagent-pretool-check
fm-tool-update-check
fm-turnend-foreign-owner-arm-fix
fm-update
fm-vendor-auth-probe
fm-wake-daemon-lifecycle-e2e
fm-wake-drain-open-decisions-cursor

Behavior portable serial 4 (33)

fm-agy-signals-live-e2e
fm-ask-user-authority
fm-backlog-atomicity
fm-backlog-read-bound
fm-calm-pi-extension
fm-check-unregister
fm-claude-session-lock-live-e2e
fm-cmux-claude-composer-live-e2e
fm-control-recovery [current focused pass]
fm-control
fm-copilot-primary-live-e2e
fm-cursor-primary
fm-documentation-audiences
fm-grok-stop-live-e2e
fm-harness-adapter-instructions-live-e2e
fm-harness-contract
fm-on
fm-pi-branch-extension
fm-platform-process
fm-pr-check-security [current focused pass]
fm-pr-reviewers
fm-procevent-quota
fm-remote-herdr-guard
fm-remote-job-orphan-reap
fm-secondmate-sync
fm-send-agy-confirm
fm-send-inbox-doorbell-live-e2e
fm-spawn-dispatch-profile
fm-tangle-guard
fm-task-delivery
fm-task-inbox
fm-watch-arm
fm-watch-recovery-loop

Behavior portable parallel 2 (13)

fm-arm-pretool-check
fm-backend-herdr
fm-captain-hold-lifecycle
fm-crew-state
fm-ensure-agents-md
fm-herdr-lab
fm-send-popup-settle
fm-send-settle
fm-send-strict
fm-spawn-batch
fm-supervision-instructions
fm-transition-lib
fm-x-mode

Behavior portable serial 1 (25)

fm-backend-orca
fm-calm-claude-mod
fm-claude-trust
fm-codex-continuity-live-e2e
fm-copilot-hooks-live-e2e
fm-copilot-management-live-e2e
fm-fleet-snapshot-view
fm-herdr-unregistered-agent
fm-herdr-version-floor-live-e2e
fm-mail-check
fm-pi-branch-responsiveness-live-e2e
fm-pi-codex-native
fm-private-path
fm-quota-choose
fm-remote-backlog-handoff
fm-remote-reply
fm-secondmate-safety
fm-send-resolve-key
fm-send-secondmate-marker-herdr-e2e
fm-startup-network
fm-stow-cascade
fm-test-catalog
fm-update-windows
fm-wake-drain-unread-status
fm-watch-triage

Behavior portable serial 3 (38)

fm-bearings-board
fm-bearings-snapshot
fm-bootstrap-network-parallel
fm-calm-claude-mod-plugin
fm-ci-workflow
fm-classify-decision-key
fm-composer-matrix-live-e2e
fm-contributions
fm-cursor-harness
fm-daemon
fm-gemini-harness
fm-harness-adapter-references
fm-herdr-session-cleanup
fm-inactive-reconcile
fm-muse-harness
fm-path
fm-pi-branch-live-e2e
fm-pi-watch-extension
fm-quota-array-dispatch-live-e2e
fm-remote-doctor
fm-remote-secondmate-trace-context
fm-rovo-harness
fm-rovo-signals-live-e2e
fm-secondmate-liveness
fm-secondmate-restart
fm-sessionstart-hook-live-e2e
fm-sessionstart-instruction-refresh-live-e2e
fm-shared-captain-inheritance
fm-spawn-worktree-settle
fm-startup-performance
fm-supervision-events
fm-tasks-axi
fm-teardown-endpoint-safety
fm-teardown
fm-tmux-agent-liveness
fm-trace-context-lib
fm-wake-queue
fm-watch-checkpoint

Behavior portable parallel 1 (11)

fm-brief
fm-cd-pretool-check
fm-composer-ghost
fm-composer-lib
fm-grok-harness
fm-lint
fm-pi-primary-types
fm-pr-merge
fm-review-diff
fm-test-run
fm-tmux-submit-busy

mremond and others added 20 commits September 16, 2026 07:43
kunchenguid#4627)

* fix: restore published contribution follow-up (Fixes kunchenguid#4469)

* fix(review): Fix contribution freshness and merge actor routing

* fix(review): Restore issue triage and scope contribution follow-up

* fix(test): test: assert one wake per contribution signal

* fix(document): Document contribution follow-up

* fix: restore truthful terminal delivery evidence

* fix(review): Disclose unsupported contributions and deduplicate watcher wakes

* fix(review): Preserve unmeasured unsupported contributions across Bearings

* fix(review): Deduplicate shared contribution wakes and isolate diagnostics

* fix(ci): Captain, fixed the CI failure by updating the PR-security fake GitHub interface to support the contribution observer’s API reads. Verified with shellcheck, git diff --check, the full contribution suite, and a focused merged-poll retirement reproduction. The full PR-security script was not allowed to complete locally after its expanded observer path made it substantially slower
…nguid#4658)

* fix(bin): make a remote-reply document gap self-clearing and re-attemptable

A remote mate's undelivered document raised a keyed `blocked` decision that
nothing could ever resolve, and any `data/*.md` substring in any mirrored line
was an unconditional fetch instruction. A mate announcing a report it had not
written yet therefore manufactured a permanent, factually false blocker, and
its own explanation of the false alarm manufactured more.

The reader has no permanence vocabulary: a report still being written refuses
exactly like a path that will never exist. So an undelivered document is now a
durable, re-attemptable obligation under `state/remote-replies/<id>.pending-docs`,
re-attempted on the next delta and on the channel's own quiet poll, and retired
with a matching `resolved` line naming the local copy once it arrives. The
cursor still advances and no delta stalls on one bad pointer.

Only a structured `report=data/....md` pointer now offers a document, so a path
merely mentioned in prose - including one under another home's mirror tree,
which is provably not that mate's to serve - is never fetched. Offers are
deduplicated across the whole delta, the escalation names each missing document
once and carries the reader's own reason instead of discarding it, and a
strictly increasing notice ordinal keeps a later escalation from being
swallowed as duplicate bytes. A mirrored line still lands once whichever
pointer form it was first written under.

* no-mistakes(review): Require structured pointer token boundaries

* no-mistakes(review): Unify boundary-safe pointer extraction and rewriting

* fix(bin): identify a mirrored line independently of its delivery state

Two defects in the boundary-safe pointer work.

The at-most-once check compared only the all-remote and all-local renderings
of a line, so it could not recognize a mixed one. A line offering two documents
where only the first was deliverable mirrored as local-plus-remote; once the
second arrived, a cursor-loss whole-log recapture rendered the same line
all-local, matched neither alternate, and mirrored a second time. A line's
identity is now the canonical form every boundary-valid pointer would take once
delivered, derived by the same parser that does extraction and rewriting, so it
no longer depends on which documents happened to be deliverable at the time.

The pointer map was passed to awk through the process environment. A delta may
carry up to the configured 1 MiB bound, and an expanded map of delivered
pointers can exceed the platform's exec argument limit, so awk would fail to
start; because no caller checked, the empty result would have been appended as
blank lines while the cursor advanced past dropped status content. The map now
travels in a file, and every call site checks the exit status and stops the
ingest rather than committing a delta it could not render.

Both passes now run once per stream instead of twice per line.

* no-mistakes(review): Abort ingest when document pointer extraction fails

* no-mistakes(review): Exclude structured cross-home pointers from document transfer

* fix(bin): fail open on an undeliverable remote document instead of tracking it

Narrow the remote-reply document fix to the scope the diagnosis actually
requires, as decided after measuring a simpler alternative.

A document the reader cannot deliver now fails open. The mate's line is
mirrored with its own pointer, the cursor advances, and one unkeyed note
carries the reader's reason. A note never enters the open-decision fold, so it
cannot stand open the way the original keyed block did - which removes the
never-clearing false blocker by construction rather than by resolving it.

That makes the durable self-clearing obligation unnecessary, so it goes: the
per-mate pending-documents record, its notice ordinal and resolved
announcements, and the poll-side retry. Canonical line identity goes too, and
with it a way to silently drop a genuine status line; mirroring is back to
at-most-once on exact bytes. The cross-home exclusion goes as well: under
fail-open a cross-home report= either fails harmlessly or is a nested remote
report this mate genuinely holds, which is now relayed again.

Kept: fetching only on a structured report= pointer, the boundary-correct
parser, the file-based rewrite map, and checked extraction and rewrite exit
status. The parser now scans behind a sentinel byte so a rejected candidate can
no longer give the text right after it a false leading boundary.

The reported incident is covered end to end: a report path announced in prose
before it exists raises no decision, and the report still arrives through the
ledger publisher's structured offer once written.

* no-mistakes(review): Preserve source-line identity across remote reply replays

* no-mistakes(document): Document remote reply transfer and replay semantics

* no-mistakes(lint): Fix staging truncation lint checks
* Preserve substantive Calm mid-turn text

* no-mistakes(review): Distinguish newline-preserved replies from short narration

* no-mistakes(document): Document Calm mid-turn preservation boundaries

* no-mistakes(ci): Fixed the flaky contribution watcher test by increasing its bounded checkpoint from 5 to 15 seconds, allowing diagnostics to surface under slower CI load. Verified with `bash tests/fm-contributions.test.sh` and `git diff --check`
…#4656)

* fix(bin): re-record PR poll identity after a volume device renumber (Fixes kunchenguid#4260)

A volume remount can renumber the state filesystem's st_dev while every
inode and byte stays the same; APFS does this across a reboot. A poll
registration records its sidecar and check as device:inode, so every poll
armed before the remount failed strict validation and the watcher refused
all of them as unauthenticated state checks until each was re-armed by hand.

There are two device comparisons. fm_pr_private_file_valid compares a live
file's device with the state directory's device read in the same invocation:
it refuses a file that is not on the state directory's own filesystem and
already survives a renumber, so it is unchanged. The registration's recorded
identity versus the live identity (from kunchenguid#556, reused by the kunchenguid#932 retirement
receipt) binds the registration to the exact files published in its own
transaction; its device part is what breaks.

When strict capture fails, the watcher now proves the device is the only
difference: every other artifact check passes (template bytes, both hashes,
private mode, single link, live device, metadata), both recorded identities
name one device, and each recorded inode equals its live inode. Only then,
under the task's control lock, does it rewrite the two identity lines,
repeating the whole proof and comparing the registration's file identity and
bytes just before the rename, and then capture strictly again. A swapped,
altered, re-moded, relinked, split-device, or foreign-device artifact still
fails a proof and is still refused, and a pending retirement receipt blocks
the rewrite.

Reproduction: on macOS a poll armed on an APFS disk image that was detached
and re-attached behind another image moved st_dev 16777239 -> 16777243 with
inodes, bytes, mode, and link count unchanged; the real watcher refused it on
main and reports its merge with this change. The portable regression test
rewrites a real registration's recorded device and drives the watcher.

Not changed here: the status presentation cursor keys rows by its own
device:inode identity in bin/fm-classify-lib.sh, a different helper that
needs its own fix; a retirement receipt left by a reboot between its
publication and removal still names the old device and stays refused; custom
check trust binds only a content hash and is unaffected.

* fix(review): Serialize PR poll publication writers

* fix(review): Bound PR poll publication lock scope
…llow-up to kunchenguid#4627) (kunchenguid#4661)

A budget that expires partway through an observation no longer records an
error or prints the unavailable wake; the URL keeps its prior record and is
observed first next poll. forge() flags budget exhaustion at the point it
refuses, or when a read is killed at the budget's own deadline, so a genuine
forge failure still records the error and wakes. Each distinct URL is now
observed once per poll and applied to every owning task.
…kunchenguid#4680)

* fix(bin): clear parent pending-replies on local secondmate retirement

Local secondmate teardown left resolved parent pending-reply records behind
after home removal (seen after papa-hdds / pxmx retirement). Refuse non-forced
retirement while any reply for that id is still unresolved, and delete every
matching record plus its delivery confirmation after a successful local or
remote retirement, matching the remote cleanup path.

* no-mistakes(document): Align secondmate retirement docs with pending-reply cleanup

* no-mistakes(review): Lokale Pending-replies-Sicherheitsprüfung vor Home-Entfernung

* no-mistakes(review): Pending-replies-corr_id auf 16-Hex absichern

* no-mistakes(review): Pending-replies Basename und corr_id abgleichen

* no-mistakes(document): Clarify forced retirement pending-reply cleanup

---------

Co-authored-by: ladwein <ladwein@firstmate.bost8.thelad.loc>
kunchenguid#4677)

* fix(bin): accept Orca's composite worktree id at teardown

Teardown refused every Orca-backed task because the endpoint validator
checked orca_worktree_id with the simple-atom rule meant for tmux-style
window names, which rejects any character outside [A-Za-z0-9._@%+-]. Orca
returns that id as `<orca id>::<absolute worktree path>`, so the colon and
slashes in every real value made validation fail and finished Orca tasks
could never be cleaned up.

Validate the field as the composite it is: both halves of the first `::`
split present, the path half absolute, and no embedded newline, carriage
return, or tab. The terminal field keeps the atom check, which is correct
for it, and no other backend's validation changes.

The existing Orca fixtures recorded ids like `wt-teardown`, a shape Orca
never returns, which is why the suite passed a check the real value fails.
They now carry the composite form, so the tests exercise the real value.

* no-mistakes(document): name Orca's repo id in the composite worktree id

* no-mistakes(document): list teardown endpoint safety suite in Orca regression entry points
* feat(bin): add opt-in typed dispatch resolution through typesafe.ai

Add bin/fm-dispatch-resolve.sh, which resolves one concrete crewmate or
scout profile from a written brief with typesafe.ai's System One model:
one Choice question over the rules' `when` texts, then the confidence
floor, the rule's `approval` and `floor`, each profile's `provider` and
`floor`, one quota-axi snapshot, and the spendPriority argmax all in code.
It is off unless TYPESAFE_API_KEY is in the environment or the home's
gitignored .env; off means one stderr line, exit 0, and no network call,
so firstmate dispatches exactly as before. The key reaches curl on a file
descriptor, never argv.

Extract fmx_env_get into bin/fm-env-lib.sh as the one .env accessor and
the harness-to-provider table into bin/fm-quota-axi-lib.sh so the new
tool and bin/fm-quota-choose.sh share one owner each. Bootstrap validates
the four new optional dispatch fields. Document the schema, the operator
contract, the AGENTS.md intake step, and the live and benchmark evidence.

* no-mistakes(review): Harden typed dispatch resolution and quota bounds

* no-mistakes(review): Validate dispatch floors and ranking evidence

* no-mistakes(review): Tighten dispatch response and floor evidence

* no-mistakes(review): Neutralize none matching and resolve defaults locally

* no-mistakes(review): Preserve providerless profiles outside typed resolution

* no-mistakes(review): Validate response usage and reject duplicate profiles

* no-mistakes(review): Escalate unverifiable floors and validate probabilities

* no-mistakes(review): Validate probability mass and unknown profile floors

* no-mistakes(review): Simplify resolver interface and preserve fallback routing

* no-mistakes(review): Fix constants and rank partial quota evidence

* no-mistakes(review): Add authoritative provider mapping and enforce explicit providers

* no-mistakes(review): Declare provider for documented Pi profile

* no-mistakes(review): Validate provider identifiers and support Gemini dispatch

* no-mistakes(review): Strictly anchor provider identifiers

* no-mistakes(review): Validate selectors and preserve fallback candidate evidence

* no-mistakes(review): Gate typed validation and harden resolver evidence

* no-mistakes(review): Preserve opt-in routing and harden candidate evidence

* no-mistakes(review): Prioritize known exhaustion over quota uncertainty

* no-mistakes(review): Isolate API secrets and preserve no-key diagnostics

* no-mistakes(review): Fallback safely when dispatch rules are absent

* no-mistakes(review): Prioritize quota vetoes and isolate bootstrap secrets

* no-mistakes(document): Document typed dispatch safety and fallback behavior
…n decisions aren't lost (kunchenguid#3753)

* test: reproduce buried status declarations in shared readers

* fix: share status event reads and preserve open blockers

* fix: retain terminal scout and ship status declarations

* no-mistakes(review): Fix status chronology, legacy completions, and reader performance

* no-mistakes(review): Share terminal decision reconciliation across fleet snapshots

* no-mistakes(review): Unify terminal supersession across cached folds and consumers

* no-mistakes(review): Filter per-key status history while preserving terminal chronology

* no-mistakes(test): Preserve parent lock ownership in Bash 3.2 subshells

* no-mistakes(review): Anchor legacy status tokens so prose cannot hide pauses

* no-mistakes(document): Document latest-event status read and kind-scoped fold cursor

* no-mistakes(lint): Quote literal done in test for-lists for SC1010

* ci: expect 19 snapshot/fleet-view tests

This branch adds a fleet-snapshot regression, so the stock macOS Bash
lane's hardcoded guard of 18 'ok - ' lines fails on the new count.
Bump the guard and its message to 19.

* no-mistakes(review): Restore multiline child outcome reporting

* no-mistakes(review): Select ledger terminal events through bounded shared reader

* no-mistakes(review): Report newest open decision instead of preferring blocked

* no-mistakes(review): Require colon before ship/scout terminal supersession in fold

* no-mistakes(review): Gate socket-down override on latest event; drop lock matrix

* no-mistakes(review): Fold only colon-bearing or keyed lines as decision transitions

* no-mistakes(review): Pre-select candidate lines before per-key closing-verb fold

* no-mistakes(test): Update fleet-view expectations to newest-open-decision rule

* no-mistakes(document): Align status-read docs with fold-resolved crew state

* no-mistakes(document): Correct status-reader contracts in classify-lib and crew-state headers

* no-mistakes(ci): Greptile P1 (bin/fm-crew-state.sh:729, "Stale socket blocker survives") was a real defect introduced by commit b7c2183 on this branch, and is fixed. Root cause: the daemon-socket-down override took its verb check from `last_status_line "$LOG"` but its evidence and emitted detail from `$LOG_LINE` (status_current_line = the fold's newest still-open decision). Those are different lines whenever a later recognized `blocked:` event is one the decision fold declines. Reproduced by sourcing bin/fm-classify-lib.sh on `blocked: no-mistakes daemon socket is missing` followed by `blocked [key=pending-reply-t3]: still waiting on the answer` (reserved-namespace key whose note does not speak that vocabulary, so _fm_decision_key_transition_allowed rejects it): open set still holds the socket blocker, last_status_line returns the newer line, its verb is blocked, so the gate passed and the stale daemon-down evidence overrode a healthy attributed run. Fix (bin/fm-crew-state.sh): capture LOG_LATEST=$(last_status_line "$LOG") once and read verb, socket-down evidence, and the emitted note all off that same line, so the override fires only while the socket-down declaration is itself the log's latest recognized event — preserving the narrow override the prior round's user instruction asked for. Comment updated to state that contract. No new machinery; the two-line conflation was removed rather than papered over. Regression: extended tests/fm-crew-state.test.sh:test_socket_refusal_override_expires_when_the_crew_moves_on with the reproduced sequence, asserting the run-step reading (state: working, source: run-step) and absence of the override detail. It fails before the fix ("not ok - a later unfolded blocked event also hands the reading back to the run (missing: 'state: working')") and passes after. Verified locally: tests/fm-crew-state.test.sh, tests/fm-fleet-snapshot-view.test.sh, tests/fm-classify-decision-key.test.sh, tests/fm-watch-triage.test.sh, tests/fm-captain-hold-lifecycle.test.sh all pass; bin/fm-lint.sh (shellcheck 0.11.0 + actionlint) exits 0. Changes left uncommitted in the worktree

* test: fold terminal-cleanup snapshot coverage into the completed-scout case

Keep the ship/scout/secondmate supersession assertions without adding a
nineteenth top-level fleet-view test, so CI can stay at the upstream suite count.

* no-mistakes(document): Clarify socket-down override expiry in architecture doc

* ci: retrigger flaky contribution check
…nchenguid#4689)

* fix(spawn): launch codex crewmates with codex's hook layer disabled

A freshly launched Codex worker never reached its instructions. Codex
stopped it on an interactive "Hooks need review" modal whose selection
sits on "Review hooks", which is neither trusting nor declining.
Firstmate's key plane carries only Enter, Escape and Ctrl-C with no arrow
navigation, so the selection cannot be moved, and pre-accepting the
prompt by writing Codex's own trust store would record an operator
consent that was never given.

The hooks are the machine's own ~/.codex/hooks.json plus any project's
.codex/hooks.json. A crewmate needs neither: its turn-end signal is the
-c notify= program on the same launch, and Firstmate's project hooks are
primary-session infrastructure that stands down in a child worktree.

Crewmate and scout launches now pass --disable hooks. That is the
opposite of --dangerously-bypass-hook-trust, which RUNS the untrusted
hooks; disabling the feature runs none of them and leaves the operator's
~/.codex untouched. An unknown feature name is a hard Codex error, so a
release that drops the flag fails the launch loudly instead of silently
restoring the modal. A secondmate is a primary in its own home and keeps
the project hooks its turn-end guard and session-start digest ride on.

Verified on codex-cli 0.151.0: the modal is gone and the turn-end
notification still lands.

This unblocks the second review that every finished pull request is supposed to get.

Fixes kunchenguid#4673

* no-mistakes(review): Fix contradictory hook count in Codex verification record
…d#4669, Fixes kunchenguid#4670) (kunchenguid#4710)

* fix(bin): settle terminal contributions and wake once per read-failure episode

A contribution whose last good observation is merged or closed is final:
poll no longer re-reads it, projection keeps it fresh, and a stale error
recorded beside it is cleared once. A genuine forge-read failure on an open
contribution still records its error on every cycle but prints the
unavailable wake only when it starts a failure episode; a successful read
ends the episode. Open PRs linked from done tasks keep being observed.

The false unavailable beside a complete observation was budget exhaustion
mid-observation, already fixed by kunchenguid#4661.

* fix(review): Settle terminal contribution owners

* fix(review): Deduplicate shared contribution failure episodes

* fix(test): Preserve settled terminal contribution records
* fix(crew-state): select authoritative validation runs by identity

Use the AXI run overview and id-addressed status reads to preserve replacement review gates, report competing live runs as unknown, and retain newer failures. Keep the coarse ledger in creation order rather than preferring an older live row.

Refs: kunchenguid#3215

* fix(review): Resolve same-branch run identities beyond capped history

* fix(review): Fix run-selection compatibility, races, and worker-state fallbacks

* fix(review): Limit run validation to the requested branch

* fix(test): Anchor AXI fixtures and document remaining live evidence gaps

* fix(document): Clarify run selection documentation and capture ownership

* fix(lint): Fix ShellCheck diagnostics while preserving fixture isolation
* fix(AGENTS): send a captain-facing outcome instead of shipshape for finished requested work

MAIN answered a supervision-branch outcome for completed captain-requested
work (implementation done, PR ready for review and merge approval) with
"Captain, shipshape.", reading section 9's no-action reply as covering it
and reading the Pi protocol's "do not re-emit the anchor verbatim" as "no
captain-facing response is owed".

Section 9 now limits the shipshape reply to true no-ops (idle re-read,
empty heartbeat, consequence-free acknowledgement) and requires a short
outcome response naming what finished and what word is needed whenever
requested work finishes or a result needs the captain's word, even when a
transcript entry already shows the substance. The Pi protocol's re-emit
rule now says it bounds repetition only, and carries a worked example of
the ready-for-review outcome whose correct processing turn a shipshape
reply fails.

No executable contract evaluates the content of MAIN's captain-facing
reply, so the regression is the protocol example in the owner doc rather
than a text-match test.

* no-mistakes(document): Clarify captain-facing outcomes versus no-ops

* docs(pi): restore the ready-for-review regression example as a preserved-verbatim contract line

The document step condensed the Pi protocol's re-emit rule and dropped the
worked example of a finished, ready-for-review outcome whose correct
processing turn a "Captain, shipshape." reply fails. That example is the
contract's regression: no executable contract evaluates the content of
MAIN's captain-facing reply, so the owner doc's example is the test case.

Restore it directly under the re-emit rule, prefixed as a regression
example that is kept verbatim and never condensed or summarized away.

* no-mistakes(review): Clarify captain outcome and decision-word requirements

* no-mistakes(document): Clarify captain-facing completion outcomes

* docs(pi): require the PR URL in the visible captain-facing outcome reply

Captain review on the regression example: drop the sample reply string
and say only that the ready-for-review outcome requires relaying a
captain-facing outcome response, not just "Captain, shipshape.".

Fold in the visible-PR-handoff failure seen this session: after the
branch outcome reporting this fix green, MAIN's visible reply was only
"Awaiting your merge call." with no PR URL, leaning on the dim anchor.
Section 9's URL rule now also covers a review or merge ask and names the
visible reply as where the URL goes, sourced from the ready status, pr=
metadata, or the supervision branch's summary and never left to a
transcript entry. The Pi protocol adds the same-way failure and places
the captain-facing text in the final visible assistant reply after the
fm_branch_processed call, because Calm hides assistant text emitted in
the same step as a tool call as a working note.

Investigation verdict, evidence in the PR comment: no recent PR caused
the handoff failure; Pi has hidden same-step pre-tool assistant text
since kunchenguid#2339 (2026-08-13), kunchenguid#4655 changed only the Claude Code mod, and
kunchenguid#4658 touched only remote report transfer.

* no-mistakes(review): Restore safe outcome ordering and consolidate PR URLs

* no-mistakes(document): Clarify captain-facing supervision outcomes

* docs(AGENTS): keep the whenever-a-PR-is-mentioned trigger on the consolidated URL rule

The consolidated section 9 URL rule narrowed its trigger to a review or
merge ask, dropping the "whenever a PR is mentioned" catch-all from
kunchenguid#3648 that keeps every PR URL copied from a durable record and never
assembled from memory. Restore that trigger as a union with the review
or merge ask so the one consolidated rule covers both.
* Fix foreign-owner turn-end supervision loop

* no-mistakes(review): Scope foreign-owner safe exit to Claude guard

* no-mistakes(document): Document Claude foreign-owner safe exit
…orb (kunchenguid#4778)

Under set -u, stock macOS bash 3.2.57 treats "${arr[@]}" on an empty
indexed array as an unbound variable and aborts the shell. In
signal_turnend_panes_churned() the missing_keys loop was reachable with
an empty array whenever every churned key already held a fresh
.churn-since-* marker (a second churning turn-end inside an open
deferral window), so each watcher cycle died about half a minute in and
supervision restarted endlessly. The created_keys rollback loops had the
same latent crash on their error paths.

Audit of bin/ for the same pattern found one more confirmed-reachable
case: remote_handoff's noncanonical-body scan iterates to_move, which is
empty when a retried remote handoff finds every key already staged in
the outbox. All other "${arr[@]}" sites are either count-guarded,
guaranteed non-empty by construction, or unreachable while empty.

Guard the three reachable expansions with the repo's existing
"${arr[@]+...}" idiom. New regression test drives a real watcher
through the all-marked churn path; the macos-stock-bash CI lane runs it
under real /bin/bash 3.2 via FM_TEST_ONLY.
… lock. (kunchenguid#4783)

The synthetic harness was named synthetic-claude, which Linux procps truncates to synthetic-claud so fm-lock.sh never matched a harness or wrote state/.lock before the test read it.

Co-authored-by: Cursor <cursoragent@cursor.com>
* docs: require complete final responses across harnesses

* no-mistakes(document): Document complete final replies for Grok Bot

* docs: point Grok replies to the shared contract owner

* no-mistakes(review): Clarify final recap without batching decision asks
* fix(calm): preserve substantive Pi mid-turn text

* no-mistakes(review): Preserve substantive Pi Calm text per block

* no-mistakes(test): Cover shared Calm preservation boundaries behaviorally

* no-mistakes(document): Consolidate Calm preservation documentation
Merge the frozen canonical snapshot while retaining the fork's pilot,
native-path, process, Azure completion, and startup-cost boundaries.
Compose kind-aware status decisions with in-process readers, retain
single-pass snapshot metadata, and secure device re-recording through
the native private-path owner.

Carry typed dispatch through the pilot capability seam, disable Codex
worker hooks without changing primary launches, and preserve the shared
Calm module's repository-relative fixture dependencies. Transfer runner
metadata to the catalogs without granting concurrency admission.

Firstmate-Upstream-SHA: 888871d
Register the classifier's existing cases with the shared named-case
interface while preserving their full-suite order. This permits bounded
serial diagnosis of the new long-history and terminal-declaration cases.

Export the isolated PR fixture's home and state for its sourced lock
owner and subprocesses, satisfying the full source-aware lint contract
without suppressing warnings or weakening private-path assertions.

Firstmate-Upstream-SHA: 888871d
@timbarreto

Copy link
Copy Markdown
Owner Author

Final exact-head CI result

Verified at 2026-09-18T01:32:06.774614+00:00 for f1640f0a2abbb68f128ee46a59c37595186362e6.
20 successful, 0 pending, 0 failed, 0 absent; one verified workflow/job producer for every expected check.
Both automatic workflows completed successfully.
The PR remains open, non-draft, mergeable and unmerged; auto-merge is off.
Use a merge commit to retain the frozen upstream ancestry.

Check Result Producer evidence
Lint successful CI / lint
Test coverage guard successful CI / test-coverage
Behavior portable parallel 1 successful CI / tests-portable-parallel-1
Behavior portable parallel 2 successful CI / tests-portable-parallel-2
Behavior portable serial 1 successful CI / tests-portable-serial {'shard': 1}
Behavior portable serial 2 successful CI / tests-portable-serial {'shard': 2}
Behavior portable serial 3 successful CI / tests-portable-serial {'shard': 3}
Behavior portable serial 4 successful CI / tests-portable-serial {'shard': 4}
Behavior portable serial 5 successful CI / tests-portable-serial {'shard': 5}
Behavior tests (Herdr) successful CI / tests-herdr
Behavior timing aggregate successful CI / tests-timing-aggregate
Stock macOS Bash snapshot compatibility successful CI / macos-stock-bash
Repo invariants successful CI / invariants
Windows self-update entry point successful Fork CI / windows-update
Windows reconciliation (core) successful Fork CI / reconciliation-windows {'subject': 'core'}
Windows reconciliation (copilot-launch) successful Fork CI / reconciliation-windows {'subject': 'copilot-launch'}
Windows reconciliation (legacy-rollback) successful Fork CI / reconciliation-windows {'subject': 'legacy-rollback'}
Windows reconciliation (pr-completion) successful Fork CI / reconciliation-windows {'subject': 'pr-completion'}
Windows Copilot management successful Fork CI / windows-management
Harness package compatibility successful Fork CI / harness-package-compatibility

All four final local repository gates pass, together with source-aware lint and 14 successful focused behavior invocations after the approved continuation.
The original full-script timeouts remain recorded; the unchanged isolated history/transition cases and the final native/Linux/macOS lanes pass.
The first head's CI lint finding was confined to isolated test environment declarations and is fixed without suppressions; no production deadline was increased.
Local TypeScript was absent; the exact final-head package/type jobs above supply that evidence.

Known incoming limitations, including canonical kunchenguid#4476's capped-overview rerun race and the optional live-vendor coverage gaps, remain explicitly documented in the PR body; a green matrix is not a claim that those limitations were fixed.
No PR merge or local-main synchronization was performed.

Integrate PR #69's missing-terminal recovery and PR-poll publication
serialization without advancing the canonical upstream snapshot.

Keep metadata locked through publication, retain the upstream publication
lock, and release both before contribution or parent-channel reporting.
Capture watcher snapshots under metadata authority, release it before
lifecycle acquisition, and repeat the protected capture after remount
re-recording. Recovery takes control, metadata, then publication locks.

Preserve both sides' recovery, tamper, publication and remount regressions.
The separate capped no-mistakes rerun-selection race remains unchanged.

Firstmate-Upstream-SHA: 888871d
@timbarreto

Copy link
Copy Markdown
Owner Author

Fork-base conflict resolution: 460aca8

Resolved and pushed 460aca84d171cc64a1132fece6228910150d4456, tree dce299f9920d553b4b08168d2e9fc8a8750af0f0, by merging the fork's actual new main 6e220fcb3ad2eaf2a469ac2f4556a0544f7d4afe into the existing reconciliation branch.
The first parent is f1640f0a2abbb68f128ee46a59c37595186362e6; both branches' history is preserved.
GitHub reports this PR mergeable, open and non-draft, with auto-merge off.
Only origin/main was fetched; canonical upstream remains frozen at 888871de5cdf875ba4f4c0d231da6efdf7bad9a8.
Local main is unchanged and no other project checkout or live Firstmate home was used.

Conflict decisions

  • bin/fm-pr-check.sh: keep PR fix: recover missing Herdr workers and serialize PR polls #69's metadata lock across the entire visible publication and upstream fix(bin): preserve PR merge polls across volume remounts kunchenguid/firstmate#4656's separate publication lock. Release both before contribution arming or parent-channel reporting.
  • bin/fm-watch.sh: take metadata-locked snapshots, defer a busy writer, and release read authority before lifecycle acquisition. Device recovery takes control → metadata → publication locks, then repeats the protected snapshot. Strict content/privacy/identity validation and later snapshot revalidation remain unchanged.
  • Incoming missing-terminal recovery, replay/refusal behavior, documentation and both sides' regressions are retained. Its control implementation and recovery suite remain byte-identical to the new fork main.
  • The update changes exactly the 11 incoming paths; the complete PR still has the same 102-path manifest and unchanged 205-script selection. Workflow/catalog/runner/proof definitions are byte-identical to the prior reconciliation head, preserving the 20 expected automatic producers and all gates, pins and deadlines.

Two different races

PR #69 fixes the partial PR-poll publication/authentication race.
It does not fix canonical #4476's capped no-mistakes rerun-selection race; bin/fm-nm-run-lib.sh and bin/fm-crew-state.sh were unchanged by #69 and this base merge.
That documented high-risk upstream limitation remains.

Fresh local verification on the committed tree

All 11 commands below passed with cache disabled and the new literal base in validation context.
All four repository gates were rerun; no previous-head pass was substituted.
B=C:/Program Files/Git/usr/bin/bash.exe, FM_LIVE=0; behavior cases use FM_TEST_BASE_PATH=/mingw64/bin:/usr/bin:/bin:/usr/sbin:/sbin and FM_TEST_CHECK_TIMEOUT=30.
The last setting gives only fixture subprocesses Windows headroom; no production/CI deadline or embedded negative timeout assertion changed.

Command Result ms CI owner
S (expanded below) passed 15961 CI / Lint; Stock macOS Bash snapshot compatibility
"$B" bin/fm-lint.sh bin/fm-pr-check.sh bin/fm-watch.sh bin/fm-control.sh bin/fm-control-recovery-lib.sh tests/fm-pr-check-security.test.sh tests/fm-control-recovery.test.sh passed 107914 CI / Lint
"$B" bin/fm-lint.sh passed 88408 CI / Lint
"$B" bin/fm-doc-audience-check.sh passed 5657 CI / Lint and the portable documentation-audiences subject
"$B" bin/fm-test-run.sh --check-coverage passed 134478 CI / Test coverage guard
FM_TEST_ONLY=test_reregistered_poll_is_not_rejected_mid_publication "$B" bin/fm-test-run.sh --jobs 1 tests/fm-pr-check-security.test.sh passed 191858 CI / Behavior portable serial 4
FM_TEST_ONLY=test_watcher_rejects_tampered_registration_after_publication "$B" bin/fm-test-run.sh --jobs 1 tests/fm-pr-check-security.test.sh passed 140442 CI / Behavior portable serial 4
FM_TEST_ONLY=test_device_renumbered_poll_stays_armed "$B" bin/fm-test-run.sh --jobs 1 tests/fm-pr-check-security.test.sh passed 420294 CI / Behavior portable serial 4
FM_TEST_ONLY=test_device_rerecord_preserves_private_policy "$B" bin/fm-test-run.sh --jobs 1 tests/fm-pr-check-security.test.sh passed 76935 Fork CI / Windows reconciliation (pr-completion); CI / Behavior portable serial 4
FM_TEST_ONLY=test_relaunch_missing_endpoint_preserves_copy "$B" bin/fm-test-run.sh --jobs 1 tests/fm-control-recovery.test.sh passed 75102 Fork CI / Windows Copilot management; CI / Behavior portable serial 4
I-new (expanded below) passed 42930 CI / Test coverage guard and the expanded portable/Herdr producer inventory

S is "$B" -c with:

set -e
inventory=$(bin/fm-lint.sh --list-files)
while IFS= read -r script; do
  [ -z "$script" ] || /bin/bash -n "$script" || exit
done <<< "$inventory"

I-new is "$B" -c with:

set -euo pipefail
bin/fm-test-run.sh --list --changed --base 6e220fcb3ad2eaf2a469ac2f4556a0544f7d4afe > "$EVIDENCE/changed-inventory.txt"
printf 'FM_RECONCILE_NEW_BASE_INVENTORY count='
wc -l < "$EVIDENCE/changed-inventory.txt"

Prerequisites were probed: recorded Bash, Git, standard text/file utilities, Perl, pinned ShellCheck/actionlint, Python, jq and PowerShell, plus host Git signing/hook/bare-repository policy without changing it.
Full logs, probes and cumulative accounting are retained outside the repository in the original evidence directory's base-update-6e220fc/ subdirectory.
The two PR-registration fixtures explicitly reported contribution observation unarmed because their deliberately restricted fixture PATH has no jq; those cases prove publication/authentication behavior, not contribution-observer coverage.
The full contribution suite, both publication-lock serialization cases, complete device-tamper/recovery matrices and strict package types remain with their existing CI producers.
No optional live-vendor test was enabled.

Coverage remains 239 = 24 parallel + 199 serial + 16 Herdr; documentation validation now checks 108 surfaces / 478 local links.
The cumulative ledger is 3,849,341 ms, including 1,411,919 ms for this base update; the two original timeouts are retained as historical outcomes, with no new timeout here.
Aggregate budgets remain removed by the explicit earlier instruction, while each command retained actual cancellation.

The fresh exact-head CI runs are CI and Fork CI.
Prior-head green checks are not this head's evidence; the current check inventory and results are reported separately.
The PR stays unmerged.

@timbarreto

Copy link
Copy Markdown
Owner Author

Base-update CI complete: 460aca8

At 2026-09-18T04:22:40.544574+00:00, all 20 automatic checks passed on 460aca84d171cc64a1132fece6228910150d4456 against fork base 6e220fcb3ad2eaf2a469ac2f4556a0544f7d4afe.
Both workflows completed successfully; every expected name has one verified workflow/job producer, with no failed, pending, absent, cancelled or skipped required producer.
GitHub reports the PR mergeable/clean. It remains open, non-draft and unmerged, with auto-merge off.

Check Result Exact producer
Lint successful CI / lint
Test coverage guard successful CI / test-coverage
Behavior portable parallel 1 successful CI / tests-portable-parallel-1
Behavior portable parallel 2 successful CI / tests-portable-parallel-2
Behavior portable serial 1 successful CI / tests-portable-serial {'shard': 1}
Behavior portable serial 2 successful CI / tests-portable-serial {'shard': 2}
Behavior portable serial 3 successful CI / tests-portable-serial {'shard': 3}
Behavior portable serial 4 successful CI / tests-portable-serial {'shard': 4}
Behavior portable serial 5 successful CI / tests-portable-serial {'shard': 5}
Behavior tests (Herdr) successful CI / tests-herdr
Behavior timing aggregate successful CI / tests-timing-aggregate
Stock macOS Bash snapshot compatibility successful CI / macos-stock-bash
Repo invariants successful CI / invariants
Windows self-update entry point successful Fork CI / windows-update
Windows reconciliation (core) successful Fork CI / reconciliation-windows {'subject': 'core'}
Windows reconciliation (copilot-launch) successful Fork CI / reconciliation-windows {'subject': 'copilot-launch'}
Windows reconciliation (legacy-rollback) successful Fork CI / reconciliation-windows {'subject': 'legacy-rollback'}
Windows reconciliation (pr-completion) successful Fork CI / reconciliation-windows {'subject': 'pr-completion'}
Windows Copilot management successful Fork CI / windows-management
Harness package compatibility successful Fork CI / harness-package-compatibility

The conflict decisions and fresh local command evidence include all four gates, source-aware lint, five focused cases and refreshed routing against the new base.
Native/package/portable results above belong to this head, not the previous green run.

PR #69's partial poll-publication race is fixed and preserved here.
The distinct canonical kunchenguid#4476 capped no-mistakes rerun-selection race remains a documented upstream limitation; passing CI is not a claim that it was repaired.
Canonical upstream remains frozen, and local main was not synchronized.

@timbarreto
timbarreto merged commit 1c11c41 into main Sep 18, 2026
20 checks passed
@timbarreto
timbarreto deleted the reconcile/upstream-2026-09-17-888871de branch September 18, 2026 04:27
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.

8 participants