feat(bin): renew fork from upstream through f66be0f8 - #19
Merged
Conversation
…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.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 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. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Renew this fork from upstream: merge
upstream/maininto ourmainso the fork carries upstream's latest work without losing any of our own.Starting position:
upstreamis https://github.com/kunchenguid/firstmate;originis our forksanis/firstmate. Merge base is10b93b2c(the previous renewal, fm-upstream-sync-8). Ourmainwas 59 commits ahead and 9 behind. The nine commits to bring in, newest first:f66be0f8fix(pi): restore Pi 0.84.4 renderer compatibility (kunchenguid#3261);52b59a13fix(pi): gate first provider call on startup context (kunchenguid#3158);a3906593feat(bin): publish per-home summary ledgers (kunchenguid#3222);42072140fix(bin): accelerate and bound changed test runs (kunchenguid#3250);1fd7ea28feat(bin): add concurrent bounded remote transport lanes (kunchenguid#3210);c651b590fix(pi): surface requested outcomes without replaying fleet events (kunchenguid#3211);bca584a8fix(bin): prioritize active pipeline-owned crew runs (kunchenguid#3194);4f89f5b5fix(pi): prevent duplicate captain outcome reports (kunchenguid#3184);7ee0c192fix(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 landed4a39aa0ffix(bin): rebalance portable-serial shard weights after the upstream merge, a deliberate re-tuning of shard balance for THIS home. Upstream lands42072140(accelerate and bound changed test runs) anda3906593(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- upstream7ee0c192reworks merge-outcome verification so a merge is not reported until it is proved. Our fork carries0988f74ffeat(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- upstream1fd7ea28adds 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, including08ba9045(bearings mismatch classification and parallel shard balance evidence) and7c04bf26(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:
git fetch upstream, then mergeupstream/maininto the branch.git log --oneline 10b93b2c..upstream/main -- <file>andgit 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.Merge upstream/main: fork renewal (9 commits through f66be0f8).VERIFICATION REQUIRED:
git log --oneline main..upstream/mainshows nothing left to bring in; run the suites covering every file resolved by hand plus the ones upstream touched, withtests/fm-test-run.test.sh,tests/fm-remote-job.test.sh,tests/fm-public-followup.test.shandtests/fm-tool-update-check.test.shall directly in scope; every shell file touched is shellcheck-clean; for each conflicted file readgit 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 weights4a39aa0fset are still the effective ones and that upstream's new bounding still applies on top.OPERATIONAL CONSTRAINTS: always pass
--repo sanis/firstmateto 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):
bin/fm-pr-merge.sh: upstream moved the PR metadata recording into a newrecord_pr_metadata()and gates every reported merge on a proved outcome. Our0988f74fpasses--no-description-checkon 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 aREADME.mdedit, which is no longer an empty selection in this fork because we map every tracked prose path to thedocumentation-audiencesfamily; it now uses the.gitignoretrigger our fork already introduced, keeping upstream's rewritten duration and budget assertions intact. Our side also re-addedfm-documentation-audiences.test.shto 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.shauto-merged cleanly: upstream never touchedportable_serial_weight_hints, so all 133 of4a39aa0f's hint lines are byte-identical and still the effective ones. Upstream's two new serial scripts land on thePORTABLE_SERIAL_DEFAULT_WEIGHT_MSdefault and the bin-packer absorbs them at roughly 820s per shard against the 20-minute cap. Upstream's new--list-scheduledordering demonstrably reads our hints and its--max-wall-msbounding works on top.tests/fm-public-followup.test.shneeded 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 instantPF_TEST_NOW, while our9b15dcfdanchored the fixture window to the wall clock at seed time. The literal merge passed its tests but leftreceived_atfive 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 fromPF_TEST_NOW, which satisfies each side's stated intent; the publishedSEED_*_EXPIRES_AT/_EPOCHvariables our fork added are retained.docs/fm-test-portable-shards.mdis 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-coveragepasses (171 total, 24 parallel, 135 serial across 4 shards, 12 herdr);bin/fm-lint.shexits 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 (697c1208andf66be0f8),HEAD..upstream/mainis empty, and 63 files changed: upstream's 62 plus the one shard-table doc correction.What Changed
upstream/main(9 commits,7ee0c192..f66be0f8) into the fork as a true two-parent merge: per-home summary ledgers (newbin/fm-home-summary-refresh.shplus its suite), concurrent bounded remote transport lanes inbin/fm-remote-job-worker.sh/bin/fm-remote-job-lib.sh, proved GitHub merge-outcome verification inbin/fm-pr-merge.sh, accelerated and wall-bounded changed-test selection inbin/fm-test-run.sh, pipeline-owned crew-run prioritization inbin/fm-crew-state.sh, and the Pi supervision/renderer fixes across.pi/extensions/(including the newlib/fm-sessionstart-supervisor.mjs), with their tests and docs.bin/fm-pr-merge.shkeeps upstream'srecord_pr_metadata()gate while carrying the fork's--no-description-checkflag and its reason;bin/fm-test-run.shkeeps the fork'sportable_serial_weight_hintsas the effective weights with upstream's new bounding layered on top;tests/fm-test-run.test.shkeeps upstream's three new cases alongside the fork's prose-selection test, re-pointing upstream's empty-selection case at the.gitignoretrigger since prose paths now map to a test family;tests/fm-tool-update-check.test.shkeeps the fork's wider 3s budget with upstream's sharper root-cause note.tests/fm-public-followup.test.shnow exportsPF_TEST_NOWso both seed helpers derive their fixture windows from the pinned clock instead of wall time (removing thereceived_atdrift the literal merge left behind), anddocs/fm-test-portable-shards.mdwas 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-checkthe solefm-pr-merge.shdivergence, 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)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.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=0Evidence: 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.Evidence: Suite logs for the nine targeted suites (all exit 0)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
tests/fm-public-followup.test.sh:26-PF_TEST_NOW=1787539200is 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: onlyrun_pf(line 108) and the twofmx_context_registry_setcalls (lines 169, 215) pin the clock.$POLL,$SESSION_START,$TEARDOWN,$PROMOTE,$EMITandtasks_inall still run at the wall clock. The seeded thread window is thereforePF_TEST_NOW + 7d = 2026-08-31T02:40Z— a fixed calendar date again from those paths' point of view, which is the exact time-bomb shape9b15dcfdand upstream'sPF_TEST_NOWboth 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:105callsfmx_context_registry_pruneat the wall clock withmax_age=604800, so from 2026-08-31 the$POLLinvocations in the relay-poll test delete the seededstate/x-context/<request>.jsonwhoserecorded_atisPF_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 fromSEED_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 thatexport FMX_NOW_OVERRIDE="$PF_TEST_NOW"(line 31) covers the whole suite, three explicit clock prefixes are unreachable/redundant:${FMX_NOW_OVERRIDE:-$PF_TEST_NOW}inrun_pf(line 113) can never take its:-branch, andFMX_NOW_OVERRIDE="$PF_TEST_NOW"on the twofmx_context_registry_setcalls (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 therun_pfdefault 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 0bash 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 0bash tests/fm-tool-update-check.test.sh— exit 0bash 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-shadoweddatelogging every bare+%squery, run against HEAD's suite and against a copy of ec645f2's pre-fix suite; compared callersWall-clock independence:PATH=<shim>:$PATH bash tests/fm-public-followup.test.shwith the machine clock shifted +1 year — 52 ok, exit 0bin/fm-test-run.sh --check-coverage→FM_TEST_COVERAGE ok total=171 parallel=24 serial=135 serial_shards=4 herdr=12bin/fm-test-run.sh --list-scheduled --lane portable-serial-{1,2,3,4}of4and--list --lane ...for shard sizesbin/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) andgit merge-base --is-ancestorfor each of the nine upstream commitsgit diff f66be0f8...HEAD -- bin/fm-pr-merge.sh(single intentional hunk) and diff ofportable_serial_weight_hints()between4a39aa0fand HEAD (identical, 137 lines)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.