Reconcile upstream 7111081c (September 16, 2026) - #58
Conversation
…d#4497) * fix(dispatch): support Codex Luna max effort * no-mistakes(review): use portable CODEX_HOME path in codex effort reference
kunchenguid#4498) * feat(calm): render smooth Unicode swell * feat(calm): make sails asymmetric * feat(calm): use quarter sail glyph * no-mistakes(review): docs: sync calm feasibility sprite passage with approved renderer * no-mistakes(document): docs: sync calm wave phase doc comment * no-mistakes(ci): CI の Lint 失敗は tests/fm-calm-pi-extension.test.sh の test_interactive_terminal_e2e 関数で `boat_narrow_sails` が local 宣言に残っていたことによる ShellCheck SC2034 でした。関数内での参照を確認したところ、狭幅端末の検査は boat_narrow_previous / boat_narrow_direction / boat_narrow_reversed に移行済みで、boat_narrow_sails は代入も参照も一切ありませんでした。そのため local 宣言からこの 1 語のみを削除しました(3315 行目)。Calm の描画実装、他のテストアサーション、ドキュメントは変更していません。検証: bin/fm-lint.sh(ローカル変更ファイルモード)exit 0、CI 相当の `shellcheck --norc --external-sources tests/fm-calm-pi-extension.test.sh` exit 0(SC2034 解消)、`bash -n` 構文チェック通過、actionlint 1.7.12 でワークフロー 3 件 valid。
kunchenguid#4491) * fix: supersede scout delivery brief on promotion * fix: preserve ship safety contract after promotion * no-mistakes(document): Document fm-promote.sh now supersedes brief.md on relaunch
…d stop cleanup dropping accents from a held body (kunchenguid#4471) * fix(bin): let captain holds work on hosts with an older JSON::PP Holding a task for the captain, and the cleanup that keeps a captain-held row open, both fail outright on any host whose JSON::PP defaults allow_nonref off - 2.27202 on a Linux desk is one. Both read a task's body back with `decode_json`, but tasks-axi shows a scalar field as a JSON-encoded bare string, and an older library rejects that whole value with "must be object or array". The consequence is fleet-wide on such a host, not one broken command: a worker there cannot formally record a decision for the captain at all. It can only mention the decision in passing in a status line, where it can be missed - which is how a real decision goes unrecorded. The hold reports that the task lost its hold-set stamp; the cleanup cannot return the row to Queued. Both call sites now ask for allow_nonref explicitly rather than inheriting whatever the installed library defaults to. The second one is worth naming: its `/\A"/` guard reads as deliberate, but a leading quote is exactly the bare-string case that fails, so the guard selects for the failing input rather than protecting against it. The regression case forces the older default back off for every perl the commands spawn, then drives both paths - holding a task that carries a body, and tearing down a captain-held row whose deliverable must still be appended. It also probes that the simulation genuinely rejects a bare scalar, so the case cannot pass vacuously on a lenient host. Each half was verified failing on its own unfixed call site with that site's real error message. Suites: fm-captain-hold-lifecycle 51 cases, fm-backlog-atomicity 99 cases, 0 failures. Verification limit: the mechanism is reproduced and tested, but neither fix is verified against a real JSON::PP 2.27202 host, because none is in the loop. This laptop runs 4.06, where the bug does not manifest. `bin/fm-procevent-lavish.sh:471` was checked and left alone - it matches a brace-delimited object before decoding, so allow_nonref never applies. * fix(bin): stop cleanup silently dropping accented characters from a held body Cleanup rewrites a captain-held row's body to append the finished work's deliverable, and the decoder it reads that body with printed decoded characters to a stream with no `:raw` layer. A character at or below U+00FF then came out as one latin-1 byte instead of two UTF-8 ones, so a body reading "café" lost the accent. `fm_backlog_retain` writes that body straight back through `--body-file`, and nothing reported an error - the character was simply gone from a row still waiting on the captain. The decoder now writes bytes, the same `binmode STDOUT, ":raw"` plus `utf8::encode` that the sibling decoder in `bin/fm-captain-hold.sh` already used. Review of the parent commit found this on one of the lines that commit already changed. It predates that change. The test asserts bytes rather than decoded strings, because comparing strings cannot tell latin-1 from UTF-8. It uses two separate rows on purpose: any character above U+00FF makes perl print the whole string as UTF-8, so one body carrying both an accent and an em dash passes even unfixed and proves nothing. Verified failing before the fix on the accented row, passing after. Suites: fm-captain-hold-lifecycle 52 cases, fm-backlog-atomicity 99 cases, 0 failures. * no-mistakes(document): record body-decode regression proofs in captain-hold lifecycle doc * no-mistakes(review): drop whole-file UTF-8 check from retained-body test * no-mistakes(review): correct stale JSON::PP fleet-host claim in lifecycle doc * no-mistakes(review): anchor native-reproduction claims per defect in lifecycle doc
…furniture (kunchenguid#4532) * fix(composer): read codex 0.154's idle starfield and status footer as furniture codex-cli 0.154.0 animates a braille "starfield" around its idle composer: on the row above the bold `›` prompt row, on the `›` row behind the SGR-2 dim `Ask Codex to do anything` placeholder, and on the row below it, then draws a bright status footer (`<model> <effort>[ fast] · <path> · <title>`). The cells are truecolor greys on both sides of the ghost luminance ceiling, so the brighter ones survive ghost stripping, and the rows below the glyph carry no structural edge. The shared classifier selected the bare `›` shape, extended its wrap region over the two rows beneath the glyph, read the survivors and the footer as wrapped typed input, and answered `pending`; the steering doorbell defers on exactly that verdict, so no doorbell ever reached an idle codex 0.154 pane. bin/fm-composer-lib.sh now recognises that furniture by shape, declared once next to the idle placeholders and reached from the two wrap-region boundary points: - a row whose non-whitespace content is entirely braille cells (U+2800..U+28FF, detected byte-exactly under LC_ALL=C) is furniture: it never counts as wrapped typed content and bounds a bare composer's wrap region; braille behind the glyph row's content is stripped before the emptiness decision when nothing else follows the glyph; a row mixing braille with other text stays typed content; - the codex status footer bounds the wrap region exactly as omp's status row does, anchored on the effort token, a spaced middle dot, and a `~` or `/` path cell, so a typed `fix · tests` stays composer input; - `^Ask Codex to do anything$` joins the verified idle-placeholder set; the ghost strip remains what proves that row empty, and the bare-row rule that bright placeholder text is real input is unchanged. Unchanged: the strict blank-row rule, the styled=0 degradation (a plain cmux/orca capture of this screen still reads `unknown`, never `pending`), FM_COMPOSER_GHOST_LUMA_MAX, and every other harness's shape. tests/fm-composer-lib.test.sh carries both live Herdr samples byte-for-byte with the divergence (letters in place of the starfield read `pending`) and the over-stripping negatives; tests/fm-composer-codex-idle-live-e2e.test.sh is the default-on live guard (token-free, skips explicitly without codex or tmux) that launches the installed codex idle and asserts `empty` through both the tmux and the cursorless styled reads, naming codex --version on failure. docs/verification/runtime-backends.md records the dated Herdr evidence: `pending` before, `empty` after, on the captured screen. * no-mistakes(review): drop unreachable codex footer rule and inert placeholder entry --------- Co-authored-by: Todd Billings <todd@usdvcapital.com>
* fix(bin): refuse empty text steers in fm-send A marked secondmate request sent with an empty message delivered only marker and correlation bytes and minted a pending-reply expectation the parent could never see resolved, stalling the fleet with no loud error (kunchenguid#4255). Fail closed on an empty or whitespace-only message on the text path, mirroring the existing --resolve-key refusal. * chore: retain ambient Pi-lens autoformat as its own commit Formatting-only edits produced by ambient Pi-lens autoformat during the msg-loss investigation, kept separate from the behavioural change in c23acba so the fix stays reviewable on its own. AGENTS.md is deliberately excluded: its only autoformat edit stripped the trailing space from the documented FM_OPERATIONAL_PREFIX value, which bin/fm-operational-input.sh:28 defines as "FIRSTMATE_OP: " and line 11 records as permanent compatibility. Documenting that constant without its trailing space makes the doc wrong about the contract, so that one line was restored rather than retained.
…chenguid#4554) On rose-pine-moon the two-color water (cyan crests over blue troughs) read as a pink stripe over aqua, the yellow left sail and mast clashed with the red right sail, and the hull carried a blue interior run. Every water cell is now blue so the swell reads through glyph height alone, and both sail halves, the mast, and the whole hull are one yellow run. Geometry, cadence, animation, direction flip, resize clamping, and the narrow fallback are unchanged. Update the unit and real-TUI color assertions to the new palette and the Calm docs that described the old one.
…chenguid#4270) * fix(watch): stop aging a second mate's active turn from its launch The parent watcher's second-mate wake-loop stall check exempts a mate that is demonstrably inside an active turn, but secondmate_in_active_turn asked busy_turn_over_age first and returned "not in a turn" whenever that said the bound was crossed. busy_turn_over_age ages from state/<task>.turn-ended, falling back to state/<task>.meta. A second mate's turns end in its own home, so the parent never gets a turn-ended mark for it and the fallback ages the mate's last launch. Every mate launched more than BUSY_TURN_MAX_SECS ago was therefore permanently "over age", the busy pane was never consulted, and any turn outstripping FM_SECONDMATE_WAKE_STALL_SECS raised a false wake-loop stall. The gate now bounds the busy exemption by <idle> - how long the queue's drain position has not moved - which is evidence this home actually holds. A busy mate stays exempt while the queue has been frozen for less than BUSY_TURN_MAX_SECS, and a mate stuck busy forever still alarms, so the bound that stops a busy pane from proving liveness forever is kept rather than removed. busy_turn_over_age is untouched; its remaining callers are the ordinary crew busy-pane bound. The regression pins the case that actually broke: a mate whose launch record predates BUSY_TURN_MAX_SECS and which is demonstrably mid-turn must not escalate, while the same mate with its queue frozen past the bound still publishes exactly one notification. The existing coverage only exercised a freshly launched mate, which passes either way. Reaching that alert now costs a pane capture inside the gate, so the three checkpoints in this suite that assert an alert move from a 1s to a 4s bound - the value the neighbouring active-turn cases already use. The bound is a ceiling, not a wait: the checkpoint returns on the first actionable wake. On a loaded machine a 1s bound missed the alert repeatedly; at 4s it did not miss in 20 runs under the same load. * no-mistakes(review): scope the second-mate active-turn regression test's coverage claim * no-mistakes(document): fix stale second-mate active-turn comments in fm-watch
…unchenguid#4278) * feat(bin): add read-only PR blocker and reviewer-discovery commands Two focused, opt-in commands that read GitHub and never write to it. fm-pr-state.sh reports what still blocks one pull request from the author's side: a closed or merged state, draft state, unknown or conflicting mergeability, absent or failing required checks, and a blocking CHANGES_REQUESTED decision explained by each reviewer's latest verdict, marked STALE when it was left at a superseded head. A pull request that only awaits an approval is not reported as blocked, and advisory checks are omitted. Every reading is taken against one exact head; a push that lands mid-read invalidates the whole result rather than mixing two snapshots. fm-pr-reviewers.sh suggests reviewers from the most recent commits to the pull request's exact changed paths, counting each commit once, resolving handles through GitHub's own commit author.login mapping, and excluding the author and Bot accounts. Both stay read-only: no review request, no approval, no merge. Unresolved review-thread state is left unreported because the REST API does not expose it and unattended commands may not use GraphQL. Closes kunchenguid#3731 * no-mistakes(review): accept only PR URLs and stop at terminal state * no-mistakes(review): report unconfirmed required checks; make URL-only guards discriminate * no-mistakes(review): stop attributing readings to unverified heads * no-mistakes(review): narrow readiness contract to checks that have reported * no-mistakes(review): read the pull request once, drop the head guard * no-mistakes(document): scope pr-forge isolation proof to its measured members * no-mistakes(document): record uncovered pr-forge members and their pending proof * docs(isolation-proof): re-prove pr-forge at its full membership tests/fm-pr-state.test.sh and tests/fm-pr-reviewers.test.sh joined the pr-forge family in this branch, and script_allows_concurrency grants four workers by family membership alone, so both ran concurrently on a proof measured before they existed. Re-proved the family at all eight members: two consecutive runs, 0 failures, each begun with the one-minute load average below 6.0 so the result measures isolation rather than contention. A third run taken between them is disclosed rather than recorded, because it started while the previous run's workers were still decaying. The new durations are not comparable with the six-member measurement above them, so they are not presented as evidence about the two new members, and that record's 1.72x four-worker figure is left as a statement about its own run rather than restated as current. * no-mistakes(review): disclose gh error-text coupling at its matching site and tests
…uid#2752) * fix(bin): teach validation-round pauses in briefs * no-mistakes(document): Point classifier comments to authoritative pause examples
…guid#4510) * fix(teardown): refuse a cleanup whose endpoint close failed bin/fm-teardown.sh discarded both the exit status and the stderr of every fm_backend_kill call, so a close that genuinely failed was indistinguishable from one that succeeded. Teardown continued past it, deleted the task's durable records, returned its worktree, and reported the cleanup as completed. The deleted metadata is the only record of which endpoint belongs to the task, so such a close did not merely leave a stray session behind, it stranded one: nothing was left on disk naming it. The adapters could not carry that signal either. Driven against the real code, every backend arm returned 0 for a genuine failure exactly as it did for an already-exited endpoint, so there was nothing for the four call sites to propagate even once they stopped swallowing it. The tmux arm now resolves a close that did not succeed against the window's exact recorded identity, since kill-window fails the same way for a window that is gone and one that is still there. The Orca arm reports a close its missing CLI never attempted. Both stay silent for an endpoint that is already legitimately gone, and the remaining arms are unchanged: their close-command timing cannot be established without the real Zellij, Orca, and cmux binaries, and a gate that refused ordinary cleanup of an already-exited session would be worse than the defect. docs/verification/runtime-backends.md records what each backend can prove. A reported close failure now reaches teardown's existing retain-and-stop refusal before the records naming the endpoint are removed, matching where the Herdr confirmed-gone gates already sit for the same hazard, and the retained records let a rerun finish once the close works. * no-mistakes(review): refuse unreadable tmux close re-read; honor --force override * no-mistakes(review): drop unreachable Orca force arm; prove CLI-absent close * no-mistakes(document): document endpoint-close refusal in its backend and retirement owners * no-mistakes(ci): The two reported failing checks are NOT code defects. Both "CI" (run 34935529184) and "Require no-mistakes" (run 34935529206) returned conclusion=action_required with zero jobs and 0s duration (run_started_at == updated_at), which is this repo's workflow-approval gate holding the run before any job starts. No job executed, so nothing in the diff could have caused them; two unrelated branches (fm/captain-hold-json-nonref, fm/presenter-core-l1) show the identical shape in the same time window. Verified the change locally instead: bin/fm-lint.sh clean, bin/fm-test-run.sh --check-coverage ok, and all suites the diff touches pass (fm-teardown-endpoint-safety 25/25 including the five new endpoint-close cases, fm-backend-orca, fm-backend, fm-backend-tmux-smoke, fm-backend-cmux, fm-backend-zellij, fm-backend-herdr). Separately, I found and fixed a genuinely flaky test that the phase rules require me to make deterministic: tests/fm-tmux-agent-liveness.test.sh intermittently failed "an idle shell pane must classify dead" (verdict ambiguous, comms=[bash sleep]). It is selected by --changed for this diff, so it would run against this PR once CI is approved. Root cause, established by instrumenting the pane's process group: the idle window was created by `new-session` with no command, so it inherited tmux's default-shell, i.e. whoever runs the suite. ps on the pane tty showed `-zsh` -> `bash` -> `sleep`, all sharing pgid==tpgid, i.e. the host operator's shell configuration spawning a periodic helper directly into the pane's FOREGROUND process group, which is the one surface the classifier reads. `sleep` classifies as `other`, so fg_other=1 and the verdict became `ambiguous` instead of `dead` whenever that helper overlapped the 10s poll window. Every other window in the suite runs an explicit command via new_window; the idle case was the only one whose process group the host defined. Fix (smallest root-cause, test-only, 1 line + explanatory comment): create the idle window with an explicit bare `/bin/sh` (`-- /bin/sh`), the same shell the neighbouring background case already execs. Its foreground group is now exactly one process (verified: `/bin/sh` alone), so no host configuration can inject into it. This flake is pre-existing and NOT caused by this PR: an interleaved A/B showed base commit da5e658 failing the identical case (2/6 runs) alongside head (3/7 runs), and the diff only extracted the tmux inventory read into a helper with identical semantics while never touching fm_backend_tmux_foreground_comms. After the fix: 8/8 consecutive passes, with lint and the coverage guard still clean. Change left uncommitted in the working tree
* feat(calm): ship the Claude Code Calm and sailboat mod behind the function-hooks flag Add .claude/mods/firstmate-calm, a Claude Code mod (function-hooks plugin) that brings Calm to Claude Code: the sailboat replaces the stock working row through a Raster repainted on the sprite's own tick, and tool, tool-group, mid-turn narration, and canonically classified operational user rows draw at zero height. /calm is registered by the hooks module itself and toggles the same per-home config/calm preference the Pi extension uses, so one choice applies on either harness; rows redraw retroactively on toggle and stay hidden across claude --continue. The mod loads only while Claude Code's default-off CLAUDE_CODE_ENABLE_FUNCTION_HOOKS flag is on. Nothing sets that flag in any settings file, and the plugin carries no command file, skill, agent, or classic hook, so it is a complete no-op while the flag is off. The trusted project auto-loads it through an .agents/skills symlink, the only path Claude Code scans for project plugins. Extract the working-ship geometry, bounce track, cadences, and freeze/resume state into a harness-neutral sprite core inside the mod (Claude Code refuses hooks-module imports from outside the plugin folder) and have the Pi widget paint that core's frames as standard ANSI, byte for byte as before; the Pi suite stays green. Classify operational rows through a port of bin/fm-operational-input.sh's classify command guarded by a corpus parity test against the shell owner. Tests: portable Node checks (plugin shape, sprite parity with Pi's rendering, Raster packing, policy, classifier parity), the mod's own claude plugin test suites behind a default-on wrapper, and an opt-in live TUI guard proving the flag-off no-op, the moving boat, hidden rows, the persisted toggle, and resume on Claude Code 2.1.272. Docs: record the version-scoped Claude Code evidence and the three bounded gaps in docs/calm-mode-feasibility.md, describe the Claude Code contract in docs/calm.md, and make the shared preference, layout, and contributor notes harness-neutral. * no-mistakes(review): Preserve colliding final replies and strengthen parser parity * no-mistakes(review): Preserve final replies and strengthen canonical parity checks * no-mistakes(review): Require exact function-hooks opt-in before Calm activation * no-mistakes(review): Clarify Calm module loading and activation boundaries * no-mistakes(review): Reset Calm presentation state across session starts * no-mistakes(document): Refresh Calm session lifecycle documentation * feat(calm): paint the Claude Code working ship in Claude's own theme colors The captain picked the "Claude native" palette for the Claude Code mod's Raster: every water cell takes the spinner blue of the active theme family (#93a5ff dark, #5769f7 light) and the whole boat takes the Claude orange of the stock spinner (#d77757), one water color and one boat color. The family follows the `theme` setting's prefix, read at load through $.config.list and re-read on a config.set of that row, with `auto` and custom themes falling back to the dark set. The Pi extension keeps its standard ANSI blue and yellow, byte for byte. Rename the shared sprite's color classes from hue names to `water` and `boat`, since each harness now maps them to its own colors; geometry, motion, cadence, and the activation gate are untouched. Tests cover both palettes' packing and the family rule under Node, and the plugin kit drives every theme value, a theme change mid-session, the Calm-off pass-through, and inertness of the menu read while the flag is off. The docs describe the Claude Code colors and record the guard passing on 2.1.273. * no-mistakes(review): Use light palette for unresolved Claude themes * no-mistakes(document): Refresh Claude Calm verification evidence
…kunchenguid#4586) * fix(watch): honour a declared wait before wedge-escalating a quiet pane wedge_timer_check escalated on elapsed idle time alone. Nothing asked whether the worker had already said why its pane was quiet, so a lane that declared a bounded external wait climbed the escalation ladder for as long as the wait lasted, and past FM_WEDGE_DEMAND_INSPECT_COUNT every repeat carried demand-deep-inspection - which by its own wording forbids re-absorbing on the run-step or pane state, so the supervisor could not use the evidence that was there either. The generated brief promises that declaring `paused:` buys the long recheck cadence instead of a wedge, but the timer was still reachable while that declaration stood: a crew that declares a wait and then has an active run or busy pane attributed to it is handed to the timer as provably-working. The declaration is what the worker said about its own silence, so it now outranks a liveness verdict that only says something is running. The consult runs in the at-threshold branch that was about to escalate, beside the worktree walk already there, and costs one status-line read. Either status-line record defers to the same FM_PAUSE_RESURFACE_SECS recheck the declared-wait absorber already uses, so the wait is still rechecked and cannot rot invisibly. Which verb declared it decides the wording, because the two block on different people: a `paused:` wait is owed by an external dependency and asks the reader to confirm it still holds, while a `captain-held:` transfer is owed by the captain reading the recheck and asks them to answer or release the hold. A hold is not rechecked at all while the away-posture record exists, as on every other captain-held path, and that absorb arms no throttle so the recheck is owed in full on return. A declared clearing time that has already passed stops counting, and a lane that never declared one keeps the identical escalation schedule, reason, count and demand-deep-inspection wording, so detection and its worst-case time are unchanged. The deferral restarts the idle timer rather than cancelling it, so a lane that stops waiting escalates again within one threshold. A lane quiet because its own validation run is parked at a gate awaiting a human decision is deliberately out of scope: reading that state needs a signal carrying who the wait is on and what clears it, rather than one inferred from a parked verdict that also covers gates awaiting the crewmate itself. Tests pin both directions for each case and were each confirmed to fail with the consult removed. * no-mistakes(document): docs: honour declared waits in stale-escalation docs
* fix(bin): derive passed PR state from PR record A completed no-mistakes run with outcome=passed does not prove the associated pull request merged or closed. A parked gate can be approved on other evidence, so the old crew-state label could report an open PR as merged and make teardown look safe when unlanded work still exists. For passed runs, derive the crew-state detail from the run or task PR identity, accept a matching merge-poll retirement receipt as local merged evidence, and otherwise perform a bounded forge read. If the identity is absent or unreadable, report the run as passed with unknown PR state instead of inventing a merged claim. Fixes kunchenguid#4607 * no-mistakes(review): Add bounded GitLab merge-request state reads * no-mistakes(review): Preserve network-free inactive crew-state scans * no-mistakes(document): Document PR record readers in shared library
Merge the frozen canonical snapshot while preserving the fork's pilot interfaces, Windows identity and transport, Azure completion, lifecycle ownership, startup cost guarantees, and independent CI producers. Compose Codex Luna max effort at the legacy caller without restoring extracted pilot implementations. Transfer upstream test metadata through the catalog seam, preserve named-case coverage, and retain the shared Calm sprite's repository-relative dependency in the Pi type fixture. Fill missing serial hints from successful, non-gated CI measurements; keep concurrency admission and all runtime deadlines unchanged. Distinguish upstream family-proof evidence from the fork's frozen member admissions. Firstmate-Upstream-SHA: 7111081
Exact-head reconciliation handoffObserved 2026-09-16T14:49:07.315Z for 9 successful, 10 pending, 0 failed, 1 not yet visible, against the 20 expanded automatic checks.
The manual Windows Herdr experiment was not dispatched and is not one of these 20 producers. |
Frozen upstream reconciliation
Normal merge of 15 canonical commits, preserving fork behavior and upstream ancestry.
Use a merge commit, not squash or rebase. Merge commits are enabled; this ordinary non-draft PR must remain unmerged with auto-merge disabled until separately approved.
PR readiness is not merge readiness: all four local repository gates and nine focused behavior invocations passed; the complete exact-head GitHub Actions matrix is still required.
GitHub Actions owns the complete cross-platform matrix.
bdb761d9575f524cbea957738fb7149dd6877994d49932335485e2098f13fe1cafaa3077d4410f6c7111081cc10ad8cafcd5a8c7eef75d2b1f724026bc6720ddee8931803c04c44edb1186bf670fb9c90ec85c62e280e1d0480b7ff8f3b674521ae0d210Firstmate-Upstream-SHA: 7111081
The newest valid reachable trailer, on
d9b73af6f291577a8e15dd1ff7f54c68d8761038, proves the prior snapshot.That object exists and is an ancestor of both frozen inputs; earlier reconciliation merge
b087c8dd287a0172cd07f175623f9fc2704dc64bhas it as its second parent, and merged fork PR #52 records the same upstream snapshot and retained head.Main merge
f50d385be9c53b8b2173996b47a1a8a916475ea3retains that head.The matching merge base is supporting ancestry evidence, not the sole synchronization proof.
Upstream was fetched once; the two frozen parents preserve ancestry without reconstruction or an anchor.
Git's trailer parser, tree, file modes, 77-path manifest and clean worktree were verified.
Work was isolated in
C:/src/firstmate-reconcile-2026-09-16-7111081c; primaryC:/src/firstmateremains clean on the original main commit.Existing local rerere settings (enabled=true, autoupdate=false) and global Git policies were preserved.
No live Firstmate home, fleet operation, vendor prompt, credential, merge setting or runtime deadline was changed.
Conflict and ownership decisions
All eight textual conflict paths were resolved against saved base/fork/upstream versions and originating commit/PR evidence.
CONTRIBUTING.mdbin/fm-spawn.shbin/fm-test-run.shtests/catalog/core.tsv, including the mod loader-entry route; the runner and independent proof owner stay byte-identical to frozen fork (kunchenguid#4565/kunchenguid#4278/kunchenguid#4532; fork #40/#44).tests/fm-pi-primary-types.test.shUnconflicted changes remain with their real owners: verified passed-run PR labels and bounded GitHub/GitLab observation; forge-free inactive reconciliation; endpoint-close failure propagation and exact tmux presence re-reads; Orca missing-CLI refusal; declared-wait wedge deferral and secondmate queue-progress aging; empty-steer refusal; promotion's current delivery contract; older JSON::PP/UTF-8 preservation; Codex composer furniture; and the shared Calm sprite/optional Claude mod.
The new read-only PR advisory commands remain GitHub-only as upstream specifies; Azure registration/observation/retirement still use the existing fork codec and native path owner.
A missing supported PR observation is unknown, never an invented merge.
Native/pilot modules, startup fast readers, summary coalescing, Copilot Stop transport, recovery guards, signed-Pi rendering and remote-doctor integrity stay intact.
The complete pilot interface, executable generated Pi artifact, actual Codex/Copilot launch fixtures, rollback case, 13 startup cost/freshness cases and Azure parse/observation/file-replacement checks passed locally.
Those deterministic/native fixtures are not claimed as fresh live vendor runs.
Coverage repair without weaker guards
The first coverage gate correctly refused 34 unhinted / 194 serial scripts, above its unchanged 15% limit after seven incoming test additions.
Fill only 17 previously missing serial hints with the slowest successful, non-gated portable-serial sample per script across three green runs:
35067102623, 35093058383, and 35098646812.
Every sample's run head and artifact SHA-256 are retained outside the repository.
Existing hints, parallel weights, admissions, fallback weight, thresholds and job deadlines are unchanged; skipped/native-only measurements are not substituted.
The refreshed guard passes: 234 = 24 parallel + 194 serial + 16 Herdr, five complete serial shards, 17 unhinted serial scripts, zero missing parallel hints.
The changed selection is 194 scripts, all assigned below; it was inventoried, never executed as a local full suite.
Local evidence and limits
Interpreter:
C:/Program Files/Git/usr/bin/bash.exe, not WSL; FM_LIVE=0; serial selected cases; no dependency installs; caching disabled.Observed tools: Bash 5.3.15, Git 2.55.0.windows.5, Node 24.19.0, jq 1.8.2, Perl 5.42.3, cygpath 3.6.10, ShellCheck 0.11.0 and actionlint 1.7.12.
Read-only signing/hooks/safe.bareRepository probes left host safeguards untouched; test Git isolation remains owned by the existing fixture library.
Measured controller total: 2285843 ms, plus a conservative 30000 ms reservation for initial untimed location probes; 84 seconds remain in the original 2400-second allowance, with one timeout.
The user's continuation did not reset or enlarge the budget or the two-timeout circuit breaker.
All preflight and retry attempts are charged; no interrupted, failed, skipped or preflight-only result is reused as a pass.
/c/src/...path into Node source, which native Node resolves asC:\c\src\...; plugin-shape setup fails with ENOENT before behavior assertions. The one local serial retry and a clean detached worktree at the exact frozen upstream reproduce the same failure. No baseline bytes or selectors were adapted. The test and directly imported Calm files are upstream-exact; Linux CI / Behavior portable serial 1 owns full portable coverage. This is not a local Calm pass or new Windows vendor proof.tsc --versionfailed before Pi typecheck execution. The installed Pi package is present. CI / Behavior portable parallel 1 and Fork CI / Harness package compatibility own the strict compiler/fixture check.Only catalog duration data changed after the initial code gates; only the proof document changed afterwards.
The final documentation gate was refreshed (106 classified surfaces, 466 local links); shell/runtime/selection inputs of the recorded code checks remain unchanged.
These are applicable unchanged-input results, not cache hits.
Exact local commands, outcomes and durations
T(subject, case)expands toFM_TEST_ONLY=<case> 'C:/Program Files/Git/usr/bin/bash.exe' bin/fm-test-run.sh --jobs 1 tests/<subject>.test.sh.FULLomits FM_TEST_ONLY.All commands run through the existing bounded controller and
fm-timeout-lib.sh; the differential alone uses the detached frozen-upstream root.S:Iinventories only; it never executes a full suite:Preflight-only invocation: 16239 ms, exit 75; no planned gate was executed or credited.
Declared unique prerequisite commands are below.
The controller stops probing a check at its first failure, so the package-path probe after the missing tsc was not executed.
Successful probes are capability evidence only, never test passes:
Sbin/fm-lint.shbin/fm-doc-audience-check.shbin/fm-test-run.sh --check-coverageIbin/fm-lint.sh bin/fm-spawn.sh bin/fm-bootstrap.sh bin/fm-pr-lib.sh bin/fm-crew-state.sh bin/fm-teardown.sh bin/backends/tmux.sh bin/backends/orca.sh tests/fm-pi-primary-types.test.sh tests/fm-test-run.test.shbin/fm-test-run.sh --check-coverageIT(fm-test-run, test_calm_mod_and_sprite_select_all_consumers)T(fm-test-catalog, FULL)T(fm-calm-claude-mod, FULL)T(fm-pi-primary-types, FULL)T(fm-calm-claude-mod, FULL)T(fm-calm-claude-mod, FULL) [detached frozen upstream]T(fm-harness-contract, FULL)T(fm-spawn-dispatch-profile, test_codex_threads_model_and_max_effort)T(fm-spawn-dispatch-profile, test_copilot_threads_model_effort_and_hooks)T(fm-inactive-reconcile, test_reconciliation_sets_no_forge_mode_for_state_read)T(fm-startup-performance, FULL)T(fm-test-run, test_calm_mod_and_sprite_select_all_consumers)T(fm-pr-local-cost, FULL)T(fm-control-relaunch, test_failed_pilot_publication_retires_replacement_wiring)bin/fm-doc-audience-check.shPlans, per-invocation logs/results, frozen side versions, manifests, sample provenance and the budget ledger are retained outside the repository at
C:/src/.fm-reconcile-runs/2026-09-16T1315Z.No task evidence or private fleet material is committed.
No-renames divergence and locality audit
The incoming source manifest has 74 paths; the runner returns to unchanged fork bytes, and four explicit integration paths (both catalogs, runner regression and fork fixture guidance) yield 77 committed paths.
The staged and committed path sets match the final NUL-delimited manifest, SHA-256 01d29652c6712b312742192aede3300addd8e9523ef46c3b8d01293f6200c899; no file mode drift or broad line-ending renormalization occurred.
All 21 PR additions originate in frozen upstream; this run introduces no new fork-only implementation module.
43 incoming paths are byte/mode-equivalent to frozen upstream: 22 existing paths and 21 additions.
The other 31 incoming paths compose retained fork behavior, registry/fixture integration or intentionally retained spawn formatting.
The 67 additive fork paths and two intentional policy deletions remain 67 and two; the 288-to-245 reduction recovers upstream changes, not supposedly deleted fork behavior.
No rename detection was used to hide relocation.
The shared Calm geometry moves to its canonical Claude-owned sprite and is reached by Pi's tracked symlink; that is a shared implementation, not vanished code.
The mod-local operational-input port remains upstream's physical-import-boundary exception with parity coverage, while signed-Pi rendering/static remote-doctor facts remain deliberate legacy/integrity exceptions.
Reproduce inventories and retained caller hunks:
The 22 existing paths now equivalent to frozen upstream (all 21 additions are also equivalent)
Workflow/catalog/runner/proof comparison
Both automatic workflows, the manual Windows experiment, catalog loader, behavior runner and concurrency proof owner retain frozen-fork bytes.
The complete shared-path diff against frozen upstream and fork-only owner comparison were audited together; upstream's absence of fork modules is not deletion evidence.
Only catalog metadata/coverage hints and the documented upstream-versus-fork admission distinction change on that verification surface.
Complete changed-script routing
Every selected script has one existing primary Linux producer below; each entry expands to
tests/<name>.test.sh.Untagged entries are CI-only to preserve the bounded local plan; tagged local cases do not replace their complete CI script.
Real Herdr uses its dedicated isolated backend job; optional/live subjects remain gated and any absent capable vendor runner is disclosed above.
Native Windows, stock macOS and pinned-package coverage additionally retain their producers listed above.
All 194 selected scripts, individual CI owners and local dispositions
CI / Behavior portable serial 3 (34)
CI / Behavior portable serial 4 (33)
CI / Behavior tests (Herdr) (16)
CI / Behavior portable serial 1 (27)
CI / Behavior portable parallel 2 (13)
CI / Behavior portable serial 2 (28)
CI / Behavior portable serial 5 (32)
CI / Behavior portable parallel 1 (11)
Exact-head CI handoff
The live-check follow-up reports pending, successful, failed or absent status for this exact head and verifies unique producers.
A previous head's green result, required skip/cancellation, historical vendor transcript or local mock is not merge-readiness evidence.
This PR is intentionally opened before broad CI completes and remains unmerged.