diff --git a/.agents/skills/bootstrap-diagnostics/SKILL.md b/.agents/skills/bootstrap-diagnostics/SKILL.md index 0aad8846387..2f1bf31aed3 100644 --- a/.agents/skills/bootstrap-diagnostics/SKILL.md +++ b/.agents/skills/bootstrap-diagnostics/SKILL.md @@ -30,7 +30,7 @@ When any diagnostic needs captain attention, report the plain consequence and re Rerun the printed command; it is idempotent and re-derives every finding. A `hit the ...s bound` line means one of those checks is slow or unreachable - most often a remote secondmate host - and the stage stopped rather than letting it wedge; a `lock was no longer held` line means the session that asked for the sweeps no longer owns them, so leave them to the session that does. - `TANGLE: ` - the primary checkout is stranded on a feature branch instead of its default branch; `AGENTS.md` section 8 explains why this guard exists and what it protects. - The work is safe on that branch ref; restore the primary to its default branch with the printed `git -C checkout `, then re-validate that branch in a proper worktree. + The work is safe on that branch ref; restore the primary to its default branch with the printed `git -C switch `, then re-validate that branch in a proper worktree. This is the only sanctioned firstmate-initiated git write to the primary, and it is a non-destructive branch switch that strands nothing. - `STARTUP_MEMORY_BUDGET: invalid config/startup-memory-budget - ` - the visible startup-memory budget is not a safe one-line positive decimal file; do not infer the default or propagate it. Correct the local primary file, then rerun session start so the normal convergence path can deliver the validated value to secondmate homes. diff --git a/bin/fm-bootstrap.sh b/bin/fm-bootstrap.sh index 62568cf5771..096ea89f842 100755 --- a/bin/fm-bootstrap.sh +++ b/bin/fm-bootstrap.sh @@ -84,7 +84,7 @@ # secondmate_handoff_resume, x_mode_setup, fleet_sync) while still # printing every read-only detect line # above; the TANGLE line switches to advisory-only wording with no -# checkout command. Used by +# branch-restore command. Used by # fm-session-start.sh's read-only path when another live session holds # the fleet lock, so a second concurrent session never race-mutates # PR-check artifacts, secondmate homes, pending handoff outboxes, @@ -1250,7 +1250,7 @@ detect_local_config() { if [ "${FM_BOOTSTRAP_DETECT_ONLY:-0}" = 1 ] && [ "${FM_BOOTSTRAP_LOCKED:-0}" != 1 ]; then echo "TANGLE: primary checkout on feature branch '$tangle_branch' (expected '$tangle_default'); the work is safe on that ref - read-only session must leave restore work to the session holding the fleet lock" else - echo "TANGLE: primary checkout on feature branch '$tangle_branch' (expected '$tangle_default'); the work is safe on that ref - restore the primary with: git -C $FM_ROOT checkout $tangle_default, then re-validate the branch in a proper worktree" + echo "TANGLE: primary checkout on feature branch '$tangle_branch' (expected '$tangle_default'); the work is safe on that ref - restore the primary with: git -C $FM_ROOT switch $tangle_default, then re-validate the branch in a proper worktree" fi fi crew= diff --git a/bin/fm-brief.sh b/bin/fm-brief.sh index 116cfd23e9a..fa73f944cc6 100755 --- a/bin/fm-brief.sh +++ b/bin/fm-brief.sh @@ -447,7 +447,7 @@ You are in a disposable git worktree of $REPO, at a detached HEAD on a clean def The path check is authoritative: \`git rev-parse --git-dir\` and \`git rev-parse --git-common-dir\` can help inspect the repo, but they do not prove you are outside the primary checkout. If the top-level path is the primary checkout or not the worktree you were launched in, STOP - do not branch or commit here - append \`blocked: launched in primary checkout, not an isolated worktree\` to the status file and stop. -1. First action: create your branch: \`git checkout -b fm/$ID\`$SETUP2 +1. First action: create your branch: \`git switch -c fm/$ID\`$SETUP2 # Rules $RULE1 diff --git a/bin/fm-guard.sh b/bin/fm-guard.sh index 21d6da3ed81..62942177810 100755 --- a/bin/fm-guard.sh +++ b/bin/fm-guard.sh @@ -141,7 +141,7 @@ if [ -n "$tangle_branch" ]; then printf '● This read-only session must leave restore work to a session with verified fleet-lock ownership.\n' else printf "● Restore the primary to '%s':\n" "$tangle_default" - printf '● git -C %s checkout %s\n' "$FM_ROOT" "$tangle_default" + printf '● git -C %s switch %s\n' "$FM_ROOT" "$tangle_default" printf "● then re-validate '%s' in a proper isolated worktree.\n" "$tangle_branch" fi printf '●%s\n' "$trule" diff --git a/docs/configuration.md b/docs/configuration.md index 62a7db10610..21af841e1ef 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -336,7 +336,7 @@ An absent or incompatible `gh-axi` reports `MISSING: gh-axi (install: npm instal An absent or incompatible `lavish-axi` reports `MISSING: lavish-axi (install: npm install -g lavish-axi && lavish-axi setup hooks)`. An absent or too-old `quota-axi` reports `MISSING: quota-axi (install: npm install -g quota-axi)`; firstmate cannot resolve a profile array without a compatible binary. Bootstrap also reports a `TANGLE:` line when `FM_ROOT` is on a named non-default branch; follow the printed checkout remediation rather than treating it as an installable tool problem. -In a read-only session that did not get the fleet lock, the same line is advisory and omits the checkout command. +In a read-only session that did not get the fleet lock, the same line is advisory and omits the branch-restore command. The locked session-start deferred network stage runs bootstrap's best-effort project clone refresh through `fm-fleet-sync.sh`; [`fm-bootstrap.sh`'s header](../bin/fm-bootstrap.sh) owns the exact clone-refresh overlap, liveness-before-convergence, per-mate concurrency, ordered diagnostic replay, and sequential-fallback contract. It emits `FLEET_SYNC:` for skipped refreshes that may matter, recovered self-heals, and `STUCK:` alarms. Normal completed runs keep local-only and no-origin skips silent. diff --git a/tests/fm-session-start.test.sh b/tests/fm-session-start.test.sh index e74eceb7abf..614365aae6d 100755 --- a/tests/fm-session-start.test.sh +++ b/tests/fm-session-start.test.sh @@ -779,7 +779,7 @@ EOF assert_not_contains "$out" "drain them with bin/fm-wake-drain.sh" "read-only guard printed a mutating drain instruction" assert_not_contains "$out" "After draining queued wakes" "read-only guard printed a drain-then-rearm instruction" assert_not_contains "$out" "run bin/fm-watch-arm.sh" "read-only guard printed a mutating watcher-arm instruction" - assert_not_contains "$out" "git -C $root checkout main" "read-only bootstrap printed a state-changing checkout remediation" + assert_not_contains "$out" "git -C $root switch main" "read-only bootstrap printed a state-changing checkout remediation" # Detect-only bootstrap diagnostics still ran (the fakebin's PATH excludes # tasks-axi, so bootstrap's own read-only tool-detection line fires @@ -2219,7 +2219,7 @@ EOF # A re-emit skips the sweeps because it ALREADY ran them, not because it lacks # the lock, so it must still own repair rather than deferring to a lock holder. - assert_contains "$reemit" "restore the primary with: git -C $root checkout main" \ + assert_contains "$reemit" "restore the primary with: git -C $root switch main" \ "--reemit disowned a repair it is entitled to perform" assert_not_contains "$reemit" "must leave restore work to the session holding the fleet lock" \ "--reemit misreported itself as an unlocked read-only session" diff --git a/tests/fm-tangle-guard.test.sh b/tests/fm-tangle-guard.test.sh index 64aabe6400e..9d99bb84a20 100755 --- a/tests/fm-tangle-guard.test.sh +++ b/tests/fm-tangle-guard.test.sh @@ -83,11 +83,11 @@ test_guard_banner() { out=$(run_guard "$repo") assert_contains "$out" "WORKTREE TANGLE" "guard did not alarm on a feature branch in the primary" assert_contains "$out" "fm/tangle-aa1" "guard banner did not name the offending branch" - assert_contains "$out" "checkout main" "guard banner did not print the restore remediation" + assert_contains "$out" "switch main" "guard banner did not print the restore remediation" out=$(FM_GUARD_READ_ONLY=1 run_guard "$repo") assert_contains "$out" "WORKTREE TANGLE" "read-only guard did not keep the tangle alarm" assert_contains "$out" "read-only session must leave restore work" "read-only guard did not explain restore ownership" - assert_not_contains "$out" "checkout main" "read-only guard printed a state-changing restore command" + assert_not_contains "$out" "switch main" "read-only guard printed a state-changing restore command" pass "fm-guard: bordered tangle banner fires only for a feature branch and suppresses repair commands in read-only mode" } @@ -112,18 +112,18 @@ test_bootstrap_line() { git -C "$repo" checkout -q -B fm/tangle-bb2 out=$(run_bootstrap "$repo" | grep '^TANGLE:' || true) assert_contains "$out" "fm/tangle-bb2" "bootstrap did not report the tangled branch" - assert_contains "$out" "checkout main" "bootstrap TANGLE line lacked the restore remediation" + assert_contains "$out" "switch main" "bootstrap TANGLE line lacked the restore remediation" out=$(FM_ROOT_OVERRIDE="$repo" FM_HOME="$repo" FM_BOOTSTRAP_DETECT_ONLY=1 "$ROOT/bin/fm-bootstrap.sh" 2>/dev/null | grep '^TANGLE:' || true) assert_contains "$out" "fm/tangle-bb2" "detect-only bootstrap did not report the tangled branch" assert_contains "$out" "read-only session must leave restore work" "detect-only bootstrap did not explain restore ownership" - assert_not_contains "$out" "checkout main" "detect-only bootstrap printed a state-changing restore command" + assert_not_contains "$out" "switch main" "detect-only bootstrap printed a state-changing restore command" pass "fm-bootstrap: TANGLE problem line fires only for a feature branch and suppresses repair commands in detect-only mode" } # --- GUARD 1a: brief isolation assertion ------------------------------------ # The generated ship brief must carry the isolation assertion AHEAD of the -# `git checkout -b` step, so the crewmate verifies its worktree before branching. +# `git switch -c` step, so the crewmate verifies its worktree before branching. test_brief_assertion_precedes_branch() { local home brief iso br home="$TMP_ROOT/brief-home" @@ -140,7 +140,7 @@ test_brief_assertion_precedes_branch() { assert_no_grep "they are identical in the primary checkout" "$brief" \ "brief must not claim the primary checkout has identical git dirs" iso=$(grep -n 'launched in primary checkout, not an isolated worktree' "$brief" | head -1 | cut -d: -f1) - br=$(grep -n 'git checkout -b fm/' "$brief" | head -1 | cut -d: -f1) + br=$(grep -n 'git switch -c fm/' "$brief" | head -1 | cut -d: -f1) if [ -z "$iso" ] || [ -z "$br" ]; then fail "brief missing assertion ($iso) or branch step ($br)" fi