Skip to content

feat(bin): renew fork from upstream through f66be0f8 - #19

Merged
sanis merged 12 commits into
mainfrom
fm/fm-upstream-sync-9
Aug 29, 2026
Merged

feat(bin): renew fork from upstream through f66be0f8#19
sanis merged 12 commits into
mainfrom
fm/fm-upstream-sync-9

Conversation

@sanis

@sanis sanis commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Intent

Renew this fork from upstream: merge upstream/main into our main so the fork carries upstream's latest work without losing any of our own.

Starting position: upstream is https://github.com/kunchenguid/firstmate; origin is our fork sanis/firstmate. Merge base is 10b93b2c (the previous renewal, fm-upstream-sync-8). Our main was 59 commits ahead and 9 behind. The nine commits to bring in, newest first: f66be0f8 fix(pi): restore Pi 0.84.4 renderer compatibility (kunchenguid#3261); 52b59a13 fix(pi): gate first provider call on startup context (kunchenguid#3158); a3906593 feat(bin): publish per-home summary ledgers (kunchenguid#3222); 42072140 fix(bin): accelerate and bound changed test runs (kunchenguid#3250); 1fd7ea28 feat(bin): add concurrent bounded remote transport lanes (kunchenguid#3210); c651b590 fix(pi): surface requested outcomes without replaying fleet events (kunchenguid#3211); bca584a8 fix(bin): prioritize active pipeline-owned crew runs (kunchenguid#3194); 4f89f5b5 fix(pi): prevent duplicate captain outcome reports (kunchenguid#3184); 7ee0c192 fix(bin): verify the real GitHub merge outcome instead of reporting an unproved merge (kunchenguid#3064). 62 files, roughly 6800 insertions.

REAL CONFLICTS WERE EXPECTED in the fourteen files touched by BOTH sides since 10b93b2c, with this specific guidance:

  • bin/fm-test-run.sh + tests/fm-test-run.test.sh - the sharpest collision. Our fork landed 4a39aa0f fix(bin): rebalance portable-serial shard weights after the upstream merge, a deliberate re-tuning of shard balance for THIS home. Upstream lands 42072140 (accelerate and bound changed test runs) and a3906593 (per-home summary ledgers) in the same file. Upstream is changing how runs are selected and bounded; we changed how work is distributed across shards. Read both sides fully before resolving a single hunk - our weights are NOT stale noise to be overwritten by upstream's newer file.
  • bin/fm-pr-merge.sh - upstream 7ee0c192 reworks merge-outcome verification so a merge is not reported until it is proved. Our fork carries 0988f74f feat(bin): refuse a request whose description delivers evidence as a local path (feat(bin): refuse a request whose description delivers evidence as a local path #8). Both sides are correctness work on the same path; BOTH must survive.
  • bin/fm-remote-job-worker.sh + tests/fm-remote-job.test.sh - upstream 1fd7ea28 adds concurrent bounded transport lanes. Make sure the new lane concurrency composes with the earlier upstream work already there rather than half-replacing it.
  • AGENTS.md, CONTRIBUTING.md, docs/architecture.md, docs/configuration.md, docs/scripts.md, docs/gitlab-merge-watch.md, docs/verification/runtime-backends.md - our fork has its own documented divergences here, including 08ba9045 (bearings mismatch classification and parallel shard balance evidence) and 7c04bf26 (away daemon no longer blocking its own delivery, PR fix(bin): stop the away daemon from blocking its own delivery #16). Upstream documents its four new behaviours in the same sections. Merge the prose; do NOT let upstream's section wholesale replace a paragraph that documents OUR behaviour.
  • tests/fm-public-followup.test.sh, tests/fm-tool-update-check.test.sh - smaller, but both sides edited them.

REQUIREMENTS:

  1. git fetch upstream, then merge upstream/main into the branch.
  2. Resolve every conflict so BOTH sides survive: upstream's fix keeps working AND our fork's behaviour keeps working. Neither side is automatically right. Before resolving a hunk, read what each side was fixing via git log --oneline 10b93b2c..upstream/main -- <file> and git log --oneline 10b93b2c..main -- <file>. Where our fork deliberately diverged, keep our version and make upstream's fix work alongside it. A divergence whose deliberateness cannot be determined is an escalation, never a coin flip - five questions are preferable to one silent revert.
  3. The merge commit's first line must be exactly: Merge upstream/main: fork renewal (9 commits through f66be0f8).
  4. Do NOT squash, rebase our 59 commits, or rewrite history. This is a merge.
  5. Do NOT "clean up" or reformat anything beyond what conflict resolution genuinely requires.

VERIFICATION REQUIRED: git log --oneline main..upstream/main shows nothing left to bring in; run the suites covering every file resolved by hand plus the ones upstream touched, with tests/fm-test-run.test.sh, tests/fm-remote-job.test.sh, tests/fm-public-followup.test.sh and tests/fm-tool-update-check.test.sh all directly in scope; every shell file touched is shellcheck-clean; for each conflicted file read git diff upstream/main...HEAD -- <file> and confirm it reads as our fork's intentional divergence with no accidental revert of an upstream fix and no accidental loss of ours; and sanity-check the shard rebalance specifically, confirming the portable-serial shard weights 4a39aa0f set are still the effective ones and that upstream's new bounding still applies on top.

OPERATIONAL CONSTRAINTS: always pass --repo sanis/firstmate to gh-axi, because without it gh-axi resolves to UPSTREAM and confidently answers about the wrong repository (our fork has ~19 PRs; upstream is in the 3000s, so a four-digit PR number means the wrong place). Keep any evidence in the PR description free of absolute machine paths; the evidence check refuses them and they are meaningless to a reviewer on another machine.

ACCEPTANCE: the branch merges upstream cleanly into our history, both sides' behaviour is intact and evidenced by passing tests, and nothing outside conflict resolution changed.

WHAT WAS DELIVERED AND THE DECISIONS MADE (deliberate; not accidents in the diff):

  • Three files conflicted; eleven auto-merged and were each reviewed hunk by hunk against both sides.
  • bin/fm-pr-merge.sh: upstream moved the PR metadata recording into a new record_pr_metadata() and gates every reported merge on a proved outcome. Our 0988f74f passes --no-description-check on that same call, because the description's local-path guard belongs to the ready report and refusing at merge time would block a merge the captain already authorized. Kept upstream's function and call site and carried our flag plus its reason into it. The file's ONLY divergence from upstream is now that one intentional change.
  • tests/fm-test-run.test.sh: kept upstream's three new tests AND our prose-selection test. Upstream's empty-selection case used a README.md edit, which is no longer an empty selection in this fork because we map every tracked prose path to the documentation-audiences family; it now uses the .gitignore trigger our fork already introduced, keeping upstream's rewritten duration and budget assertions intact. Our side also re-added fm-documentation-audiences.test.sh to the fixture list where upstream had already added it higher up, so upstream's placement was taken rather than duplicating the entry.
  • tests/fm-tool-update-check.test.sh: both sides independently de-flaked the SAME whole-second budget granularity, ours with a 3s budget plus a pinned probe and upstream with 2s. Kept ours as the wider margin and the one this fork's own CI validated, and kept upstream's sharper statement of the root cause.
  • bin/fm-test-run.sh auto-merged cleanly: upstream never touched portable_serial_weight_hints, so all 133 of 4a39aa0f's hint lines are byte-identical and still the effective ones. Upstream's two new serial scripts land on the PORTABLE_SERIAL_DEFAULT_WEIGHT_MS default and the bin-packer absorbs them at roughly 820s per shard against the 20-minute cap. Upstream's new --list-scheduled ordering demonstrably reads our hints and its --max-wall-ms bounding works on top.
  • tests/fm-public-followup.test.sh needed one reconciliation BEYOND the textual merge, and this is a deliberate decision rather than an unrequested change: the two sides fixed the same wall-time flakiness with opposite strategies - upstream pinned the suite clock to a fixed instant PF_TEST_NOW, while our 9b15dcfd anchored the fixture window to the wall clock at seed time. The literal merge passed its tests but left received_at five days ahead of the tool's pinned clock and drifting one further day every day, which is exactly the time bomb both commits existed to remove. Both seed helpers now derive the window from PF_TEST_NOW, which satisfies each side's stated intent; the published SEED_*_EXPIRES_AT/_EPOCH variables our fork added are retained.
  • docs/fm-test-portable-shards.md is the one-owner of the shard table and the merge invalidated the numbers it records, so its counts, sums, imbalance and provenance were corrected to the merged lanes and the stale claim that the table "records every script the lanes select" was replaced with an accurate one naming the two newly merged scripts that carry the default weight. The weight hints themselves were deliberately NOT invented; refreshing them needs timing artifacts from a green CI run of this merged tree.

EVIDENCE ALREADY GATHERED: 23 suites covering every resolved file and every file upstream touched pass with failed=0; bin/fm-test-run.sh --check-coverage passes (171 total, 24 parallel, 135 serial across 4 shards, 12 herdr); bin/fm-lint.sh exits 0 (ShellCheck 0.11.0 pinned, actionlint 1.7.12 pinned). The three gate skips are Pi-not-installed environment gates on this machine, so the two Pi commits in this renewal (f66be0f8, 52b59a13) are first exercised in CI. The merge commit is a true two-parent merge (697c1208 and f66be0f8), HEAD..upstream/main is empty, and 63 files changed: upstream's 62 plus the one shard-table doc correction.

What Changed

  • Merged upstream/main (9 commits, 7ee0c192..f66be0f8) into the fork as a true two-parent merge: per-home summary ledgers (new bin/fm-home-summary-refresh.sh plus its suite), concurrent bounded remote transport lanes in bin/fm-remote-job-worker.sh/bin/fm-remote-job-lib.sh, proved GitHub merge-outcome verification in bin/fm-pr-merge.sh, accelerated and wall-bounded changed-test selection in bin/fm-test-run.sh, pipeline-owned crew-run prioritization in bin/fm-crew-state.sh, and the Pi supervision/renderer fixes across .pi/extensions/ (including the new lib/fm-sessionstart-supervisor.mjs), with their tests and docs.
  • Resolved the collisions so both sides survive: bin/fm-pr-merge.sh keeps upstream's record_pr_metadata() gate while carrying the fork's --no-description-check flag and its reason; bin/fm-test-run.sh keeps the fork's portable_serial_weight_hints as the effective weights with upstream's new bounding layered on top; tests/fm-test-run.test.sh keeps upstream's three new cases alongside the fork's prose-selection test, re-pointing upstream's empty-selection case at the .gitignore trigger since prose paths now map to a test family; tests/fm-tool-update-check.test.sh keeps the fork's wider 3s budget with upstream's sharper root-cause note.
  • Follow-ups on top of the merge: tests/fm-public-followup.test.sh now exports PF_TEST_NOW so both seed helpers derive their fixture windows from the pinned clock instead of wall time (removing the received_at drift the literal merge left behind), and docs/fm-test-portable-shards.md was corrected to the merged lanes — counts, sums, imbalance, provenance, and the per-shard timeout rationale.

Risk Assessment

✅ Low: The merge preserves every fork divergence in all 14 both-touched files (weight hints byte-identical, --no-description-check the sole fm-pr-merge.sh divergence, fork doc paragraphs intact), the fix round's suite-wide clock pin provably closes the prune path it targeted without introducing a mixed-clock or variable-leak regression, and the one changed doc's shard numbers plus the coverage guard were independently recomputed and matched exactly.

Testing

I exercised the four suites the intent puts directly in scope (fm-public-followup, fm-test-run, fm-remote-job, fm-tool-update-check) plus fm-pr-merge, fm-pr-description-guard, fm-remote-transport-lanes, fm-home-summary-refresh and fm-documentation-audiences to cover the remaining hand-resolved files and the upstream features landing in them; every one passed. Beyond pass/fail I gathered behavioural evidence that both sides survived: the merged bin/fm-pr-merge.sh differs from upstream's tip by exactly the fork's --no-description-check hunk while upstream's proved-merge assertions and the fork's "records metadata without re-litigating the description" assertion both pass; the tool's own scheduler shows 4a39aa0's serial weights are the effective ones (34/34/34/33 shards matching docs/fm-test-portable-shards.md, longest measured scripts heading shards 1 and 2) and upstream's --max-wall-ms bounding refuses on a 1 ms budget and passes on a generous one over the same run; and HEAD..f66be0f is empty with all nine upstream commits ancestors of HEAD. For the pinned-clock review commit I ran a wall-clock probe (PATH-shadowed date logging every "now" query) against HEAD and against the pre-fix suite: fm-x-poll.sh's prune path dropped from 3 real-clock reads to 0 and fm-public-followup.sh's pending expiry comparison from 1 to 0, and the suite passes unchanged with the machine clock shifted a year forward. No screenshot or rendered-HTML artifact applies: this change touches shell tooling and test fixtures with no UI, browser, or rendered surface, so the reviewer-visible evidence is CLI transcripts and probe output. The three Pi commits' gates remain environment-skipped here, so those two Pi fixes are first exercised in CI, as the author already noted. Worktree is clean, no transient files left behind.

Evidence: Upstream divergence for every hand-resolved file (bin/fm-pr-merge.sh is one intentional hunk)

Source: Upstream divergence for every hand-resolved file (bin/fm-pr-merge.sh is one intentional hunk)

$ git diff f66be0f8...HEAD -- bin/fm-pr-merge.sh +# Records canonical PR metadata only. The description's local-path guard belongs +# to the ready report, so refusing here would block a merge the captain has +# already authorized. record_pr_metadata() { - if ! "$SCRIPT_DIR/fm-pr-check.sh" "$ID" "$URL"; then + if ! "$SCRIPT_DIR/fm-pr-check.sh" --no-description-check "$ID" "$URL"; then portable_serial_weight_hints() vs 4a39aa0f: byte-for-byte identical (137 lines)

# Divergence from upstream tip f66be0f8 for the hand-resolved files

$ git diff f66be0f8...HEAD --stat -- <hand-resolved files>
 AGENTS.md                             |   5 +
 CONTRIBUTING.md                       |  10 +-
 bin/fm-pr-merge.sh                    |   5 +-
 bin/fm-remote-job-worker.sh           |  19 +++
 bin/fm-test-run.sh                    | 277 +++++++++++++++++++---------------
 docs/architecture.md                  |   7 +-
 docs/configuration.md                 |   1 +
 docs/fm-test-portable-shards.md       |  59 +++-----
 docs/gitlab-merge-watch.md            |  27 +++-
 docs/scripts.md                       |   2 +
 docs/verification/runtime-backends.md |  44 ++++++
 tests/fm-public-followup.test.sh      |  73 +++++++--
 tests/fm-remote-job.test.sh           |  22 +++
 tests/fm-test-run.test.sh             |  52 ++++++-
 tests/fm-tool-update-check.test.sh    |  12 +-
 15 files changed, 424 insertions(+), 191 deletions(-)

## bin/fm-pr-merge.sh - the only divergence is the fork's authorized-merge flag
diff --git a/bin/fm-pr-merge.sh b/bin/fm-pr-merge.sh
index 3e61b33..efb0ded 100755
--- a/bin/fm-pr-merge.sh
+++ b/bin/fm-pr-merge.sh
@@ -492,8 +492,11 @@ METHODS
   fi
 }
 
+# Records canonical PR metadata only. The description's local-path guard belongs
+# to the ready report, so refusing here would block a merge the captain has
+# already authorized.
 record_pr_metadata() {
-  if ! "$SCRIPT_DIR/fm-pr-check.sh" "$ID" "$URL"; then
+  if ! "$SCRIPT_DIR/fm-pr-check.sh" --no-description-check "$ID" "$URL"; then
     return 1
   fi
   grep -qxF "pr=$URL" "$META" || {

## bin/fm-test-run.sh - upstream's file plus the fork's serial weight table
 bin/fm-test-run.sh | 277 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 156 insertions(+), 121 deletions(-)
portable_serial_weight_hints() vs 4a39aa0f: byte-for-byte identical (137 lines)
Evidence: Shard rebalance sanity: fork weights still effective after the merge

Source: Shard rebalance sanity: fork weights still effective after the merge

$ bin/fm-test-run.sh --check-coverage FM_TEST_COVERAGE ok total=171 parallel=24 serial=135 serial_shards=4 herdr=12 $ bin/fm-test-run.sh --list-scheduled --lane portable-serial-1of4 # 34 scripts tests/fm-pr-check-security.test.sh tests/fm-remote-reply.test.sh tests/fm-watch-arm.test.sh $ bin/fm-test-run.sh --list-scheduled --lane portable-serial-2of4 # 34 scripts tests/fm-public-followup.test.sh tests/fm-teardown.test.sh tests/fm-remote-backlog-handoff.test.sh docs/fm-test-portable-shards.md records 34/34/34/33 - the tool schedules 34/34/34/33.

# Shard rebalance sanity after the renewal

$ bin/fm-test-run.sh --check-coverage
FM_TEST_COVERAGE ok total=171 parallel=24 serial=135 serial_shards=4 herdr=12

Shard sizes and the first three scripts each shard schedules (longest hint first):

$ bin/fm-test-run.sh --list-scheduled --lane portable-serial-1of4   # 34 scripts
tests/fm-pr-check-security.test.sh
tests/fm-remote-reply.test.sh
tests/fm-watch-arm.test.sh

$ bin/fm-test-run.sh --list-scheduled --lane portable-serial-2of4   # 34 scripts
tests/fm-public-followup.test.sh
tests/fm-teardown.test.sh
tests/fm-remote-backlog-handoff.test.sh

$ bin/fm-test-run.sh --list-scheduled --lane portable-serial-3of4   # 34 scripts
tests/fm-remote-secondmate-lifecycle-e2e.test.sh
tests/fm-secondmate-harness.test.sh
tests/fm-watcher-lock.test.sh

$ bin/fm-test-run.sh --list-scheduled --lane portable-serial-4of4   # 33 scripts
tests/fm-watch-triage.test.sh
tests/fm-session-start.test.sh
tests/fm-daemon.test.sh

docs/fm-test-portable-shards.md records 34/34/34/33 - the tool schedules 34/34/34/33.
Shard 1 opens with tests/fm-pr-check-security.test.sh, the 233979 ms script the
doc names as the floor for any shard count, and shard 2 with the 180863 ms
tests/fm-public-followup.test.sh: the fork's measured hints, not the default
weight, are what the bin packer is reading.
Evidence: Upstream's --max-wall-ms bounding working on top of the merged runner

Source: Upstream's --max-wall-ms bounding working on top of the merged runner

$ bin/fm-test-run.sh --max-wall-ms 1 tests/fm-lint-workflows.test.sh FM_TEST_SUMMARY total=1 failed=0 skipped_gate=0 duration_ms=18001 FM_TEST_BUDGET max_wall_ms=1 duration_ms=18001 fm-test-run: wall-clock budget exceeded: 18001ms > 1ms for scripts exit=1 $ bin/fm-test-run.sh --max-wall-ms 600000 tests/fm-lint-workflows.test.sh FM_TEST_SUMMARY total=1 failed=0 skipped_gate=0 duration_ms=13805 FM_TEST_BUDGET max_wall_ms=600000 duration_ms=13805 exit=0

$ bin/fm-test-run.sh --max-wall-ms 1 tests/fm-lint-workflows.test.sh   # upstream 42072140 bounding, tight budget
FM_TEST_BEGIN 2026-08-29T14:31:32Z tests/fm-lint-workflows.test.sh family=pure-contract-unit expected_gate_skip=none
ok - fm-lint-workflows.sh pins an explicit actionlint version (1.7.12)
ok - current .github/workflows YAML files parse
ok - column-0 heredoc workflow fails validation with a clear error
ok - valid fixture workflow passes
ok - empty workflows directory fails closed
ok - explicit malformed workflow path fails validation
ok - non-mapping workflow YAML root fails
ok - missing actionlint fails closed
ok - fm-lint-workflows.sh refuses to lint under a non-pinned actionlint version
ok - actionlint installer retries a transient download failure
ok - actionlint installer selects the official archive, URL, and checksum per OS/arch
ok - actionlint installer rejects a wrong checksum
ok - actionlint installer falls back to shasum -a 256 when sha256sum is absent
ok - actionlint installer prefers sha256sum when both hashers are present
ok - actionlint installer rejects an unsupported OS or architecture
ok - fm-lint.sh default path catches a self-broken ci.yml
FM_TEST_END 2026-08-29T14:31:50Z tests/fm-lint-workflows.test.sh exit=0 duration_ms=17888 gate_skip=false
FM_TEST_SUMMARY total=1 failed=0 skipped_gate=0 duration_ms=18001
FM_TEST_SUMMARY_FAMILY family=pure-contract-unit count=1 duration_ms=17888 failed=0
FM_TEST_SLOWEST rank=1 script=tests/fm-lint-workflows.test.sh duration_ms=17888
FM_TEST_BUDGET max_wall_ms=1 duration_ms=18001
fm-test-run: wall-clock budget exceeded: 18001ms > 1ms for scripts
exit=1

$ bin/fm-test-run.sh --max-wall-ms 600000 tests/fm-lint-workflows.test.sh  # same run, generous budget
FM_TEST_BEGIN 2026-08-29T14:31:50Z tests/fm-lint-workflows.test.sh family=pure-contract-unit expected_gate_skip=none
ok - fm-lint-workflows.sh pins an explicit actionlint version (1.7.12)
ok - current .github/workflows YAML files parse
ok - column-0 heredoc workflow fails validation with a clear error
ok - valid fixture workflow passes
ok - empty workflows directory fails closed
ok - explicit malformed workflow path fails validation
ok - non-mapping workflow YAML root fails
ok - missing actionlint fails closed
ok - fm-lint-workflows.sh refuses to lint under a non-pinned actionlint version
ok - actionlint installer retries a transient download failure
ok - actionlint installer selects the official archive, URL, and checksum per OS/arch
ok - actionlint installer rejects a wrong checksum
ok - actionlint installer falls back to shasum -a 256 when sha256sum is absent
ok - actionlint installer prefers sha256sum when both hashers are present
ok - actionlint installer rejects an unsupported OS or architecture
ok - fm-lint.sh default path catches a self-broken ci.yml
FM_TEST_END 2026-08-29T14:32:04Z tests/fm-lint-workflows.test.sh exit=0 duration_ms=13707 gate_skip=false
FM_TEST_SUMMARY total=1 failed=0 skipped_gate=0 duration_ms=13805
FM_TEST_SUMMARY_FAMILY family=pure-contract-unit count=1 duration_ms=13707 failed=0
FM_TEST_SLOWEST rank=1 script=tests/fm-lint-workflows.test.sh duration_ms=13707
FM_TEST_BUDGET max_wall_ms=600000 duration_ms=13805
exit=0
Evidence: Wall-clock probe: which commands still read the real clock, before vs after the pin

Source: Wall-clock probe: which commands still read the real clock, before vs after the pin

## BEFORE (suite as of ec645f2) ## AFTER (HEAD f4b03b0) 3 bin/fm-x-poll.sh (none) 1 bin/fm-public-followup.sh pending (none) 6 bin/fm-inactive-reconcile.sh 6 bin/fm-inactive-reconcile.sh 8 bin/fm-startup-network.sh 8 bin/fm-startup-network.sh 3 bin/fm-public-followup.sh deliver 3 bin/fm-public-followup.sh deliver Both runs: 52 ok, exit 0. fm-x-poll.sh's prune path (max_age 604800) now runs at the same pinned instant the fixture window is seeded from.

# Wall-clock probe: which commands in tests/fm-public-followup.test.sh still read the real clock

Method: a PATH-shadowed `date` that logs the caller of every bare
"what time is it now" query (`date +%s` / `date -u +%s`) and then answers it
normally. Timestamp *parsing* (date -j -f ... +%s) is left untouched.
Both runs passed (52 ok, exit 0); only the clock reads differ.

## BEFORE (suite as of ec645f2, only run_pf and two registry calls pinned)
   6 bash <repo>/bin/fm-inactive-reconcile.sh _scan-locked 1
   4 bash <repo>/bin/fm-startup-network.sh start --locked 1 --harvest-pid <pid>
   4 bash <repo>/bin/fm-startup-network.sh run --locked 1 --lock-pid <pid> --generation <gen>
   3 bash <repo>/bin/fm-x-poll.sh
   1 bash tests/zz-pf-baseline-premerge-fix.sh
   1 bash <repo>/bin/fm-public-followup.sh pending
   1 bash <repo>/bin/fm-public-followup.sh deliver pf-retry
   1 bash <repo>/bin/fm-public-followup.sh deliver pf-late
   1 bash <repo>/bin/fm-public-followup.sh deliver pf-dry

## AFTER (HEAD f4b03b0, FMX_NOW_OVERRIDE exported over the whole suite)
   6 bash <repo>/bin/fm-inactive-reconcile.sh _scan-locked 1
   4 bash <repo>/bin/fm-startup-network.sh start --locked 1 --harvest-pid <pid>
   4 bash <repo>/bin/fm-startup-network.sh run --locked 1 --lock-pid <pid> --generation <gen>
   1 bash tests/fm-public-followup.test.sh
   1 bash <repo>/bin/fm-public-followup.sh deliver pf-retry
   1 bash <repo>/bin/fm-public-followup.sh deliver pf-late
   1 bash <repo>/bin/fm-public-followup.sh deliver pf-dry

## Reading
bin/fm-x-poll.sh went from 3 wall-clock reads to 0. That is the prune path
(fmx_context_registry_prune, max_age 604800) the review finding named: it now
runs at the same pinned instant the fixture window is seeded from, so the
seeded x-context entry can never age out from under the suite.
bin/fm-public-followup.sh went from 4 reads to 3, and the one that disappeared
is the `pending` expiry comparison - the one that decides whether the seeded
window is still reachable. The three that remain are all `deliver` calls landing
in next_attempt_rfc3339(), a pre-existing raw `date +%s` that only stamps an
advisory "try again at" time on a retryable transport error; no assertion in the
suite reads it and nothing about the fixture window depends on it.
The other reads that remain are session-start's detached background helpers
(fm-startup-network.sh, fm-inactive-reconcile.sh), which stamp their own lock
generations with a raw date and never touch the seeded follow-up window, plus
one read by the test harness itself.
Evidence: Suite logs for the nine targeted suites (all exit 0)
suite-fm-test-run.log exit=0
suite-fm-remote-job.log exit=0
suite-fm-tool-update-check.log exit=0
suite-fm-pr-merge.log exit=0 (61 ok)
suite-fm-pr-description-guard.log exit=0 (23 ok)
suite-fm-remote-transport-lanes.log exit=0
suite-fm-home-summary-refresh.log exit=0
suite-fm-documentation-audiences.log exit=0
clock-shim-head.log exit=0 (suite under a +1y machine clock)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 info
  • ⚠️ tests/fm-public-followup.test.sh:26 - PF_TEST_NOW=1787539200 is a fixed past instant (2026-08-24T02:40:00Z), and the new comments on both seed helpers justify deriving the fixture window from it by asserting "every command here already runs at PF_TEST_NOW". That premise is false: only run_pf (line 108) and the two fmx_context_registry_set calls (lines 169, 215) pin the clock. $POLL, $SESSION_START, $TEARDOWN, $PROMOTE, $EMIT and tasks_in all still run at the wall clock. The seeded thread window is therefore PF_TEST_NOW + 7d = 2026-08-31T02:40Z — a fixed calendar date again from those paths' point of view, which is the exact time-bomb shape 9b15dcfd and upstream's PF_TEST_NOW both existed to remove, just drifting in the opposite direction (the window ages away from the wall clock instead of away from the pinned clock). Concretely reachable: bin/fm-x-poll.sh:105 calls fmx_context_registry_prune at the wall clock with max_age=604800, so from 2026-08-31 the $POLL invocations in the relay-poll test delete the seeded state/x-context/&lt;request&gt;.json whose recorded_at is PF_TEST_NOW. I traced every assertion in this suite and none currently depends on that file or on a live window under a wall-clock command, so no test fails today — this is latent fixture drift, not a present failure. PF_TEST_NOW=$(date -u +%s) satisfies both sides' stated intent fully: one clock for the whole suite (upstream's requirement) and a window that is always live (this fork's requirement). Nothing in the suite needs the literal 1787539200 — the one place that hard-coded it (test_rechain_claims_delivered_source_once) was already changed to derive from SEED_REPRO_EXPIRES_EPOCH. Flagging rather than fixing because the intent names this reconciliation as a deliberate decision.

🔧 Fix: pin whole public-followup suite to one clock
1 info still open:

  • ℹ️ tests/fm-public-followup.test.sh:113 - Now that export FMX_NOW_OVERRIDE=&#34;$PF_TEST_NOW&#34; (line 31) covers the whole suite, three explicit clock prefixes are unreachable/redundant: ${FMX_NOW_OVERRIDE:-$PF_TEST_NOW} in run_pf (line 113) can never take its :- branch, and FMX_NOW_OVERRIDE=&#34;$PF_TEST_NOW&#34; on the two fmx_context_registry_set calls (lines 174 and 220) restate the exported value. They are harmless — I confirmed on bash 5.3 and bash 3.2 that a temporary assignment before a shell function is restored afterwards, so the deliberate per-test overrides at lines 1614/1618/2064/2076/2080/2083 still win and do not leak — but they now read as if those three call sites were special when every other command in the suite inherits the same clock silently. Dropping them (or keeping only the run_pf default as documented defensiveness) would make the one-clock invariant single-sourced. No behavioral effect either way; listed only because simplification is in review scope.
✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-public-followup.test.sh — 52 assertions, exit 0
  • bash tests/fm-test-run.test.sh — exit 0 (upstream's bounded/accelerated changed-run tests plus the fork's prose-selection test)
  • bash tests/fm-remote-job.test.sh — exit 0
  • bash tests/fm-tool-update-check.test.sh — exit 0
  • bash tests/fm-pr-merge.test.sh — 61 assertions, exit 0 (upstream 7ee0c192 proved-merge verification)
  • bash tests/fm-pr-description-guard.test.sh — 23 assertions, exit 0, incl. the merge path records metadata without re-litigating the description (fork 0988f74f)
  • bash tests/fm-remote-transport-lanes.test.sh — exit 0 (upstream 1fd7ea28)
  • bash tests/fm-home-summary-refresh.test.sh — exit 0 (upstream a3906593)
  • bash tests/fm-documentation-audiences.test.sh — exit 0 (hand-merged prose in AGENTS.md/CONTRIBUTING.md/docs)
  • Wall-clock probe: PATH-shadowed date logging every bare +%s query, run against HEAD's suite and against a copy of ec645f2's pre-fix suite; compared callers
  • Wall-clock independence: PATH=&lt;shim&gt;:$PATH bash tests/fm-public-followup.test.sh with the machine clock shifted +1 year — 52 ok, exit 0
  • bin/fm-test-run.sh --check-coverageFM_TEST_COVERAGE ok total=171 parallel=24 serial=135 serial_shards=4 herdr=12
  • bin/fm-test-run.sh --list-scheduled --lane portable-serial-{1,2,3,4}of4 and --list --lane ... for shard sizes
  • bin/fm-test-run.sh --max-wall-ms 1 tests/fm-lint-workflows.test.sh (exit 1, budget exceeded) vs --max-wall-ms 600000 (exit 0)
  • git log --oneline HEAD..f66be0f8 (empty) and git merge-base --is-ancestor for each of the nine upstream commits
  • git diff f66be0f8...HEAD -- bin/fm-pr-merge.sh (single intentional hunk) and diff of portable_serial_weight_hints() between 4a39aa0f and HEAD (identical, 137 lines)
⚠️ **Document** - 2 infos
  • ℹ️ AGENTS.md:92 - The merge adds state/home-summary.json plus .home-summary-refresh.log/.lock, which AGENTS.md's state/ inventory does not list. Left unchanged deliberately: I confirmed that inventory is already non-exhaustive (dozens of upstream-written state paths, e.g. .last-check, .branch-outcomes.lock, .inactive-outcome-reconcile*, are absent), and upstream placed this file's documentation at its owners instead - docs/architecture.md (publication triggers and mechanics), docs/configuration.md (FM_HOME_SUMMARY_* bounds) and docs/scripts.md (script row). Adding a fork-only line to a shared upstream file would duplicate an owned fact and create renewal friction. Raising it only so the placement call is visible.
  • ℹ️ docs/fm-test-portable-shards.md:45 - The two scripts this renewal added to the portable-serial lane still carry PORTABLE_SERIAL_DEFAULT_WEIGHT_MS rather than measured hints, so the shard balance is planned from an estimate for them. This cannot be resolved from the worktree: the refresh procedure in docs/fm-test-portable-shards.md requires fm-test-timing-portable-serial-* artifacts from a green CI run of this merged tree. The doc already names both scripts and the estimate; the follow-up is to re-run the documented refresh after the next green CI.
✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

wjkawecki-jt and others added 12 commits August 27, 2026 07:49
…n unproved merge (kunchenguid#3064)

* fix(pr): verify GitHub merge outcome

* no-mistakes(review): Captain, fixed forge-only merge verification, queue guidance, metadata propagation

* no-mistakes(document): Correct forge-specific merge documentation

* no-mistakes(review): Captain: forge-only queue fix, focused tests pass

* no-mistakes(review): Captain: suppress closed-state guidance and prove parent regression

* no-mistakes(review): Captain: remove history proof; retain executable regressions

* no-mistakes(document): Clarify GitHub recording timing in architecture docs

* no-mistakes(document): Clarify outcome-aware PR merge recording documentation

* no-mistakes: apply CI fixes

* Revert "no-mistakes: apply CI fixes"

This reverts commit c326cfa.

The automatic CI repair round removed the up-front `gh` prerequisite check
while keeping the `gh` dependency: `bin/fm-pr-merge.sh` still calls
`gh api graphql` for the outcome read and `gh api` for the branch-rules read.
That left the same hard requirement without the clear named error, and review
immediately raised a new finding for exactly the failure the check prevents -
`gh-axi pr merge` landing the merge while the follow-up read fails, so the PR
metadata is never recorded.

The check is also symmetric with the GitLab arm directly above it, which
already refuses up front when `glab` or `jq` is missing, on the stated
principle that a missing tool should be a named prerequisite rather than a
merge that is armed and then refused for an unexplained reason.

The workflows this round was chasing sit at `action_required` because this is
a fork pull request; no code change can turn them green.

* fix(pr): keep PR bookkeeping when a merge outcome read fails

On the GitHub path a merge call that returned success was followed by
`github_read_outcome || exit 1`, so a transient API failure, rate limit,
or network blip during the read dropped out of the script before
`record_pr_metadata` ever ran. The merge could have landed while `pr=`
went unrecorded and the merge poll was never armed - bookkeeping lost on
a real merge. The failure path just above already recorded metadata
before exiting, so the error path was more careful than the success one.

Record the PR before that refusal. Recording arms the later merge poll
and is not a success claim, which is the same reasoning that keeps
`record_pr_metadata` on the gh-axi failure path. The refusal itself is
unchanged: exit stays non-zero and the message still names the concrete
observed state. Metadata is withheld only when the read succeeds and
proves the pull request neither merged nor queued.

Pin it with a case that stubs `gh api graphql` into failure after a
successful `gh-axi pr merge`, asserting both the non-zero exit and the
recorded metadata.

* no-mistakes(review): Aggregate queue rules and report conflicts explicitly

* fix(pr): keep the merge abstraction reachable and its bookkeeping intact

Two holes remained in the outcome-verified GitHub merge path, both on
installations where gh-axi is present but gh is not.

The verification preflight refused before bin/fm-pr-merge.sh ever reached
the configured gh-axi merge abstraction, so an installation without gh
could no longer merge at all. gh-axi now performs the merge unconditionally
and the queue-aware gh read became an optional enrichment: with gh on PATH
its GraphQL view still separates merged from queued, and without gh the
gh-axi view still proves a landed merge while every outcome it cannot prove
refuses.

The PR metadata recording sat behind the outcome read, so a merge that
landed before that read failed lost pr= and its merge poll. Recording now
happens once, before either forge call, which arms the poll without
claiming a landed outcome and leaves teardown a PR identity to verify
against no matter how the read ends.

Rebasing onto main also restored the durable merge-outcome reporting and
the GitLab landed-state confirmation that the conflict resolution dropped.

Tests pin each fix through the executable interface: the merge abstraction
is reached and verified with gh absent, a failed fallback read keeps its
bookkeeping, and a mock that snapshots the task meta during the forge call
proves pr= is recorded before the merge can land.

* no-mistakes(review): fix(pr): de-dup queue methods, fall back on failed gh read, refresh contracts

* no-mistakes(review): fix(pr): quote forge output and explain armed auto-merge on refusal

* no-mistakes(review): fix(pr): claim auto-merge armed only when the forge accepted it

* no-mistakes(review): fix(pr): tell the operator what each GitHub refusal could not observe

* no-mistakes(review): fix(pr): gate every forge-acceptance claim on a successful merge

* no-mistakes(document): align merge docs with verified GitHub outcome contract
* fix(pi): stop reporting one merge to the captain twice

The supervision branch's captain-outcome note told main, unconditionally,
that the note "is not your own earlier output" and to relay it now. When
main had already reported the same event, that assertion was false and the
order turned the correct response - saying nothing new - into a mechanical
re-report, so the captain saw one merge reported twice in 16 seconds.

Two independent changes, both needed:

- The relay instruction is now conditional. It still names itself as a
  supervision outcome so main cannot mistake it for its own earlier answer
  (the silent loss that instruction exists to prevent), and it now lets
  main stay quiet about an outcome it has already given the captain.

- The merge case is closed at its source rather than left to that judgment.
  One merge reaches a home on two independent paths by design - main's own
  permanently main-owned merge poll, and the branch's task-local status
  wake - and main's captain-facing text only reaches the branch's mirror at
  main's turn end, so the branch can escalate before it could possibly see
  the captain was already told. bin/fm-pr-merge-notified.sh answers that
  question from bin/fm-pr-lib.sh's canonical merge-notification marker, so
  the answer holds regardless of mirror timing. A captain outcome naming an
  already-published merge is delivered as the ordinary rendered note
  instead of opening a follow-up turn: still appended, still visible, still
  recorded with the verdict the branch decided, minus the wasted turn.

Any error, timeout, or unreadable state relays the outcome. A duplicate
announces itself; a lost outcome does not.

Regression coverage drives the real delivery path in both directions: a new
outcome must still reach the captain in exactly one follow-up turn even
beside an unrelated published merge, and an already-published merge must
open no second turn while a different PR in the same task still does. The
merge path's real producer and this new consumer are exercised end to end
in tests/fm-pr-merge.test.sh.

Pi-only by construction: the delivery path lives in .pi/extensions, so no
other harness loads it, and the new script only reads existing markers.

* no-mistakes(review): Document accepted latest-marker suppression residual

* no-mistakes(review): Recheck ownership before merge outcome delivery

* no-mistakes(document): Document merge-outcome suppression exception

* refactor(pi): drop the source-level merge suppression, keep the envelope fix

The captain reviewed this branch and judged the source-level duplicate
suppression overly complicated for the problem it solved, and asked for
the change to be reduced to the envelope wording alone.

Remove the mergeIntoMain downgrade path, bin/fm-pr-merge-notified.sh, and
every test and document that existed only for it. What remains is the
conditional captain-outcome instruction: main is told to stay quiet about
an outcome it has already reported and to relay anything else, which
covers the duplicate without a second mechanism.

The silent-loss protection is untouched - the note is still typed,
self-describing, and delivered as one invisible follow-up turn - and the
behavioral tests still assert that, now requiring both halves of the
conditional instruction.

* no-mistakes(ci): Clarified in code comments and owned documentation that this is intentionally an M1-only, model-facing conditional relay fix—not source-level suppression—addressing Greptile’s mistaken scope expectation without changing runtime behavior. Net diff remains 3 files and 27 insertions. Verified with fm-pi-branch-extension tests, fm-lint, doc audience check, and git diff --check; all passed

* no-mistakes(ci): Strengthened the runtime delivery test to verify the captain outcome retains its required self-description and outcome text. Verified with `bash tests/fm-pi-branch-extension.test.sh`, `bin/fm-lint.sh`, `bin/fm-doc-audience-check.sh`, and `git diff --check`; all passed. The outer pipeline can now commit and attest the new head
* fix(bin): bind the live pipeline-owned run instead of a superseded failed row

fm-crew-state.sh bound a superseded FAILED no-mistakes run to a task instead
of the LIVE replacement run: the live run's pipeline-owned lane head is not a
git object in the task worktree, so head-equality attribution rejected it and
the coarse runs-list fallback silently continued past the RUNNING row onto an
older failed row whose head equalled the stale worktree HEAD. The home summary
then flipped invalid and Bearings hid the home's live work (F10).

Attribution precedence now follows the daemon's own identity:
- An ACTIVE run for the task's branch binds without head equality while
  branch_sync.state is pipeline_owned (fm_nm_run_is_pipeline_owned_active);
  the pipeline owning the branch is itself the attribution.
- A genuinely failed run with no later run on the branch still reports failed
  through the unchanged head-equality path - real failures are not hidden.
- In the coarse runs scan, an unresolvable head is unknown attribution and
  stops the scan (fm_nm_head_resolvable) instead of falling through to an
  older row; a resolvable-but-mismatched head keeps the historical
  reused-branch skip.

The exemption never applies to a terminal run and requires pipeline_owned
specifically, both pinned by negative-control tests. Fixture shape verified
against the live incident run's real axi status output.

* no-mistakes(document): Updated run-attribution documentation ownership
…unchenguid#3211)

* fix(pi): surface requested supervision outcomes

* no-mistakes(review): Mirror in-flight captain requests before branch dispatch

* no-mistakes(review): Exercise real branch ownership and main outcome access

* no-mistakes(review): Preserve request tails and align verdict guidance

* no-mistakes(review): Preserve complete current captain requests

* no-mistakes(review): Require visible requested outcomes and realistic classification

* no-mistakes(document): Align supervision outcome documentation

* no-mistakes(ci): Fixed Greptile’s runtime-ordering finding. The extension now stages Pi’s authoritative `before_agent_start` prompt before SessionManager persistence and suppresses the later duplicate entry. Updated docs and behavioral regression to reproduce real Pi ordering and verify each prompt is mirrored exactly once. Passed branch-extension tests, supervision tests, strict Pi typecheck, full lint, and diff checks

* no-mistakes(review): Use canonical operational input classification

* no-mistakes(review): Filter legacy operational inputs canonically

* no-mistakes(document): Clarify captain request mirroring boundary

* no-mistakes(ci): Fixed the CI time-boundary failure in tests/fm-public-followup.test.sh by pinning its clock, including context-registry setup. This prevents follow-up fixtures from expiring based on wall time. Verified the full regression suite passes, project-owned lint passes, and git diff checks are clean

* no-mistakes(document): Clarify captain-visible supervision outcome documentation
…#3210)

* feat(bin): per-home remote transport lanes with cancellation, bounded send, and closed stdin

All remote commands for every home on one host used to serialize through one
single-job-at-a-time worker on one shared queue: a timed-out caller abandoned a
staged job that kept running, retries convoyed behind it, fm-send's remote leg
had no time bound, and staging captured the caller's stdin to EOF so any
fm-on.sh caller with an open stdin wedged staging indefinitely.

- The worker now serves one lane per staged home: same-home jobs run strictly
  FIFO in a new staging-sequence order while different homes run concurrently,
  each lane as its own top-level worker process (a backgrounded subshell does
  not reliably reap dead children, so a zombie group leader kept a finished
  command's process group signalable). Long-poll preemption is lane-scoped.
- A caller that disconnects or times out cancels its job: the entrypoint marks
  the record on any post-staging exit and probes its parent so a dead ssh
  channel cancels without a signal; the worker skips cancelled queued jobs,
  terminates a running cancelled job's process group, and reaps the record.
- fm-send's remote leg is bounded by FM_SEND_REMOTE_BUDGET (default 30s) and a
  bound hit exits through the existing unconfirmed-delivery contract, which
  stays idempotent because the remote enqueue deduplicates.
- fm-on.sh defaults the remote command's stdin to /dev/null; the three payload
  callers pass the new --stdin flag. Abandoned .stage.* litter is age-reaped.
- The job execution deadline no longer loses up to a second to clock
  truncation.

* no-mistakes(review): Protect live stages and validate send budgets early

* no-mistakes(review): Preserve sequence lock ownership during stale recovery

* no-mistakes(review): Allocate job sequences at publication boundary

* no-mistakes(review): Bound remote keys and extend stale lock recovery

* no-mistakes(document): Document bounded remote transport behavior

* no-mistakes(lint): Suppress intentional deferred-expansion lint warning

* no-mistakes(ci): Fixed stale sequence-lock recovery by reconciling the counter against published job records before allocating the next sequence, preventing duplicate sequences and same-home FIFO violations. Added a behavioral regression test reproducing displacement after publication and verifying execution order. Passed fm-remote-transport-lanes.test.sh, fm-remote-job.test.sh, fm-lint.sh, and git diff --check

* no-mistakes(review): Use atomic sequence claims and lossless lane keys

* no-mistakes(review): Recover regressed sequence hints and rate-limit claim reaping

* no-mistakes(review): Restrict worker heartbeats to serving loop

* no-mistakes(review): Verify supervisor identity before lane recovery signals

* no-mistakes(review): Verify tracked lane and claim owner identities

* no-mistakes(document): Clarify remote lane and transport contracts

* no-mistakes(ci): Fixed the CI time-boundary failure by pinning fm-public-followup tests to a deterministic clock, including context-registry setup. Verified tests/fm-public-followup.test.sh, tests/fm-remote-transport-lanes.test.sh, shellcheck, and git diff --check

* no-mistakes(review): Preserve assigned lane ownership of queued jobs

* no-mistakes(review): Reserve homes owned by foreign queued lanes

* no-mistakes(review): Preserve completed results during crash recovery

* no-mistakes(review): Harden claim cleanup, expiry, and cancellation races

* no-mistakes(review): Verify process groups and reap abandoned results

* no-mistakes(review): Stop leaderless groups and reap cancelled publications

* no-mistakes(document): Correct remote transport lifecycle documentation

* no-mistakes(lint): Quote done state comparisons for ShellCheck
* fix(tests): make the changed-file map select per script and stabilize a budget flake

The changed-file map's bin/ fallback resolved a direct test reference to that
test's whole FAMILY. bin/fm-push-transition-lib.sh is named by exactly one
real-Herdr E2E, so a one-line change to it selected all 12 real-herdr-gated
scripts, including a 341s presentation E2E with no dependency on it.

Resolve direct test references per script, and keep resolving consumer bin/
scripts through the curated map so recorded family-level coupling survives.

Also fix a load-sensitive flake: the tool-update budget deadline is whole-second
granular, so a test budget of 1 left headroom anywhere in (0, 1] seconds and the
first budget check could already read as exhausted.

* feat(bin): make suite wall clock a result and let a family's concurrency be proven

--max-wall-ms fails a run whose wall clock exceeds the caller's budget, after
reporting the per-script results. A suite that stays green while outgrowing its
caller's invocation budget is the regression that got an agent killed mid-run
and retried invisibly, so duration has to be a result rather than a log note.

--pool on the isolation-proof harness runs the same concurrent proof over a
whole family, so 'is this family safe to parallelize?' is answered by a command
instead of a guess. Measured watcher-wake-lock and refused it: 3 of 18 scripts
fail under concurrency on wall-clock assertions about reaching the next poll.

* perf(bin): schedule the changed suite concurrently, longest first

The watcher-wake-lock family is proven concurrent-safe (two clean runs, 18
candidates, 0 failures at 4 workers; docs/fm-test-isolation-proof.md), so
--changed now schedules its proven-concurrent scripts with bounded parallelism
and runs any unproven remainder serially afterwards, never beside them.

Concurrent runs are ordered longest-hint-first. Workers are handed scripts in
order, so alphabetical order started the 193s fm-watch-triage last and stranded
it running alone: 395s wall against a 205s balanced four-worker sum.

An explicit --jobs keeps its strict refusal, so every CI lane is unchanged.

* fix(bin): bound a hung test instead of letting it hang the suite

tests/fm-calm-pi-extension.test.sh was observed running 17+ minutes against a
464ms recorded hint, and the suite had no per-script bound to stop it. An
unbounded suite is precisely what silently outruns a caller's invocation budget,
and --max-wall-ms is evaluated after the run so it cannot end one that never
finishes.

--per-script-timeout-secs terminates a script that outruns it and records exit
124, so the run still completes, accounts for the script, and fails. The
auto-concurrent --changed path applies 900s, far above the slowest real script
(the 341s Herdr presentation E2E), so it only ever converts a hang.

* no-mistakes(review): Enforce safe concurrency and descendant timeouts

* no-mistakes(review): Validate empty runs and isolation proof pools

* no-mistakes(review): Measure selection time in wall budget

* no-mistakes(review): Reap interrupted workers and bound finalization

* no-mistakes(review): Contain shutdown descendants and watchdog finalization

* no-mistakes(review): Honor remaining budget and close launch races

* no-mistakes(review): Restore timeout helper and simplify runner cleanup

* no-mistakes(review): Record isolation pool admission metadata

* no-mistakes(review): Bound Chrome reap and scope proof admission

* no-mistakes(review): Align proof scheduling and preserve budget summaries

* no-mistakes(review): Remove unreliable finalization watchdog

* no-mistakes(review): Freeze budget duration and enforce admission caps

* no-mistakes(document): Refresh test runner concurrency documentation

* no-mistakes(lint): Fix ShellCheck findings in test runner scripts

* no-mistakes(ci): Fixed Greptile’s concurrency-consent finding. `--changed` now remains serial by default; `--changed --jobs auto` explicitly opts into bounded concurrency and the automatic hang timeout. Updated documentation and added behavioral coverage proving serial default behavior, explicit concurrent scheduling, and refusal of `--jobs auto` outside `--changed`. Verified with `bash tests/fm-test-run.test.sh`, `bin/fm-lint.sh`, and `git diff --check`

* no-mistakes(review): Restore automatic changed-suite concurrency and timeout

* no-mistakes(review): Correct changed-suite contributor guidance

* no-mistakes(review): Reject gate-skipped isolation proofs

* no-mistakes(review): Correct automatic concurrency evidence

* no-mistakes(review): Isolate nested runner process groups

* no-mistakes(review): Remove unreliable signal cleanup machinery

* no-mistakes(test): Narrow changed-suite selection to executable contract owners

* no-mistakes(document): Document isolation proof skip and artifact semantics

* no-mistakes(ci): Fixed Greptile’s concurrency-consent finding. `--changed` now remains serial by default; bounded concurrency requires explicit `--jobs auto`. Updated behavioral coverage, contributor guidance, and isolation-proof commands accordingly. Verified with `tests/fm-test-run.test.sh`, `bin/fm-doc-audience-check.sh`, `bin/fm-lint.sh`, Bash syntax checks, and `git diff --check`; all passed

* no-mistakes(review): Restore plain changed-suite automatic concurrency

* no-mistakes(review): Record resolved changed-suite worker count

* fix(bin): keep a runner change selecting its whole curated family

A pipeline fix round narrowed the curated changed-file map so bin/fm-test-run.sh
and bin/fm-test-isolation-proof.sh selected only their own two contract tests,
and the documentation surfaces only the audience test. That cut this branch's
own changed selection from 33 scripts to 5.

The runner executes every pure-contract-unit script, so its contract test
passing proves its logic is right, not that the suite it drives still runs.
Narrowing it also makes any wall-clock claim about the changed suite trivially
true by not running the work.

Only the unmapped bin/* grep fallback resolves per script; curated mappings keep
their recorded family coupling.

* perf(bin): admit the pure-contract-unit family to bounded concurrency

A runner-file change selects pure-contract-unit, so that family decides the
changed suite's wall clock. With only watcher-wake-lock admitted, 14 of its 33
selected scripts fell to the serial tail and the selection measured 327.3s
against a 300s budget: the concurrent group was 19 scripts totalling 273.4s
while the tail alone was 215.7s.

bin/fm-test-isolation-proof.sh --pool pure-contract-unit --jobs 4 passes twice,
32 candidates, 0 failures, so the family is admitted on recorded evidence.

Full 33-script plain --changed: 327.3s -> 181.8s / 178.5s / 172.7s, 0 failures,
inside a 300000ms budget. Also states the per-script guard's derivation.

* no-mistakes(review): Align contract-unit concurrency cap with recorded proof

* no-mistakes(document): Record final changed-suite performance evidence

* fix(bin): keep an empty changed selection clean on stock macOS Bash

Under set -u, bash 3.2 treats "${arr[@]}" on an EMPTY array as an
unbound-variable error, while bash 4.4+ makes it a harmless no-op. The
concurrency work removed the early exit for an empty selection, so execution
fell through to the unguarded existence loop: on stock /bin/bash 3.2.57 a
contributor who changes only documentation and runs --changed got

  bin/fm-test-run.sh: line 1713: SCRIPTS[@]: unbound variable

with exit 1 and no summary, instead of a clean total=0 pass.

Restore the early exit, and guard every remaining array expansion reachable
with an empty selection. The reported duration is real elapsed invocation
time rather than a hardcoded zero, so a selection phase that outran
--max-wall-ms still fails.

Verified on this host with /bin/bash 3.2.57: exit 1 with the unbound-variable
error before, exit 0 with FM_TEST_SUMMARY total=0 after.

* no-mistakes(document): Document shell-bound changed-suite performance

---------

Co-authored-by: Kun Chen <kun-1@kunchenguid.com>
* feat(bin): publish per-home summary ledger

* no-mistakes(review): Bound and schedule home summary publication

* no-mistakes(review): Prove recurring watcher summary refresh cadence

* no-mistakes(review): Bound refresh workers and publish durable spawns

* no-mistakes(review): Fix atomic kill process-group coverage

* no-mistakes(review): Bound state initialization within refresh timeout

* no-mistakes(document): Document recurring bounded home-summary publication

* no-mistakes(review): Bound and log all best-effort refresh failures

* no-mistakes(review): Harden cadence and timeout regression coverage

* no-mistakes(document): Document home-summary runtime tuning

* no-mistakes(lint): Fix direct exit-code check in refresh test

* no-mistakes(ci): Fixed remote secondmate retirement recreating the deleted home: teardown now skips side-band summary refresh when its overridden state directory was removed. Verified with remote lifecycle E2E, teardown tests, home-summary tests, ShellCheck, and git diff checks

* no-mistakes(document): Clarify atomic home-summary publication guarantee
* fix(pi): gate first call on startup context

* no-mistakes(document): Correct Pi startup prerequisite verification date

* no-mistakes(review): Captain, fix startup process-group retirement after leader exit

* no-mistakes(review): Captain, release reload exit listeners on shutdown

* no-mistakes(review): Captain, complete startup exit lifecycle ownership

* no-mistakes(review): Captain, release empty startup process-group ownership promptly

* no-mistakes(review): Captain, supervise startup ownership and restore failure fallback

* no-mistakes(review): Captain, restore live Pi supervisor execution

* no-mistakes(document): docs: clarify Pi startup prerequisite delivery
* fix(pi): restore 0.84.4 adapter compatibility

* no-mistakes(review): Restore Pi collapsed and expanded outcome parity

* no-mistakes(review): Preserve Pi stock previews through capability probing

* no-mistakes(document): Document Pi 0.84.4 renderer compatibility
Brings in upstream's merge-outcome verification, bounded/concurrent changed
test runs, per-home summary ledgers, concurrent remote transport lanes, and
the Pi renderer and startup fixes, without dropping this fork's own work.

Three files conflicted; eleven auto-merged and were reviewed hunk by hunk
against both sides.

bin/fm-pr-merge.sh
  Upstream (7ee0c19) moved the PR metadata recording into record_pr_metadata()
  and gates every reported merge on a proved GitHub outcome. This fork's
  0988f74 passes --no-description-check on that same call, because the
  description's local-path guard belongs to the ready report and refusing here
  would block a merge the captain already authorized. Kept upstream's function
  and call site, carried the flag and its reason into it.

tests/fm-test-run.test.sh
  Both sides added fixtures and tests to the same helper. Kept upstream's three
  new tests and this fork's prose-selection test. Upstream's empty-selection
  case used a README.md edit, which is no longer an empty selection here since
  this fork maps every tracked prose path to the documentation-audiences
  family; it now uses the .gitignore trigger this fork already introduced,
  keeping upstream's rewritten duration and budget assertions intact.

tests/fm-tool-update-check.test.sh
  Both sides independently de-flaked the same whole-second budget granularity.
  Kept this fork's 3s budget with its pinned probe, which is the wider margin
  and the one this fork's CI validated, and kept upstream's sharper statement
  of the root cause.

bin/fm-test-run.sh auto-merged cleanly: upstream never touched the weight
hints, so 4a39aa0's rebalance is byte-identical and still the effective one.
Upstream's two new serial scripts land on the default weight and the packer
absorbs them at roughly 820s per shard against the 20-minute cap.

tests/fm-public-followup.test.sh needed one reconciliation beyond the textual
merge. Upstream pinned the suite clock to a fixed instant while this fork
anchored the fixture window to the wall clock; the literal merge left the
window drifting one day further from that clock every day. Both helpers now
derive the window from PF_TEST_NOW, which is what each side was separately
reaching for.

docs/fm-test-portable-shards.md owns the shard table and the merge changed the
numbers it records, so the counts, sums and provenance are corrected to the
merged lanes. The hints themselves are unchanged; refreshing them needs timing
artifacts from a green run of this tree.

Verified: 23 suites covering every resolved file and every file upstream
touched pass (failed=0); the coverage guard passes; bin/fm-lint.sh is clean.
The three gate skips are Pi-not-installed environment gates.
@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 07c0e13d-973d-4a24-85c0-e3fef9eae9c5


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sanis
sanis merged commit 8060dfe into main Aug 29, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants