feat(bin): detect diverged primary default branch at session start - #5
Merged
Merged
Conversation
wongsuwarn
force-pushed
the
fm/firstmate-session-start-divergence-check
branch
from
August 5, 2026 17:36
135195b to
c29e532
Compare
Add a cheap, detect-only bootstrap check that flags when the primary checkout's local default branch carries commits origin/<default> does not, so the fast-forward-only self-update path can no longer reconcile it and would otherwise silently skip with no alarm.
…ocument new surface
…-update skip wording
The MAIN_DIVERGED remediation instructs a git fetch on the primary, so a detect-only, lock-refused session must not print it, matching how TANGLE already drops its own state-suggesting command there.
wongsuwarn
force-pushed
the
fm/firstmate-session-start-divergence-check
branch
from
August 5, 2026 21:19
c29e532 to
446f382
Compare
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
Follow-up to the already-shipped MAIN_DIVERGED session-start check (PR #5, already merged/CI-green for the core feature): give MAIN_DIVERGED the same FM_BOOTSTRAP_DETECT_ONLY read-only branching that the neighboring TANGLE check already has. Motivation: an earlier review round approved adding a 'git -C fetch origin' instruction to MAIN_DIVERGED's remediation text (since the underlying check deliberately never fetches, for cheapness/offline-safety, so its comparison can be stale). A later review round correctly flagged that this fetch instruction is a write to the primary's object store/refs, and printing it unconditionally in a detect-only/lock-refused session (a read-only session that did not acquire the fleet lock, per AGENTS.md section 3) is inconsistent with TANGLE's own established convention of dropping its printed repair command in that same read-only mode. This change: in bin/fm-bootstrap.sh, MAIN_DIVERGED now branches on FM_BOOTSTRAP_DETECT_ONLY exactly like TANGLE - printing advisory-only wording with no fetch instruction when detect-only/lock-refused, and the full fetch-then-reconcile remediation otherwise. The check function itself (fm_primary_diverged_branch in bin/fm-main-divergence-lib.sh) is completely unchanged and stays fetch-free in every mode - only the printed human-facing text branches. Updated the fm-bootstrap.sh header note, the bootstrap-diagnostics skill's MAIN_DIVERGED bullet, and docs/architecture.md + docs/configuration.md (which both previously claimed the wording was 'identical' between locked and read-only sessions, no longer true) to describe the split, mirroring how those same docs already describe TANGLE's own split. Added a test case to tests/fm-main-divergence.test.sh asserting the detect-only line still names the diverged branch and fires the alarm but omits 'fetch origin', while normal mode includes it. This is purely a wording/behavior split in the diagnostic output; no change to detection logic, no change to what triggers the alarm, and no fetch or mutation added anywhere.
What Changed
main) has diverged fromorigin, printing aMAIN_DIVERGED:diagnostic; the check function (fm_primary_diverged_branchinbin/fm-main-divergence-lib.sh) stays fetch-free in every mode, and the human-facing text branches onFM_BOOTSTRAP_DETECT_ONLY— advisory-only wording with nogit fetch origininstruction in detect-only/lock-refused read-only sessions, and the full fetch-then-reconcile remediation otherwise, mirroring the neighboring TANGLE split.bin/: abort parked runs and reap leaked processes before teardown, persist secondmate parent bindings for cleanup, surface fleet-wide open decisions on every wake drain, bound remote SSH dead-peer detection, and resolvefm-remote-entrypoint.shSCRIPT_DIRthrough a PATH symlink.docs/architecture.mdanddocs/configuration.mdto describe the new detect-only/locked wording split.Risk Assessment
✅ Low: A text-only diagnostic-wording split that faithfully mirrors the established TANGLE detect-only convention, leaves detection logic and the fetch-free check function untouched, and is covered by an updated test and consistent docs.
Testing
Ran the smallest relevant suite (tests/fm-main-divergence.test.sh, exit 0) which now asserts the detect-only MAIN_DIVERGED line still names the diverged branch and fires the alarm while omitting thefetch origininstruction, and that normal mode includes it. To show the actual end-user experience, I reproduced both modes by drivingbin/fm-bootstrap.shover a hermetic temp git repo with a local-only diverged default branch and captured the rendered diagnostic text as a CLI transcript: the fleet-lock (normal) line prints the full fetch-then-reconcile remediation withgit -C <root> fetch origin, and the read-only detect-only line prints advisory-only wording ("read-only session must leave refreshing and reconciling to the session holding the fleet lock") with no fetch or mutation. The check library is untouched by the commit. Everything passed; no findings.Evidence: MAIN_DIVERGED diagnostic in normal vs detect-only mode (CLI transcript)
=== NORMAL (fleet-lock holder) === MAIN_DIVERGED: primary checkout's 'main' carries commits origin/main does not; ... refresh the stale ref first with: git -C <root> fetch origin ... inspect with: git -C <root> log origin/main..main --oneline, then reconcile manually ... before rerunning /updatefirstmate === DETECT-ONLY (read-only, lock-refused) === MAIN_DIVERGED: primary checkout's 'main' carries commits origin/main did not have as of the last refresh; fast-forward self-update may no longer be able to reconcile it - this check never fetches, so the comparison may be stale; read-only session must leave refreshing and reconciling to the session holding the fleet lockPipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-main-divergence.test.sh— all 3 cases pass, including the new detect-only assertions (line namesmain, fires alarm, omitsfetch origin)Manual CLI reproduction: ranbin/fm-bootstrap.shagainst a hermetic temp repo with a local-only divergedmainin both normal andFM_BOOTSTRAP_DETECT_ONLY=1modes, capturing the actual session-startMAIN_DIVERGED:diagnostic text a captain would readVerified target commit c29e532 does not modifybin/fm-main-divergence-lib.sh(thefm_primary_diverged_branchcheck function), confirming detection logic and fetch-free behavior are unchanged✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.