From defd9b735b53e70e78fe794e20aaa6d8936ff46f Mon Sep 17 00:00:00 2001 From: Haro Date: Sun, 23 Aug 2026 22:08:05 -0300 Subject: [PATCH 1/4] fix(spawn): resolve bare project names from home --- bin/fm-spawn.sh | 26 +++++++++++++++---- tests/fm-tangle-guard.test.sh | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index 325eefd389..88dbe31ef7 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # Spawn a direct report: a crewmate in a treehouse or Orca worktree, or a # secondmate in its isolated firstmate home. -# Usage: fm-spawn.sh --mode --yolo [--harness |harness|launch-command] [--model ] [--effort ] [--backend ] -# fm-spawn.sh --scout [--harness |harness|launch-command] [--model ] [--effort ] [--backend ] +# Usage: fm-spawn.sh --mode --yolo [--harness |harness|launch-command] [--model ] [--effort ] [--backend ] +# fm-spawn.sh --scout [--harness |harness|launch-command] [--model ] [--effort ] [--backend ] # fm-spawn.sh [] [--harness |harness|launch-command] [--model ] [--effort ] [--backend ] --secondmate # --mode and --yolo are this task's delivery contract, REQUIRED for every ship # spawn and refused on --scout and --secondmate spawns. Firstmate resolves both @@ -134,6 +134,8 @@ # default-branch commit when safe; skipped syncs warn and launch unchanged. # Ship/scout spawns refuse to launch unless the resolved task path is a real # git worktree root distinct from the primary project checkout. +# A bare project name and a projects/ argument resolve against this +# home's projects dir before a relative path in the caller's cwd is considered. # Before a fresh ship or scout worker starts, its clean task worktree fetches # origin, resolves the current remote default branch, and resets to its tip. # An unreachable origin, unresolved default branch, or non-clean worktree @@ -1483,10 +1485,20 @@ resolved_existing_dir() { } resolve_project_dir_arg() { - local path=$1 + local path=$1 candidate case "$path" in projects/*) printf '%s/%s\n' "$PROJECTS" "${path#projects/}" ;; - *) printf '%s\n' "$path" ;; + */*) printf '%s\n' "$path" ;; + *) + candidate="$PROJECTS/$path" + if [ -d "$candidate" ]; then + printf '%s\n' "$candidate" + elif [ -d "$path" ]; then + printf '%s\n' "$path" + else + printf '%s\n' "$candidate" + fi + ;; esac } @@ -1652,7 +1664,11 @@ if [ "$KIND" = secondmate ]; then BRIEF="$DATA/$ID/brief.md" fi else - PROJ_ABS="$(cd "$(resolve_project_dir_arg "$PROJ")" && pwd)" + PROJ_RESOLVED=$(resolve_project_dir_arg "$PROJ") + if ! PROJ_ABS=$(CDPATH='' cd -- "$PROJ_RESOLVED" 2>/dev/null && pwd); then + echo "error: project directory cannot be resolved: $PROJ (tried '$PROJ_RESOLVED')" >&2 + exit 1 + fi WT="" BRIEF="$DATA/$ID/brief.md" fi diff --git a/tests/fm-tangle-guard.test.sh b/tests/fm-tangle-guard.test.sh index 64aabe6400..667a70d91d 100755 --- a/tests/fm-tangle-guard.test.sh +++ b/tests/fm-tangle-guard.test.sh @@ -186,6 +186,19 @@ run_spawn() { "$ROOT/bin/fm-spawn.sh" "$id" "$proj" codex --mode no-mistakes --yolo off 2>&1 } +run_scout_spawn() { + local home=$1 id=$2 proj=$3 pane=$4 fakebin=$5 + mkdir -p "$home/data/$id" + printf 'brief\n' > "$home/data/$id/brief.md" + FM_ROOT_OVERRIDE='' FM_HOME="$home" \ + FM_STATE_OVERRIDE="$home/state" FM_DATA_OVERRIDE="$home/data" \ + FM_PROJECTS_OVERRIDE="$home/projects" FM_CONFIG_OVERRIDE="$home/config" \ + FM_SPAWN_NO_GUARD=1 FM_FAKE_PANE_PATH="$pane" TMUX="fake,1,0" \ + PATH="$fakebin:$PATH" \ + "$ROOT/bin/fm-spawn.sh" "$id" "$proj" --scout --harness codex \ + --model gpt-5.6-sol --effort medium 2>&1 +} + test_spawn_isolation_abort() { local home proj fakebin out status home="$TMP_ROOT/spawn-home" @@ -215,6 +228,40 @@ test_spawn_isolation_abort() { pass "fm-spawn: aborts unless the resolved worktree is a genuine, isolated worktree" } +# The real reconcile-github-delivery-state scout passed the bare project name +# `analytics`, while earlier successful analytics spawns passed projects/analytics. +# Pin the complete corrected path: a bare name resolves through FM_HOME/projects, +# treehouse reports a distinct linked worktree, and only that isolated root is +# published in task metadata. +test_spawn_bare_project_name_reaches_isolated_worktree() { + local home project wt caller fakebin out status meta + home="$TMP_ROOT/reconcile-home" + project="$home/projects/analytics" + wt="$TMP_ROOT/reconcile-analytics-wt" + caller="$TMP_ROOT/reconcile-caller" + mkdir -p "$home/projects" "$caller/analytics" + make_repo "$project" >/dev/null + git -C "$project" worktree add -q --detach "$wt" >/dev/null 2>&1 + fakebin=$(make_spawn_fakebin "$TMP_ROOT/reconcile-fake") + + out=$(cd "$caller" && run_scout_spawn "$home" reconcile-github-delivery-state analytics "$wt" "$fakebin") + status=$? + expect_code 0 "$status" "bare-name scout spawn should reach an isolated worktree" + assert_contains "$out" "spawned reconcile-github-delivery-state harness=codex kind=scout" \ + "bare-name scout spawn did not report success" + assert_contains "$out" "worktree=$wt" \ + "bare-name scout spawn did not report the isolated treehouse worktree" + meta="$home/state/reconcile-github-delivery-state.meta" + assert_grep "project=$project" "$meta" \ + "bare project name did not resolve against the firstmate home's projects dir" + assert_grep "worktree=$wt" "$meta" \ + "spawn metadata did not publish the isolated worktree" + [ "$(git -C "$wt" rev-parse --show-toplevel)" = "$wt" ] \ + || fail "resolved target is not the linked-worktree root" + [ "$wt" != "$project" ] || fail "resolved worktree equals the primary project checkout" + pass "fm-spawn: a bare project name reaches a genuine isolated worktree" +} + # --- GUARD 1c: fm-spawn tmux window construction ---------------------------- # The prevention guard also depends on fm-spawn building robust tmux commands @@ -307,4 +354,5 @@ test_guard_banner test_bootstrap_line test_brief_assertion_precedes_branch test_spawn_isolation_abort +test_spawn_bare_project_name_reaches_isolated_worktree test_spawn_tmux_window_construction From 356d114f8c759331b94fd2a46fd8d2a8b8a3c328 Mon Sep 17 00:00:00 2001 From: Haro Date: Sun, 23 Aug 2026 22:25:12 -0300 Subject: [PATCH 2/4] no-mistakes(review): Captain, preserve relative paths and split spawn regressions --- bin/fm-spawn.sh | 1 + tests/fm-tangle-guard.test.sh | 97 ++++++++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 14 deletions(-) diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index 88dbe31ef7..37eb2466df 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -1487,6 +1487,7 @@ resolved_existing_dir() { resolve_project_dir_arg() { local path=$1 candidate case "$path" in + .|..) printf '%s\n' "$path" ;; projects/*) printf '%s/%s\n' "$PROJECTS" "${path#projects/}" ;; */*) printf '%s\n' "$path" ;; *) diff --git a/tests/fm-tangle-guard.test.sh b/tests/fm-tangle-guard.test.sh index 667a70d91d..e42d740d23 100755 --- a/tests/fm-tangle-guard.test.sh +++ b/tests/fm-tangle-guard.test.sh @@ -228,30 +228,31 @@ test_spawn_isolation_abort() { pass "fm-spawn: aborts unless the resolved worktree is a genuine, isolated worktree" } -# The real reconcile-github-delivery-state scout passed the bare project name -# `analytics`, while earlier successful analytics spawns passed projects/analytics. -# Pin the complete corrected path: a bare name resolves through FM_HOME/projects, -# treehouse reports a distinct linked worktree, and only that isolated root is -# published in task metadata. -test_spawn_bare_project_name_reaches_isolated_worktree() { +# Initiating trigger: the reconcile-github-delivery-state scout passed the bare +# project name `analytics`, while earlier successful spawns passed +# projects/analytics. Without a caller cwd shadow, the old resolver stopped +# before metadata, which was the visible symptom. +test_spawn_bare_project_name_reproduces_no_shadow_sequence() { local home project wt caller fakebin out status meta - home="$TMP_ROOT/reconcile-home" + home="$TMP_ROOT/reconcile-no-shadow-home" project="$home/projects/analytics" - wt="$TMP_ROOT/reconcile-analytics-wt" - caller="$TMP_ROOT/reconcile-caller" - mkdir -p "$home/projects" "$caller/analytics" + wt="$TMP_ROOT/reconcile-no-shadow-wt" + caller="$TMP_ROOT/reconcile-no-shadow-caller" + mkdir -p "$home/projects" "$caller" make_repo "$project" >/dev/null git -C "$project" worktree add -q --detach "$wt" >/dev/null 2>&1 - fakebin=$(make_spawn_fakebin "$TMP_ROOT/reconcile-fake") + fakebin=$(make_spawn_fakebin "$TMP_ROOT/reconcile-no-shadow-fake") + assert_absent "$caller/analytics" "no-shadow regression setup unexpectedly contains an analytics shadow" out=$(cd "$caller" && run_scout_spawn "$home" reconcile-github-delivery-state analytics "$wt" "$fakebin") status=$? + meta="$home/state/reconcile-github-delivery-state.meta" + assert_present "$meta" "original visible symptom recurred: no task metadata was created" expect_code 0 "$status" "bare-name scout spawn should reach an isolated worktree" assert_contains "$out" "spawned reconcile-github-delivery-state harness=codex kind=scout" \ "bare-name scout spawn did not report success" assert_contains "$out" "worktree=$wt" \ "bare-name scout spawn did not report the isolated treehouse worktree" - meta="$home/state/reconcile-github-delivery-state.meta" assert_grep "project=$project" "$meta" \ "bare project name did not resolve against the firstmate home's projects dir" assert_grep "worktree=$wt" "$meta" \ @@ -259,7 +260,73 @@ test_spawn_bare_project_name_reaches_isolated_worktree() { [ "$(git -C "$wt" rev-parse --show-toplevel)" = "$wt" ] \ || fail "resolved target is not the linked-worktree root" [ "$wt" != "$project" ] || fail "resolved worktree equals the primary project checkout" - pass "fm-spawn: a bare project name reaches a genuine isolated worktree" + pass "fm-spawn: the no-shadow bare-name scout reaches a genuine isolated worktree" +} + +# Masking condition: a caller cwd directory named `analytics` let the old +# resolver proceed while silently selecting that shadow instead of the active +# Firstmate home's registered project. +test_spawn_bare_project_name_ignores_cwd_shadow() { + local home project wt caller fakebin out status meta + home="$TMP_ROOT/reconcile-shadow-home" + project="$home/projects/analytics" + wt="$TMP_ROOT/reconcile-shadow-wt" + caller="$TMP_ROOT/reconcile-shadow-caller" + mkdir -p "$home/projects" "$caller/analytics" + make_repo "$project" >/dev/null + git -C "$project" worktree add -q --detach "$wt" >/dev/null 2>&1 + fakebin=$(make_spawn_fakebin "$TMP_ROOT/reconcile-shadow-fake") + + out=$(cd "$caller" && run_scout_spawn "$home" reconcile-github-delivery-state-shadow analytics "$wt" "$fakebin") + status=$? + expect_code 0 "$status" "cwd-shadow bare-name scout spawn should reach an isolated worktree" + assert_contains "$out" "spawned reconcile-github-delivery-state-shadow harness=codex kind=scout" \ + "cwd-shadow bare-name scout spawn did not report success" + assert_contains "$out" "worktree=$wt" \ + "cwd-shadow bare-name scout spawn did not report the isolated treehouse worktree" + meta="$home/state/reconcile-github-delivery-state-shadow.meta" + assert_grep "project=$project" "$meta" \ + "cwd shadow captured the bare project name instead of the home registry project" + assert_no_grep "project=$caller/analytics" "$meta" \ + "spawn metadata published the caller cwd shadow" + assert_grep "worktree=$wt" "$meta" \ + "cwd-shadow spawn metadata did not publish the isolated worktree" + [ "$(git -C "$wt" rev-parse --show-toplevel)" = "$wt" ] \ + || fail "cwd-shadow target is not the linked-worktree root" + [ "$wt" != "$project" ] || fail "cwd-shadow worktree equals the primary project checkout" + pass "fm-spawn: the home registry project wins over a caller cwd shadow" +} + +test_spawn_dot_project_args_remain_caller_relative() { + local home project subdir dot_wt dotdot_wt fakebin out status meta + home="$TMP_ROOT/relative-home" + project=$(make_repo "$TMP_ROOT/relative-project") + subdir="$project/subdir" + dot_wt="$TMP_ROOT/relative-dot-wt" + dotdot_wt="$TMP_ROOT/relative-dotdot-wt" + mkdir -p "$home/projects" "$subdir" + git -C "$project" worktree add -q --detach "$dot_wt" >/dev/null 2>&1 + git -C "$project" worktree add -q --detach "$dotdot_wt" >/dev/null 2>&1 + fakebin=$(make_spawn_fakebin "$TMP_ROOT/relative-fake") + + out=$(cd "$project" && run_scout_spawn "$home" relative-dot-project . "$dot_wt" "$fakebin") + status=$? + expect_code 0 "$status" "dot project argument should remain caller-relative" + assert_contains "$out" "spawned relative-dot-project harness=codex kind=scout" \ + "dot project argument spawn did not report success" + meta="$home/state/relative-dot-project.meta" + assert_grep "project=$project" "$meta" \ + "dot project argument did not resolve to the caller's project" + + out=$(cd "$subdir" && run_scout_spawn "$home" relative-dotdot-project .. "$dotdot_wt" "$fakebin") + status=$? + expect_code 0 "$status" "dotdot project argument should remain caller-relative" + assert_contains "$out" "spawned relative-dotdot-project harness=codex kind=scout" \ + "dotdot project argument spawn did not report success" + meta="$home/state/relative-dotdot-project.meta" + assert_grep "project=$project" "$meta" \ + "dotdot project argument did not resolve to the caller's project" + pass "fm-spawn: dot and dotdot project arguments stay caller-relative" } # --- GUARD 1c: fm-spawn tmux window construction ---------------------------- @@ -354,5 +421,7 @@ test_guard_banner test_bootstrap_line test_brief_assertion_precedes_branch test_spawn_isolation_abort -test_spawn_bare_project_name_reaches_isolated_worktree +test_spawn_bare_project_name_reproduces_no_shadow_sequence +test_spawn_bare_project_name_ignores_cwd_shadow +test_spawn_dot_project_args_remain_caller_relative test_spawn_tmux_window_construction From 36a5534e260195e5da4afb28cc292f51cf1b0d82 Mon Sep 17 00:00:00 2001 From: Haro Date: Sun, 23 Aug 2026 22:31:35 -0300 Subject: [PATCH 3/4] no-mistakes(review): Captain, enforce home-only bare project resolution --- bin/fm-spawn.sh | 18 +++++------------ tests/fm-tangle-guard.test.sh | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/bin/fm-spawn.sh b/bin/fm-spawn.sh index 37eb2466df..c000969c8e 100755 --- a/bin/fm-spawn.sh +++ b/bin/fm-spawn.sh @@ -134,8 +134,9 @@ # default-branch commit when safe; skipped syncs warn and launch unchanged. # Ship/scout spawns refuse to launch unless the resolved task path is a real # git worktree root distinct from the primary project checkout. -# A bare project name and a projects/ argument resolve against this -# home's projects dir before a relative path in the caller's cwd is considered. +# A bare project name and a projects/ argument resolve only against this +# home's projects dir. The explicit relative paths . and .. and every other +# path containing a slash retain the caller-supplied path semantics. # Before a fresh ship or scout worker starts, its clean task worktree fetches # origin, resolves the current remote default branch, and resets to its tip. # An unreachable origin, unresolved default branch, or non-clean worktree @@ -1485,21 +1486,12 @@ resolved_existing_dir() { } resolve_project_dir_arg() { - local path=$1 candidate + local path=$1 case "$path" in .|..) printf '%s\n' "$path" ;; projects/*) printf '%s/%s\n' "$PROJECTS" "${path#projects/}" ;; */*) printf '%s\n' "$path" ;; - *) - candidate="$PROJECTS/$path" - if [ -d "$candidate" ]; then - printf '%s\n' "$candidate" - elif [ -d "$path" ]; then - printf '%s\n' "$path" - else - printf '%s\n' "$candidate" - fi - ;; + *) printf '%s/%s\n' "$PROJECTS" "$path" ;; esac } diff --git a/tests/fm-tangle-guard.test.sh b/tests/fm-tangle-guard.test.sh index e42d740d23..2b4eb162b4 100755 --- a/tests/fm-tangle-guard.test.sh +++ b/tests/fm-tangle-guard.test.sh @@ -297,6 +297,41 @@ test_spawn_bare_project_name_ignores_cwd_shadow() { pass "fm-spawn: the home registry project wins over a caller cwd shadow" } +test_spawn_missing_bare_project_refuses_cwd_shadow() { + local home caller shadow wt fakebin out status meta + home="$TMP_ROOT/missing-bare-home" + caller="$TMP_ROOT/missing-bare-caller" + shadow="$caller/analytics" + wt="$TMP_ROOT/missing-bare-shadow-wt" + mkdir -p "$home/projects" "$caller" + make_repo "$shadow" >/dev/null + git -C "$shadow" worktree add -q --detach "$wt" >/dev/null 2>&1 + fakebin=$(make_spawn_fakebin "$TMP_ROOT/missing-bare-fake") + + out=$(cd "$caller" && run_scout_spawn "$home" missing-home-bare-project analytics "$wt" "$fakebin") + status=$? + expect_code 1 "$status" "missing home project should refuse a same-name cwd shadow" + assert_contains "$out" "project directory cannot be resolved: analytics" \ + "missing home project did not report a clear resolution error" + assert_contains "$out" "tried '$home/projects/analytics'" \ + "missing home project diagnostic did not name the home-scoped target" + meta="$home/state/missing-home-bare-project.meta" + assert_absent "$meta" "missing bare project captured the cwd shadow and published metadata" + assert_not_contains "$out" "spawned missing-home-bare-project" \ + "missing bare project launched from the cwd shadow" + pass "fm-spawn: a missing bare project refuses a same-name cwd shadow" +} + +test_spawn_project_argument_help() { + local out + out=$("$ROOT/bin/fm-spawn.sh" --help) + assert_contains "$out" "bare project name and a projects/ argument resolve only" \ + "spawn help did not state that bare names are strictly home-scoped" + assert_contains "$out" "explicit relative paths . and .. and every other" \ + "spawn help did not distinguish caller-supplied path arguments" + pass "fm-spawn: help distinguishes home-scoped names from explicit paths" +} + test_spawn_dot_project_args_remain_caller_relative() { local home project subdir dot_wt dotdot_wt fakebin out status meta home="$TMP_ROOT/relative-home" @@ -423,5 +458,7 @@ test_brief_assertion_precedes_branch test_spawn_isolation_abort test_spawn_bare_project_name_reproduces_no_shadow_sequence test_spawn_bare_project_name_ignores_cwd_shadow +test_spawn_missing_bare_project_refuses_cwd_shadow +test_spawn_project_argument_help test_spawn_dot_project_args_remain_caller_relative test_spawn_tmux_window_construction From f10f54f529ab50208a0b84640160239c53590947 Mon Sep 17 00:00:00 2001 From: Haro Date: Sun, 23 Aug 2026 23:43:02 -0300 Subject: [PATCH 4/4] no-mistakes: apply CI fixes --- .agents/skills/bootstrap-diagnostics/SKILL.md | 2 +- CONTRIBUTING.md | 2 +- bin/fm-bootstrap.sh | 5 +++-- tests/fm-bootstrap.test.sh | 9 +++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.agents/skills/bootstrap-diagnostics/SKILL.md b/.agents/skills/bootstrap-diagnostics/SKILL.md index 0aad884638..118e10d86f 100644 --- a/.agents/skills/bootstrap-diagnostics/SKILL.md +++ b/.agents/skills/bootstrap-diagnostics/SKILL.md @@ -18,7 +18,7 @@ When any diagnostic needs captain attention, report the plain consequence and re - `MISSING: (install: )` - list the missing tools to the captain with a one-line purpose each plus the printed install commands, wait for consent (one approval may cover the list), then run `bin/fm-bootstrap.sh install `. For `treehouse`, this also covers an installed version whose `treehouse get` lacks `--lease`; treat it as an upgrade request. - For `no-mistakes`, this also covers an installed version older than 1.31.2, because crewmate validation briefs delegate gate mechanics to no-mistakes' version-matched guidance. + For `no-mistakes`, this also covers an installed version older than `bin/fm-bootstrap.sh`'s `NO_MISTAKES_MIN` floor, which tracks the structured step-attestation requirement enforced by `.github/workflows/no-mistakes-required.yml`. For any axi-family tool - `gh-axi`, `lavish-axi`, `tasks-axi`, `quota-axi` - an installed version below its floor is a plain upgrade request; [`bin/fm-bootstrap.sh`](../../../bin/fm-bootstrap.sh) owns the floor policy, and never argue the floor down to whatever the home happens to have installed. For `tasks-axi`, this additionally covers an installed build that fails the separate feature probe (`bin/fm-tasks-axi-lib.sh` owns the definition); `config/backlog-backend=manual` only suppresses the verbose `BOOTSTRAP_INFO: tasks-axi available` fact, not this missing-tool report. For `quota-axi`, bootstrap requires it because firstmate reads its current output directly before resolving every crew-dispatch profile array; without it, report the missing requirement and do not choose around an unexamined candidate. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 19aa158b09..678ab6042c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ GitHub Actions and Dependabot are exempt so their automation keeps working, but 1. Fork the repo, then clone the parent repo or set your local `origin` back to the parent (`git@github.com:kunchenguid/firstmate.git`). 2. Create a branch and make your changes. -3. Initialize the gate with your fork as the push target: `no-mistakes init --fork-url git@github.com:/firstmate.git` (firstmate expects **no-mistakes v1.31.2+**; without a fork, plain `no-mistakes init` still works for maintainers with push access). +3. Initialize the gate with your fork as the push target: `no-mistakes init --fork-url git@github.com:/firstmate.git` (firstmate expects **no-mistakes v1.46.0+** so the PR carries the required structured step attestation; without a fork, plain `no-mistakes init` still works for maintainers with push access). 4. Commit your changes. 5. Push through the gate instead of pushing to `origin`: diff --git a/bin/fm-bootstrap.sh b/bin/fm-bootstrap.sh index 47203fc17b..33a07ba9f0 100755 --- a/bin/fm-bootstrap.sh +++ b/bin/fm-bootstrap.sh @@ -51,7 +51,8 @@ # treehouse is also MISSING when its installed version lacks # "treehouse get --lease" support. # no-mistakes is also MISSING when its installed version is older than -# 1.31.2. +# 1.46.0, the first release that emits the structured pipeline step +# attestation required by this repository's PR compliance workflow. # The AXI-family floor policy is owned beside GH_AXI_MIN and # LAVISH_AXI_MIN below; the per-tool owners point there. An installed # build below its floor reports MISSING like no-mistakes, so the operator @@ -792,7 +793,7 @@ if ! BACKEND_TOOLS=$(fm_backend_required_tools "$BACKEND"); then BACKEND_TOOLS="" fi TOOLS="$BACKEND_TOOLS $COMMON_TOOLS" -NO_MISTAKES_MIN=1.31.2 +NO_MISTAKES_MIN=1.46.0 # AXI-FAMILY FLOOR POLICY. Every axi-family floor is the CURRENT LATEST published # version of that tool, captain-bumped periodically to keep the whole fleet on the # newest axi tools. It is NOT the minimum feature-introduced version. These floors diff --git a/tests/fm-bootstrap.test.sh b/tests/fm-bootstrap.test.sh index 1810e6b5f0..3dec947b53 100755 --- a/tests/fm-bootstrap.test.sh +++ b/tests/fm-bootstrap.test.sh @@ -79,7 +79,7 @@ SH cat > "$fakebin/no-mistakes" <<'SH' #!/usr/bin/env bash if [ "${1:-}" = --version ]; then - printf '%s\n' "${FM_FAKE_NO_MISTAKES_VERSION:-no-mistakes version v1.31.2 (fake) 2026-06-27T00:02:18Z}" + printf '%s\n' "${FM_FAKE_NO_MISTAKES_VERSION:-no-mistakes version v1.46.0 (fake) 2026-08-24T00:00:00Z}" exit 0 fi exit 0 @@ -332,10 +332,11 @@ test_no_mistakes_min_version() { [ "$out" = "$missing" ] || fail "$label: expected '$missing', got: $out" ;; esac done <<'ROWS' -minimum no-mistakes version is accepted^no-mistakes version v1.31.2 (fake)^empty -newer no-mistakes minor is accepted^no-mistakes version v1.32.0 (fake)^empty +minimum no-mistakes version is accepted^no-mistakes version v1.46.0 (fake)^empty +newer no-mistakes minor is accepted^no-mistakes version v1.47.0 (fake)^empty newer no-mistakes major is accepted^no-mistakes version v2.0.0 (fake)^empty -older no-mistakes patch reports an upgrade^no-mistakes version v1.31.1 (fake)^missing +pre-attestation no-mistakes version reports an upgrade^no-mistakes version v1.45.9 (fake)^missing +formerly accepted no-mistakes version reports an upgrade^no-mistakes version v1.31.2 (fake)^missing unparseable no-mistakes version reports an upgrade^no-mistakes development build^missing ROWS pass "bootstrap enforces no-mistakes minimum version"