Skip to content

fix(bin): tolerate local Treehouse config during fleet sync - #4

Merged
sparkus merged 2 commits into
mainfrom
fm/fix-fleet-sync-local-config
Jul 29, 2026
Merged

fix(bin): tolerate local Treehouse config during fleet sync#4
sparkus merged 2 commits into
mainfrom
fm/fix-fleet-sync-local-config

Conversation

@sparkus

@sparkus sparkus commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Intent

Fix fleet-sync dirtiness handling so the deliberate untracked root-level treehouse.toml machine configuration no longer permanently blocks project-clone refresh. Preserve every real safety property: modified tracked files, staged changes, every other untracked path, names that merely contain treehouse.toml, wrong branches, and divergence must still block or report STUCK; the existing conditional secondmate seed-marker tolerance must remain unchanged and must not mask real dirt. Use one narrow exact porcelain-record allowlist in the shared dirty-status owner, apply it to the real fleet-sync entry point and all reachable callers, do not touch project clones or their git configuration, and keep the change proportionate with regression coverage for every safety case. Raise the PR through the no-mistakes pipeline to sparkus/firstmate with base main, never by hand, and do not merge.

What Changed

  • Allow fleet sync and shared fast-forward callers to preserve an exact untracked root-level treehouse.toml while refreshing clones.
  • Keep tracked changes, staged changes, other untracked paths, lookalike names, and unsafe branch states blocking; preserve the conditional secondmate seed-marker exception.
  • Document the narrow local-config exception and add regression coverage for fleet-sync and secondmate-sync safety cases.

Risk Assessment

✅ Low: The change implements a narrow exact-record exception in the shared dirty-status owner, routes fleet-sync through it, preserves the conditional seed-marker exception and other safety checks, and adds proportionate regression coverage.

Testing

Baseline provenance matched the supplied base and target; focused fleet-sync, secondmate, and update regressions passed; direct CLI evidence showed the behind clone syncing while preserving treehouse.toml and its Git configuration, while genuine tracked dirt remained STUCK with HEAD and the edit untouched.

Evidence: Direct fleet-sync operator transcript
=== Operator case: exact root treehouse.toml ===
before HEAD: 0d668093314ff7dc76913ecf037dda63c0496546
before status:
?? treehouse.toml
fleet-sync output:
config-ok: synced 0d66809..5cb6482
after HEAD:  5cb6482aa4f283971a8e1c53eb78757fbc51f94c
origin/main: 5cb6482aa4f283971a8e1c53eb78757fbc51f94c
after status: ?? treehouse.toml
treehouse.toml: root = "/machine/local/treehouse"
git config unchanged: yes

=== Safety case: genuine tracked dirt ===
before HEAD: 5cb6482aa4f283971a8e1c53eb78757fbc51f94c
before status:  M version.txt
fleet-sync output:
real-dirt: STUCK: on branch main with uncommitted changes, 1 commits behind origin/main - needs attention
after HEAD:  5cb6482aa4f283971a8e1c53eb78757fbc51f94c
after status:  M version.txt
local edit preserved: operator edit

E2E RESULT: PASS - exact local config refreshed and preserved; real dirt stayed STUCK and untouched.
Evidence: Fleet-sync regression transcript
ok - detached clean ancestor is re-attached and fast-forwarded (recovered)
ok - detached HEAD with unique commits is reported STUCK and left untouched
ok - detached clean ancestor with diverged local default is reported STUCK and left untouched
ok - dirty working tree is reported STUCK and left untouched
ok - an exact untracked treehouse.toml is tolerated and preserved
ok - a modified tracked file still blocks fleet sync
ok - a staged change still blocks fleet sync
ok - an unrelated untracked file still blocks fleet sync
ok - an untracked name containing treehouse.toml still blocks fleet sync
ok - non-default named branch is reported STUCK and left untouched
ok - diverged default branch is reported STUCK and left untouched
ok - on-default clean behind clone still fast-forwards
ok - already-current clone is reported unchanged
ok - no-origin clone is skipped (benign), not flagged STUCK
ok - local-only clone is skipped (benign), not flagged STUCK
ok - single-project form accepts a bare project name
ok - single-project bare name resolution is not cwd-sensitive
ok - single-project form accepts a projects/<name> relative name
ok - single-project projects/<name> resolution is not cwd-sensitive
ok - single-project form leaves a genuinely bad name unresolved
ok - whole-fleet form processes every clone under projects/
ok - bootstrap relays recovered: and STUCK: fleet-sync outcomes
ok - orphaned provably-stale packed-refs.lock is cleared and the clone syncs
ok - a live packed-refs.lock is never removed and the sync fails loudly
ok - a live process holding the clone worktree dir blocks lock removal (clone-dir liveness)
ok - a transient packed-refs.lock that self-clears is retried without a force-remove
ok - a non-packed-refs.lock fetch failure keeps today's behavior (no retry)
Evidence: Secondmate shared-caller regression transcript
ok - T1 updated: a behind home fast-forwards to the primary's local HEAD
ok - T2 current: an already-current home is a no-op and reports no instruction change
ok - T3 dirty: an uncommitted home is skipped, its edit preserved
ok - T4 diverged: a home that is not an ancestor of the primary's HEAD is skipped
ok - T5 in-flight: a home on a feature branch is skipped, its work preserved
ok - T6 no fetch: the local-HEAD sync never invokes git fetch
ok - T7 sweep nudges on a real instruction change only, but still fast-forwards
ok - T8 bootstrap sweeps live homes and sends exactly one marked nudge for the instruction change
ok - T8a bootstrap nudge send respects FM_STATE_OVERRIDE
ok - T8f bootstrap nudge retry rejects malformed marker ids
ok - T8c failed bootstrap nudge is surfaced and recorded for retry
ok - T8d bootstrap nudge retry is idempotent after success
ok - T8e bootstrap nudge retry refuses a changed home instead of guessing
ok - T8b stale herdr nudge failures leave a retry marker after respawn rotates fm-<id> metadata
ok - T9 bootstrap surfaces a skipped dirty live secondmate home
ok - T10 spawn fast-forwards a secondmate worktree to the primary's local HEAD before launch
ok - T11 spawn warns when pre-launch sync is skipped
ok - T12 gitignored marker: a freshly seeded home reads clean to fleet-sync and the ff sweep
ok - T13 gitignored marker: an existing marker-only-dirty home converges, then reads clean
ok - T14 marker tolerance does not mask a genuinely dirty home
ok - T15 an exact untracked treehouse.toml does not block shared fast-forward logic
ok - T16 existing secondmate-marker tolerance remains intact
ok - T17 the firstmate repo gitignores the secondmate seed marker
# all fm-secondmate-sync tests passed
Evidence: Firstmate update shared-caller regression transcript
ok - T1 main + secondmate fast-forward (single-parent), reread + nudge signalled
ok - T3 reread gates on instruction surface, nudge on advancement
ok - T4 dirty secondmate skipped, local edit preserved
ok - T5 diverged secondmate skipped, local commit preserved
ok - T6 idempotent: a second run is a no-op
ok - T7 registry backstop resolves, dedups meta+registry, excludes the firstmate repo
ok - T9 firstmate off its default branch is skipped, not forced
ok - T10 firstmate detached HEAD is skipped
ok - T11 unsafe secondmate home is not fast-forwarded
# all fm-update tests passed

Pipeline

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.

  • Provenance: git status --short --branch, git rev-parse HEAD, and git merge-base HEAD 79d84b682429c3c65e30d8f54840086ee687f6b9
  • bash tests/fm-fleet-sync.test.sh
  • bash tests/fm-secondmate-sync.test.sh
  • bash tests/fm-update.test.sh
  • Direct isolated bin/fm-fleet-sync.sh config-ok rehearsal with an exact root-level untracked treehouse.toml
  • Direct isolated bin/fm-fleet-sync.sh real-dirt rehearsal with a modified tracked file
  • Compared .git/config hashes before and after the successful fleet refresh
  • Verified final HEAD remains edab82238ffce53e9f14e703d10c964bbabebf6d and the worktree contains no transient test outputs
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@sparkus
sparkus merged commit de44dcd into main Jul 29, 2026
10 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.

1 participant