Skip to content

fix: preserve run authority across capped reruns - #70

Merged
timbarreto merged 2 commits into
mainfrom
fix/nm-capped-rerun-race
Sep 18, 2026
Merged

timbarreto merged 2 commits into
mainfrom
fix/nm-capped-rerun-race

Conversation

@timbarreto

@timbarreto timbarreto commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

Current head: c32582a64c4e8d9bcda17092f4e5a2dfe008ddf9; current fork base: 765b4f91b4e086a0483a4cb8c9d8d6d494ca65a7.
The merge conflicts are resolved. All 20 automatic checks passed on this exact head; both workflows succeeded on their first attempt.

Summary

Fix the capped no-mistakes rerun-selection race documented as a remaining limitation in canonical PR #4476, after synchronizing with merged PR #68.

  • Preserve the overview's readable live run identities across the complete SQLite inventory lookup.
  • When the selected predecessor changed from live to terminal, perform one fresh read-only lookup for its replacement.
  • Use the replacement's own ID-addressed status and existing branch/head/custody checks; never reuse the predecessor's gate details.
  • Report unknown with every observed candidate ID if no successor is established, the refresh fails, identities disappear or conflict, or the replacement changes again.
  • Keep genuine newer failures visible and retain the single-lookup stable capped path.

The production change is confined to bin/fm-nm-run-lib.sh's current-state selector.
The coarse runs-ledger/teardown attribution functions and bin/fm-crew-state.sh's final identity/liveness/head/custody checks are unchanged.
No database write, runtime deadline change, new dependency, workflow change or concurrency admission is introduced.
The separate normal-path three-CLI-call cost noted by kunchenguid#4476 is not changed by this fix.

Root cause and deterministic reproduction

The capped overview fallback retained candidate IDs but discarded their earlier live state before recursively selecting from the complete inventory.
Consequently, an overview showing A live, followed by an inventory showing A cancelled and a replacement B starting before the final status read, could produce a falsely consistent terminal verdict for A.

The regression invokes the real state reader over disposable Git and SQLite fixtures.
A shim lets the actual read-only query finish, then publishes the replacement into that fixture database before the next observation, without sleeps or production-source mutation.
Before the fix, two independent runs reproduced:

not ok - a superseded cancellation was reported while its replacement was live
state: failed · source: run-step · run cancelled · run: 01NEW
FM_LIVE=0 \
FM_TEST_ONLY=test_capped_rerun_between_inventory_and_status_keeps_replacement_gate \
  bin/fm-test-run.sh --jobs 1 tests/fm-crew-state.test.sh

The same scenario now preserves 01RERUN and its review gate.
An additional red/green case ensures partial displayed-head semantics cannot erase a readable live identity before the complete lookup; the fetched successor still needs full validation.

Regression coverage

Nine new named cases cover:

  1. Stable capped selection: one reader invocation and byte-unchanged database.
  2. The reported inventory/status interleaving: fresh successor and its own gate, one refresh, no extra CLI call.
  3. No successor yet: uncertainty, followed by normal visibility of a later stable cancellation.
  4. A genuinely newer failure discovered by the refresh.
  5. Further rerun churn: the existing final-status disagreement guard reports uncertainty without another refresh.
  6. Unavailable refresh: both visible and previously hidden candidate IDs survive.
  7. Competing, malformed and disappearing successor identities.
  8. Pending as well as running predecessors.
  9. Liveness retained before complete head validation.

All 133 cases from current main retain their order, including the original 128 and the five added by PR #71.
The nine rerun cases make 142 registered cases, preserving both parents' order through the shared fm_test_run_cases interface.
The documentation records these as controlled interleavings, not newly captured live no-mistakes runs.
No live pipeline was initialized or controlled and no vendor session was started.

Conflict resolution with PR #71

Normally merged PR #71's fork-main update into this branch; no squash, rebase or force-push.
The sole conflict was the case registry at the end of tests/fm-crew-state.test.sh.
The combined registry keeps all 142 cases exactly once and preserves the relative order of each parent's cases.
It retains main's array-style registration and PR #70's full-suite-only success banner, so listing or one selected case is not mislabeled as a complete suite pass.

PR #70's selector and its two documentation changes are byte-identical to 4cc19b0.
The 13 other incoming paths are byte-identical to new main, preserving generation-bound reporting, active-run precedence, later busy-turn authority, recovery receipts, and the default bounded snapshot.
The PR still changes exactly four paths against its actual base: +300/-18, with no existing file-mode changes.
Workflow definitions, runner algorithms, proof admissions, package pins, live gates and production deadlines are unchanged.

Current local verification

10 focused behavior cases passed, alongside all four repository gates, explicit source-aware lint, the executable case-list/order audit, and refreshed lane/changed-path inventories.
Case listing and inventory checks are inspection evidence, not suite executions.
All checks used explicit Git-for-Windows Bash, serial selected-case execution, cache off, and FM_LIVE=0.

Command or selected case Result Elapsed ms
shell-syntax passed 11800
repository-lint passed 52280
source-aware-lint passed 43856
documentation-audiences passed 14844
lane-coverage timeout 184734
case-registration-and-scope passed 20578
ci-lane-inventory passed 123201
lane-coverage-retry passed 151827
capped-rerun-between-inventory-and-status-keeps-replacement-gate passed 27268
capped-rerun-keeps-liveness-before-complete-head-validation passed 29462
capped-stable-inventory-uses-one-reader passed 27257
capped-refresh-preserves-a-genuinely-newer-failure passed 32459
active-run-is-authoritative passed 24071
current-launch-report-beats-only-launch-seed passed 115461
current-launch-without-report-requires-live-agent passed 28459
current-launch-report-reaches-bounded-snapshot passed 29804
current-launch-report-survives-dead-endpoint passed 30107
launch-report-does-not-retire-secondmate passed 17124
actual-base-changed-routing passed 18536

The first coverage attempt timed out after 184,734 ms at a 180-second external cancellation bound, without an assertion diagnostic.
That bound was shorter than the earlier same-host successful coverage run (198,240 ms at a 300-second bound).
One serial retry used the previous 300-second bound and passed unchanged in 151,827 ms.
The timeout remains a timeout; neither production/CI deadlines nor test assertions changed, and no performance-regression repair is claimed.

The behavior rows above use the existing public runner, with the row name prefixed by test_ and hyphens replaced by underscores for FM_TEST_ONLY:

FM_LIVE=0 FM_TEST_ONLY=<registered-case-name> \
  bin/fm-test-run.sh --jobs 1 tests/fm-crew-state.test.sh

Other command owners:

while IFS= read -r script; do /bin/bash -n "$script" || exit; done < <(bin/fm-lint.sh --list-files)
bin/fm-lint.sh
bin/fm-lint.sh bin/fm-nm-run-lib.sh bin/fm-crew-state.sh bin/fm-classify-lib.sh tests/fm-crew-state.test.sh
bin/fm-doc-audience-check.sh
bin/fm-test-run.sh --check-coverage
FM_TEST_LIST_CASES=1 bash tests/fm-crew-state.test.sh
bin/fm-test-run.sh --list --changed --base 765b4f91b4e086a0483a4cb8c9d8d6d494ca65a7

The case audit proves 128 common + 9 PR #70 + 5 PR #71 = 142, no duplicate or missing registration, both parent orders retained.
The 64 selected scripts all map to existing CI producers; no broad local suite was run.
The fresh coverage partition is 240 = 24 parallel + 200 serial + 16 Herdr, five serial shards, 21 unhinted serial subjects and zero unhinted parallel subjects.
Documentation validation reports 108 surfaces / 479 local links.
The full current-state suite remains owned by Behavior portable parallel 2.
Native management, stock Bash, package and real-Herdr guarantees remain with their existing workflow jobs; optional skips never become live passes.

Fresh CI

All 20 automatic producers passed on the current head, verified at 2026-09-18T12:46:47Z.
Both workflows completed successfully on attempt 1, with one verified workflow/job producer per expected check and no missing, pending, failed or mismatched required producer.
The complete 142-case current-state suite passed in portable parallel 2: exit=0 duration_ms=38463 gate_skip=false, including the capped-rerun and default-bound replacement-snapshot assertions.
No current-head CI rerun was needed; the older retry below remains historical evidence only.
The manual-only Windows Herdr experiment was not dispatched.

Historical evidence before this base update (4cc19b0)

These results apply only to the original published head, not to the merge commit above.
The original 137-case suite and all 20 checks passed, with one targeted retry of portable serial 4 and its dependent summary.
That initial shard reported failures in unchanged PR-poll/startup fixtures; both assertions passed on its same-head retry, without code/deadline/assertion changes, and the initial causes remain unestablished.
The first failed log and both attempts remain retained; a narrow underlying gh api fallback retrieved that complete read-only log after gh-axi truncated it.

The original local runs also retained three pre-existing Windows fixture-setup failures: one quoted-path Git/SQLite fixture and two no-Python restricted-PATH fixtures (/usr/bin/env: bash: No such file or directory).
These were not counted as passes or skipped coverage; the old full-suite CI passed independently.
This update does not claim those local fixture setups were repaired.

Original workflows: CI, Fork CI.
The original PR body, case logs, deterministic red/green evidence and audit are archived outside the repository.

Provenance and delivery

  • Previous head / first merge parent: 4cc19b0a989c592bf29324ff607f77210cf48760.
  • Actual fork base / second merge parent: 765b4f91b4e086a0483a4cb8c9d8d6d494ca65a7.
  • Current published head: c32582a64c4e8d9bcda17092f4e5a2dfe008ddf9.
  • Reviewed and locally validated tree: 51d69810c3740ba156803b17ce4854c539089a51.
  • Working tree clean; the only worktree is C:/src/firstmate2.
  • Local main remains at the previously synchronized 1c11c416fe4d70b475332795e7c698f3afb03dd6; this request did not authorize updating it.
  • Canonical upstream was not refetched or advanced.
  • Evidence: %TEMP%/firstmate2-rerun-race-20260918/base-update-765b4f9/, including every command plan/log/result, scope/order audit and fresh CI observations.

Leave this ordinary, non-draft PR unmerged, with auto-merge off pending separate approval.

The capped overview fallback kept run identities but discarded their live
state before selecting from SQLite. If a rerun cancelled the predecessor
between those reads, its later cancelled status falsely appeared consistent
even after a replacement had started.

Preserve the readable live identities, refresh the read-only same-branch
inventory once when the selected predecessor becomes terminal, and report
unknown when no replacement can be established. Retain every observed ID
on an unreadable refresh and preserve genuine newer failures, final status
and head/custody checks, and the unchanged normal-path lookup count.

Add deterministic inventory/status interleavings and bounded-refresh
regressions, register all existing crew-state cases in their original order,
and document the controlled-fixture versus live-evidence boundary.
@timbarreto

Copy link
Copy Markdown
Owner Author

Final verification: 4cc19b0

At 2026-09-18T06:09:46.440510+00:00, 20/20 automatic checks are successful for 4cc19b0a989c592bf29324ff607f77210cf48760, based on 1c11c416fe4d70b475332795e7c698f3afb03dd6.
Every check has one verified workflow/job producer; no required check is pending, failed or absent.
The PR remains open, non-draft, mergeable and unmerged, with auto-merge off.

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

Retry history retained

The first CI attempt passed 19 checks, including the full current-state suite, but portable serial 4 reported two failures in unchanged PR-poll/startup fixtures.
Only that shard and its dependent aggregate were rerun; the commit, assertions, deadlines and coverage were unchanged.
The retry log confirms both assertions passed and reports:

FM_TEST_SUMMARY total=41 failed=0 skipped_gate=8 duration_ms=1185330

The eight skips are existing optional gates, not new live passes.
Other successful jobs retain their original same-head execution results; GitHub's copied attempt-2 job IDs do not imply those jobs were re-executed.
The original failure causes were not established, so this is not a claim to have repaired those fixtures.

Bug-fix proof

The deterministic race test failed twice before the fix with state: failed ... run cancelled ... 01NEW after its replacement became live.
It now returns the verified replacement's own review gate, with one bounded inventory refresh and no additional CLI call.
Nine new cases cover stable reads, missing/unreadable/competing/malformed/disappearing successors, newer real failures, repeated churn, pending predecessors and partial displayed-head semantics.
All 128 original cases retain their order; the full suite now has 137 registered cases and passes in portable parallel 2.

The four local gates, source-aware lint, named-case/order audit and focused regressions passed.
Three unchanged Windows fixture setups could not run locally; their failures and the controlled-fixture/live-evidence distinction remain explicit in the PR body.
No live no-mistakes pipeline or credentialed vendor session was started.
The normal-path three-status-call latency issue is separate and unchanged.

Preserve PR #71's generation-bound replacement reports alongside PR #70's
bounded capped-rerun selection. Resolve the shared current-state registry
as the ordered union of both parents: 142 cases, with named selection and
listing retained and the full-suite success banner emitted only for a
full execution.

Keep incoming production behavior and PR #70's selector unchanged.
@timbarreto

Copy link
Copy Markdown
Owner Author

Merge conflict resolved: c32582a

Merged fork main 765b4f91b4e086a0483a4cb8c9d8d6d494ca65a7 into this branch normally.
The one conflict was the current-state case registry: 142 unique cases, preserving all 137 from this PR and all 133 from PR #71 in their original relative orders.
No production behavior was chosen away: this PR's selector and incoming generation-bound reporting remain intact.

All four local gates and ten focused cases passed on tree 51d69810c3740ba156803b17ce4854c539089a51, including the original capped-rerun interleaving, genuine newer failure, active-run authority, launch-seed/busy precedence, default-bound fleet snapshot, and secondmate exclusion.
The initial coverage command hit its too-short 180-second external cutoff; its single unchanged retry at the prior 300-second bound passed.
That timeout and all earlier failures remain documented in the body and external evidence.

Fresh CI and Fork CI are running for this exact head.
GitHub reports mergeable; the PR remains unmerged, with auto-merge off.

@timbarreto

Copy link
Copy Markdown
Owner Author

Conflict-resolution head fully verified: c32582a

At 2026-09-18T12:46:47.452426+00:00, all 20 automatic checks passed for c32582a64c4e8d9bcda17092f4e5a2dfe008ddf9, against fork main 765b4f91b4e086a0483a4cb8c9d8d6d494ca65a7.
Both workflows succeeded on their first attempt; every expected check has one verified exact-head workflow/job producer.
No pending, failed, missing or mismatched required producer remains.

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

Both sides of the conflict retained and exercised

The case registry is the ordered union of the two parents: 128 shared + 9 capped-rerun + 5 revived-worker cases = 142, with no duplicates or missing definitions.
The current-state job log confirms the full unfiltered suite passed, including the capped-rerun interleaving and the replacement-report fleet snapshot with its default deadline:

all fm-crew-state tests passed
FM_TEST_END 2026-09-18T12:32:23Z tests/fm-crew-state.test.sh exit=0 duration_ms=38463 gate_skip=false

Locally, all four repository gates and ten focused cases passed, alongside source-aware lint and fresh scope/order/routing audits.
The first local coverage attempt hit its 180-second outer cancellation bound; the unchanged one-time retry at the prior 300-second bound passed, and the original timeout remains in the body and evidence.
This is distinct from current-head CI, which needed no retry.

The PR remains open, non-draft, mergeable/clean and unmerged, with auto-merge off.
The working tree is clean, local main was not advanced, and the read-only scoped process audit found no remaining task-owned test/validator processes.
No canonical refetch, live Firstmate home, credentialed vendor session, deadline change or force-push was used.

@timbarreto
timbarreto merged commit 7d38978 into main Sep 18, 2026
20 checks passed
@timbarreto
timbarreto deleted the fix/nm-capped-rerun-race branch September 18, 2026 13:01
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.

1 participant