// scripts/queue-commit.sh and the queue guard (8.12): F1, the bootstrap (F3) // and the general cases. Every run is in a scratch repository with the // scripts committed; nothing touches this checkout's .git. // // Schedules use PATH shims for git and node. Each shim calls // /on-git or /on-node, when present, before and after the real // command, and the call blocks, so an action runs at an exact point in the // procedure. Actions run with the original PATH, so they reach real git. import { strict as assert } from "node:assert"; import { spawn } from "node:child_process"; import { createHash } from "node:crypto"; import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { test } from "node:test"; import { sleepMs } from "../src/io.mjs"; import { cli, scratchRepo, sh } from "./helpers.mjs"; const QJSON = "docs/plans/queue.json"; const QMD = "docs/plans/QUEUE.md"; const FIX = `git reset -q -- ${QJSON} ${QMD}`; const GUARD = "mosaic queue guard: refused"; const REAL_GIT = sh("sh", ["-c", "command -v git"]).stdout.trim(); function q(s) { return `'${String(s).replaceAll("'", "'\\''")}'`; } function sha256(buf) { return createHash("sha256").update(buf).digest("hex"); } // A repository with the scripts, the guard installed by sage and, unless // `bootstrap` is set, genesis committed through queue-commit.sh. function ready(t, { bootstrap = false } = {}) { const repo = scratchRepo(t, { scripts: true }); const ctl = join(repo.base, "ctl"); const shimDir = join(repo.base, "shims"); mkdirSync(ctl); mkdirSync(shimDir); const origPath = repo.env.PATH; for (const [name, real] of [["git", REAL_GIT], ["node", process.execPath]]) { const on = join(ctl, `on-${name}`); writeFileSync(join(shimDir, name), [ "#!/bin/sh", `if [ -x ${q(on)} ]; then PATH=${q(origPath)} ${q(on)} before "$@" >${q(join(ctl, "log"))} 2>&1; fi`, `${q(real)} "$@"; s=$?`, `if [ -x ${q(on)} ]; then PATH=${q(origPath)} ${q(on)} after "$s" "$@" >${q(join(ctl, "log"))} 2>&1; fi`, "exit $s", "", ].join("\n"), { mode: 0o755 }); } const r = { ...repo, ctl, hook: join(repo.gitDir, "hooks/pre-commit"), // Runs queue-commit.sh through the shims. qc(args, env = {}) { const res = sh("bash", [join(repo.root, "scripts/queue-commit.sh"), ...args], { cwd: repo.root, env: { ...repo.env, PATH: `${shimDir}:${origPath}`, ...env }, allowFail: true, }); return { code: res.status, out: res.stdout, err: res.stderr }; }, // Installs an action. `body` is bash; $phase is before or after, $status // the exit status after, $sub the git subcommand, $@ the arguments. on(name, body) { writeFileSync(join(ctl, `on-${name}`), [ "#!/bin/bash", "phase=$1; shift; status=", 'if [ "$phase" = after ]; then status=$1; shift; fi', 'a=("$@"); i=0; while [ "${a[i]:-}" = -C ]; do i=$((i+2)); done; sub=${a[i]:-}', `CTL=${q(ctl)}; R=${q(repo.root)}`, "unset GIT_INDEX_FILE", 'once() { [ -e "$CTL/once-$1" ] && return 1; : > "$CTL/once-$1"; }', 'echo "$phase $sub" >> "$CTL/calls-$(basename "$0")"', body, "", ].join("\n"), { mode: 0o755 }); }, off(name) { rmSync(join(ctl, `on-${name}`), { force: true }); }, calls(name) { const p = join(ctl, `calls-on-${name}`); return existsSync(p) ? readFileSync(p, "utf8").split("\n").filter(Boolean) : []; }, ctlFile(name) { return readFileSync(join(ctl, name), "utf8").trim(); }, head() { return repo.g("rev-parse", "HEAD").trim(); }, blob(rev, path) { return sh("git", ["-C", repo.root, "cat-file", "blob", `${rev}:${path}`], { env: repo.env }).stdout; }, revAt(rev) { return JSON.parse(r.blob(rev, QJSON)).revision; }, }; const inst = r.qc(["--install-hook", "--by", "sage"]); assert.equal(inst.code, 0, inst.err); if (!bootstrap) { genesis(r); const c = r.qc(["--genesis", "-m", "queue genesis"]); assert.equal(c.code, 0, c.err); } return r; } function genesis(r) { const g = cli(r, ["genesis", "--op", "genesis-2026-09-26", "--root", r.root, "--branch", "refactor", "--map", "agents/sage/work/queue-migration-map.md"], { by: "sage" }); assert.equal(g.code, 0, g.err); } let noteN = 0; function note(r, id = 6) { const res = cli(r, ["note", String(id), `note ${++noteN}`, "--op", `note-op-${noteN}`], { by: "darkwing" }); assert.equal(res.code, 0, res.err); return res; } function stageFile(r, name, text = "source\n") { writeFileSync(join(r.root, name), text); r.g("add", "--", name); } function assertUntouched(r, head, res, why) { assert.equal(res.code, 2, `${why}: ${res.err}`); assert.equal(r.head(), head, why); assert.ok(!r.calls("git").includes("before update-ref"), `${why}: update-ref ran`); } // --- F1 --- test("F1: an ordinary commit after update-ref is refused until step 8; then it commits and the queue stays at C", (t) => { const r = ready(t); note(r); r.on("git", `if [ "$phase $sub $status" = "after update-ref 0" ]; then echo src > "$R/src.txt"; git -C "$R" add src.txt git -C "$R" commit -q -m ordinary 2> "$CTL/commit-err"; echo $? > "$CTL/commit-rc" fi`); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 0, res.err); assert.notEqual(r.ctlFile("commit-rc"), "0"); assert.match(r.ctlFile("commit-err"), new RegExp(GUARD)); assert.match(r.ctlFile("commit-err"), new RegExp(FIX.replaceAll(".", "\\."))); const c = r.head(); assert.equal(r.revAt(c), 1); r.off("git"); r.g("commit", "-q", "-m", "ordinary"); assert.equal(r.g("rev-parse", "HEAD^").trim(), c); assert.equal(r.revAt("HEAD"), 1); assert.equal(r.blob("HEAD", "src.txt"), "src\n"); }); // A commit paused in its editor after its guard passed against H. Whether // git holds index.lock during the editor depends on the form: git 2.55 // doesn't for plain `commit -e` and does for `commit -e -- path`. Step 8 // reconciles when the lock is free and exits 3 when it isn't; either way // the paused commit loses at its own HEAD update. async function pausedCommit(t, form) { const r = ready(t); note(r); stageFile(r, "src.txt"); const h = r.head(); const started = join(r.ctl, "editor-started"); const go = join(r.ctl, "editor-go"); const editor = join(r.ctl, "editor.sh"); writeFileSync(editor, `#!/bin/sh\n: > ${q(started)}\nwhile [ ! -e ${q(go)} ]; do sleep 0.05; done\necho "ordinary" > "$1"\n`, { mode: 0o755 }); const child = spawn("git", ["-C", r.root, "commit", "-e", "-q", ...form], { env: { ...r.env, GIT_EDITOR: editor }, stdio: ["ignore", "pipe", "pipe"] }); let childErr = ""; child.stderr.on("data", (d) => { childErr += d; }); const exited = new Promise((resolve) => child.on("exit", resolve)); for (let i = 0; i < 200 && !existsSync(started); i++) sleepMs(50); assert.ok(existsSync(started), "the editor never started"); const locked = existsSync(join(r.gitDir, "index.lock")); t.diagnostic(`git commit -e${form.map((a) => ` ${a}`).join("")}: index.lock ${locked ? "held" : "free"} during the editor`); const res = r.qc(["-m", "queue rev 1"]); writeFileSync(go, ""); const code = await exited; assert.equal(res.code, locked ? 3 : 0, `index.lock ${locked ? "held" : "free"} during the editor: ${res.err}`); if (locked) assert.match(res.err, /another git process holds \.git\/index\.lock/); const c = r.head(); assert.equal(r.g("rev-parse", "HEAD^").trim(), h); assert.equal(r.revAt(c), 1); assert.notEqual(code, 0); assert.match(childErr, new RegExp(`cannot lock ref 'HEAD': is at ${c} but expected ${h}`)); assert.equal(r.head(), c, "the old queue landed on top of C"); if (locked) r.g("reset", "-q", "--", "docs/plans/queue.json", "docs/plans/QUEUE.md"); assert.equal(r.g("diff", "--cached", "--name-only").trim(), "src.txt"); r.g("commit", "-q", "-m", "ordinary"); assert.equal(r.revAt("HEAD"), 1); return locked; } test("F1: a plain `commit -e` whose guard ran before update-ref fails at its own HEAD update", async (t) => { await pausedCommit(t, []); }); test("F1: a `commit -e -- path` whose guard ran before update-ref fails at its own HEAD update", async (t) => { await pausedCommit(t, ["--", "src.txt"]); }); test("F1: step 8 with index.lock held exits 3, and ordinary commits stay refused until the printed command runs", (t) => { const r = ready(t); note(r); r.on("git", `if [ "$phase $sub" = "before ls-files" ] && once lock; then : > "$R/.git/index.lock"; fi`); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 3, res.err); assert.match(res.err, /holds \.git\/index\.lock/); assert.ok(res.err.includes(`run: ${FIX}`) || res.err.includes(`until this runs: ${FIX}`)); const c = r.head(); assert.equal(r.revAt(c), 1); r.off("git"); unlinkSync(join(r.gitDir, "index.lock")); stageFile(r, "src.txt"); const refused = sh("git", ["-C", r.root, "commit", "-q", "-m", "ordinary"], { env: r.env, allowFail: true }); assert.notEqual(refused.status, 0); assert.match(refused.stderr, new RegExp(GUARD)); assert.equal(r.head(), c); sh("sh", ["-c", FIX], { cwd: r.root, env: r.env }); r.g("commit", "-q", "-m", "ordinary"); assert.equal(r.revAt("HEAD"), 1); assert.equal(r.g("rev-parse", "HEAD^").trim(), c); }); test("F1: HEAD moving after commit-tree and before update-ref: refused, nothing published", (t) => { const r = ready(t); note(r); const h = r.head(); r.on("git", `if [ "$phase $sub" = "after commit-tree" ] && once move; then echo other > "$R/other.txt"; git -C "$R" add other.txt; git -C "$R" commit -q -m other fi`); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 1, res.err); assert.match(res.err, new RegExp(`refs/heads/refactor moved since ${h}; nothing published; start again`)); assert.equal(r.g("rev-parse", "HEAD^").trim(), h); assert.equal(r.revAt("HEAD"), 0); assert.equal(r.g("log", "-1", "--format=%s").trim(), "other"); }); test("F1: H is recorded before the canary, so HEAD moving during the canary makes update-ref fail", (t) => { const r = ready(t); note(r); const h = r.head(); r.on("git", `if [ "$phase $sub" = "before hook" ] && once move; then echo other > "$R/other.txt"; git -C "$R" add other.txt; git -C "$R" commit -q -m other fi`); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 1, res.err); assert.match(res.err, new RegExp(`moved since ${h}`)); assert.equal(r.g("log", "-1", "--format=%s").trim(), "other"); assert.equal(r.g("rev-parse", "HEAD^").trim(), h); assert.equal(r.revAt("HEAD"), 0); // Both guard checks ran in full (two canary runs each), so only update-ref caught the move. assert.equal(r.calls("git").filter((c) => c === "before hook").length, 4); }); test("F1: a shared-index change during the procedure is not committed", (t) => { const r = ready(t); note(r); r.on("git", `if [ "$phase $sub" = "before commit-tree" ]; then echo late > "$R/late.txt"; git -C "$R" add late.txt; fi`); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 0, res.err); assert.deepEqual(r.g("diff-tree", "-r", "--name-only", "HEAD^", "HEAD").trim().split("\n"), [QMD, QJSON]); assert.equal(r.g("diff", "--cached", "--name-only").trim(), "late.txt"); }); test("F1: a queue path staged after update-ref: step 8 stops and touches nothing", (t) => { const r = ready(t); note(r); r.on("git", `if [ "$phase $sub $status" = "after update-ref 0" ]; then git -C "$R" add docs/plans/queue.json; sha256sum "$R/.git/index" | cut -d' ' -f1 > "$CTL/index-sha" fi`); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 3, res.err); assert.match(res.err, /someone staged a queue path; the index was not touched/); assert.equal(sha256(readFileSync(join(r.gitDir, "index"))), r.ctlFile("index-sha")); assert.equal(r.revAt("HEAD"), 1); }); test("F1: a missing or a different hook refuses", (t) => { const r = ready(t); note(r); const h = r.head(); const bytes = readFileSync(r.hook); r.on("git", ""); unlinkSync(r.hook); assertUntouched(r, h, r.qc(["-m", "x"]), "missing"); assert.match(r.qc(["-m", "x"]).err, /queue guard is not installed/); writeFileSync(r.hook, `${bytes}\n# edited\n`, { mode: 0o755 }); const diff = r.qc(["-m", "x"]); assertUntouched(r, h, diff, "different"); assert.match(diff.err, /differs from scripts\/git-hooks\/pre-commit/); const inst = r.qc(["--install-hook", "--by", "sage"]); assert.equal(inst.code, 2); assert.match(inst.err, /a different pre-commit hook exists/); }); test("F1: same bytes without the exec bit, a symlinked hook, and core.hooksPath in the local or global scope each refuse before update-ref", (t) => { const r = ready(t); note(r); const h = r.head(); const bytes = readFileSync(r.hook); r.on("git", ""); chmodSync(r.hook, 0o644); let res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "no exec bit"); assert.match(res.err, /not executable/); chmodSync(r.hook, 0o755); const target = join(r.base, "hook-copy"); writeFileSync(target, bytes, { mode: 0o755 }); unlinkSync(r.hook); symlinkSync(target, r.hook); res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "symlink"); assert.match(res.err, /is a symlink/); unlinkSync(r.hook); writeFileSync(r.hook, bytes, { mode: 0o755 }); r.g("config", "core.hooksPath", ".githooks"); res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "local hooksPath"); assert.match(res.err, /core\.hooksPath is set \(local/); r.g("config", "--unset", "core.hooksPath"); r.g("config", "--global", "core.hooksPath", "/nonexistent-hooks"); res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "global hooksPath"); assert.match(res.err, /core\.hooksPath is set \(global/); r.g("config", "--global", "--unset", "core.hooksPath"); res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 0, res.err); }); test("F1: the canary refuses a hook that git would not run", (t) => { const r = ready(t); note(r); const h = r.head(); r.on("git", `if [ "$phase $sub" = "before hook" ] && once chmod; then chmod 0644 "$R/.git/hooks/pre-commit"; fi`); const res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "canary"); assert.match(res.err, /refused \(step1\): the canary's clean run failed/); }); test("F1: the guard deactivated after step 1 is refused at the step-7 recheck", (t) => { const r = ready(t); note(r); const h = r.head(); r.on("git", `if [ "$phase $sub" = "after commit-tree" ]; then chmod 0644 "$R/.git/hooks/pre-commit"; fi`); const res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "step 7"); assert.match(res.err, /refused \(step7\): \.git\/hooks\/pre-commit is not executable/); assert.ok(r.calls("git").includes("after commit-tree")); }); // --- bootstrap (F3) --- test("bootstrap: implementation-only HEAD, the guard, genesis, the --genesis commit, then an extending commit", (t) => { const r = ready(t, { bootstrap: true }); const impl = r.head(); assert.equal(sh("git", ["-C", r.root, "cat-file", "-e", `HEAD:${QJSON}`], { env: r.env, allowFail: true }).status, 128); assert.equal(readFileSync(r.hook, "utf8"), r.blob("HEAD", "scripts/git-hooks/pre-commit")); genesis(r); const g = r.qc(["--genesis", "-m", "queue genesis"]); assert.equal(g.code, 0, g.err); assert.match(g.err, /ok verify --snapshot rev 0: pair valid, view current, genesis alone/); assert.equal(r.g("rev-parse", "HEAD^").trim(), impl); assert.equal(r.revAt("HEAD"), 0); assert.equal(r.g("status", "--porcelain").trim(), ""); note(r); const c = r.qc(["-m", "queue rev 1"]); assert.equal(c.code, 0, c.err); assert.match(c.err, /extends the base/); assert.equal(r.revAt("HEAD"), 1); assert.equal(r.g("status", "--porcelain").trim(), ""); }); test("bootstrap: --genesis with a base present, no base without --genesis, an op before the first commit, a changed map, another branch", (t) => { const r = ready(t, { bootstrap: true }); let res = r.qc(["-m", "x"]); assert.equal(res.code, 2); assert.match(res.err, /HEAD has no docs\/plans\/queue\.json; the first queue commit needs --genesis/); genesis(r); res = r.qc(["-m", "x"]); assert.equal(res.code, 2); assert.match(res.err, /needs --genesis/); const op = cli(r, ["note", "6", "early", "--op", "note-early-1"], { by: "darkwing" }); assert.equal(op.code, 2); assert.match(op.err, /genesis not committed/); // The map changed in HEAD after genesis read it. const mapPath = join(r.root, "agents/sage/work/queue-migration-map.md"); const mapText = readFileSync(mapPath, "utf8"); writeFileSync(mapPath, `${mapText}\nEdited.\n`); r.g("add", "agents/sage/work/queue-migration-map.md"); r.g("commit", "-q", "-m", "map edit"); res = r.qc(["--genesis", "-m", "x"]); assert.equal(res.code, 2); assert.match(res.err, /genesis read map blob [0-9a-f]{40}, but HEAD's agents\/sage\/work\/queue-migration-map\.md is/); writeFileSync(mapPath, mapText); r.g("add", "agents/sage/work/queue-migration-map.md"); r.g("commit", "-q", "-m", "map restored"); r.g("checkout", "-q", "-b", "other"); res = r.qc(["--genesis", "-m", "x"]); assert.equal(res.code, 2); r.g("checkout", "-q", "refactor"); res = r.qc(["--genesis", "-m", "queue genesis"]); assert.equal(res.code, 0, res.err); res = r.qc(["--genesis", "-m", "x"]); assert.equal(res.code, 2); assert.match(res.err, /--genesis, but HEAD already has docs\/plans\/queue\.json/); }); test("bootstrap: the archived tests and validator run outside any repository", (t) => { const r = ready(t); note(r); r.on("node", `if [ "$phase" = before ] && { [ "$1" = --test ] || [ "$3" = --snapshot ]; }; then { echo "$1|$(pwd -P)|\${GIT_CEILING_DIRECTORIES:-}|$(git rev-parse --show-toplevel >/dev/null 2>&1; echo $?)"; } >> "$CTL/node-where" fi`); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 0, res.err); const lines = r.ctlFile("node-where").split("\n"); assert.equal(lines.length, 2); for (const line of lines) { const [first, cwd, ceiling, rc] = line.split("|"); assert.ok(first === "--test" || first === "packages/queue/src/cli.mjs", first); assert.ok(!cwd.startsWith(`${r.root}/`) && cwd !== r.root, cwd); assert.ok(cwd.startsWith(`${ceiling}/`), `${cwd} under ${ceiling}`); assert.notEqual(rc, "0", "a repository was found around the archive"); } }); // --- general --- test("general: an unrelated staged file stays staged, and the committed blobs are the snapshot bytes", (t) => { const r = ready(t); note(r); stageFile(r, "src.txt"); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 0, res.err); const m = /snapshot rev 1: queue\.json ([0-9a-f]{64}), QUEUE\.md ([0-9a-f]{64})/.exec(res.out); assert.ok(m, res.out); assert.equal(sha256(r.blob("HEAD", QJSON)), m[1]); assert.equal(sha256(r.blob("HEAD", QMD)), m[2]); assert.equal(r.blob("HEAD", QJSON), readFileSync(join(r.root, QJSON), "utf8")); assert.equal(r.g("diff", "--cached", "--name-only").trim(), "src.txt"); assert.equal(sh("git", ["-C", r.root, "cat-file", "-e", "HEAD:src.txt"], { env: r.env, allowFail: true }).status, 128); }); test("general: a queue write after the snapshot is not committed", (t) => { const r = ready(t); note(r); const cliPath = join(r.root, "packages/queue/src/cli.mjs"); r.on("node", `if [ "$phase $status $2" = "after 0 snapshot" ] && once write; then MOSAIC_AGENT_NAME=darkwing node ${q(cliPath)} note 6 late --op note-late-1 > "$CTL/late-out" 2>&1 fi`); const res = r.qc(["-m", "queue rev 1"]); assert.equal(res.code, 0, res.err); assert.match(r.ctlFile("late-out"), /ok note-late-1 rev 2/); assert.equal(r.revAt("HEAD"), 1); assert.equal(JSON.parse(readFileSync(join(r.root, QJSON), "utf8")).revision, 2); r.off("node"); const again = r.qc(["-m", "queue rev 2"]); assert.equal(again.code, 0, again.err); assert.equal(r.revAt("HEAD"), 2); }); test("general: a snapshot whose log does not extend the base refuses", (t) => { const r = ready(t); note(r); // A bypass commit of rev 1, then the working files rolled back to rev 0 // and the loss accepted: the working log forks from HEAD's. r.g("add", QJSON, QMD); r.g("commit", "-q", "--no-verify", "-m", "bypass"); writeFileSync(join(r.root, QJSON), r.blob("HEAD^", QJSON)); writeFileSync(join(r.root, QMD), r.blob("HEAD^", QMD)); const acc = cli(r, ["accept-history", "--op", "accept-1", "--reason", "test rollback", "--yes"], { by: "sage" }); assert.equal(acc.code, 0, acc.err); const h = r.head(); r.on("git", ""); const res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "fork"); assert.match(res.err, /the snapshot's log does not extend the base's \(base rev 1, snapshot rev 1\)/); }); test("general: install-hook privilege, repair of a same-bytes hook, and its refusals", (t) => { const r = ready(t, { bootstrap: true }); let res = r.qc(["--install-hook"]); assert.equal(res.code, 2); assert.match(res.err, /no actor/); res = r.qc(["--install-hook"], { MOSAIC_AGENT_NAME: "darkwing" }); assert.equal(res.code, 2); assert.match(res.err, /privileged \(jason or sage\), not darkwing/); chmodSync(r.hook, 0o644); res = r.qc(["--install-hook"], { MOSAIC_AGENT_NAME: "jason" }); assert.equal(res.code, 0, res.err); assert.match(res.out, /the same bytes were already there/); assert.equal(sh("stat", ["-c", "%a", r.hook]).stdout.trim(), "755"); const bytes = readFileSync(r.hook); unlinkSync(r.hook); const target = join(r.base, "hook-copy"); writeFileSync(target, bytes, { mode: 0o755 }); symlinkSync(target, r.hook); res = r.qc(["--install-hook", "--by", "sage"]); assert.equal(res.code, 2); assert.match(res.err, /is a symlink/); unlinkSync(r.hook); r.g("config", "core.hooksPath", ".githooks"); res = r.qc(["--install-hook", "--by", "sage"]); assert.equal(res.code, 2); assert.match(res.err, /core\.hooksPath is set/); assert.ok(!existsSync(r.hook)); }); test("general: environment overrides, a linked worktree and usage", (t) => { const r = ready(t); note(r); const h = r.head(); for (const k of ["GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR"]) { const res = r.qc(["-m", "x"], { [k]: join(r.root, ".git") }); assert.equal(res.code, 2, k); assert.match(res.err, new RegExp(`${k} is set`)); } const wt = join(r.base, "wt"); r.g("worktree", "add", "-q", "-b", "wt", wt); const w = sh("bash", [join(wt, "scripts/queue-commit.sh"), "-m", "x"], { cwd: wt, env: r.env, allowFail: true }); assert.equal(w.status, 2); assert.match(w.stderr, /linked worktree/); for (const args of [[], ["-m", ""], ["--by", "sage", "-m", "x"], ["--install-hook", "-m", "x"], ["--bogus"], ["-m"]]) { assert.equal(r.qc(args).code, 4, JSON.stringify(args)); } assert.equal(r.head(), h); }); test("general: a queue path staged before the run refuses at step 1", (t) => { const r = ready(t); note(r); const h = r.head(); r.g("add", QMD); r.on("git", ""); const res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "staged"); assert.match(res.err, /the shared index has staged changes to docs\/plans\/queue\.json or docs\/plans\/QUEUE\.md/); assert.ok(res.err.includes(FIX)); assert.ok(!r.calls("git").includes("before commit-tree")); }); test("general: HEAD's queue tests failing in the archive refuse", (t) => { const r = ready(t); writeFileSync(join(r.root, "packages/queue/tests/fail.test.mjs"), 'import { test } from "node:test";\ntest("fails", () => { throw new Error("archived failure"); });\n'); r.g("add", "packages/queue/tests/fail.test.mjs"); r.g("commit", "-q", "-m", "failing test"); note(r); const h = r.head(); r.on("git", ""); const res = r.qc(["-m", "x"]); assertUntouched(r, h, res, "archive tests"); assert.match(res.err, /archived failure/); assert.match(res.err, /refused: HEAD's queue tests failed in the archive/); });