diff --git a/test/land-and-deploy-postfail.test.ts b/test/land-and-deploy-postfail.test.ts index 840c303e4..8446921b2 100644 --- a/test/land-and-deploy-postfail.test.ts +++ b/test/land-and-deploy-postfail.test.ts @@ -8,12 +8,11 @@ * only the STOP-Read pointer). After ANY non-zero `gh pr merge`, the skill * must query authoritative PR state via * GraphQL (including queue membership) and - * branch on the result instead of blindly retrying `gh pr merge` (cli/cli#3442, - * cli/cli#13380). + * branch on the result instead of blindly retrying `gh pr merge`. * * Static invariants pin: * - §4a-postfail header present - * - Universal invariant text + reference to upstream gh bugs + * - Query-before-retry invariant after any non-zero merge exit * - All three state branches (MERGED, OPEN, CLOSED) named explicitly * - MERGED branch: capture merge SHA via mergeCommit.oid * - MERGED branch: non-destructive worktree cleanup with uncommitted-work guard @@ -52,12 +51,9 @@ describe("PR #1620 §4a-postfail in land-and-deploy template", () => { expect(postfail).toBeLessThan(queue); }); - test("Universal invariant + upstream gh bug references", () => { - const body = readTmpl(); - expect(body).toMatch(/Universal invariant/); - expect(body).toMatch(/non-zero exit from `gh pr merge`/); - expect(body).toMatch(/cli\/cli#3442/); - expect(body).toMatch(/cli\/cli#13380/); + test("any non-zero merge exit queries authoritative state before retrying", () => { + const body = readTmpl().replace(/\s+/g, " "); + expect(body).toMatch(/non-zero exit from `gh pr merge`, query authoritative PR state before retrying/i); }); test("Authoritative state query includes auto request and queue membership", () => { @@ -82,9 +78,9 @@ describe("PR #1620 §4a-postfail in land-and-deploy template", () => { test("MERGED worktree cleanup is non-destructive (uncommitted-work guard)", () => { const body = readTmpl(); expect(body).toMatch(/uncommitted work/); - expect(body).toMatch(/STOP worktree cleanup without removing/); - expect(body).toMatch(/Do NOT use `--force`/); - expect(body).toMatch(/Do NOT remove the user's primary working tree/); + expect(body).toMatch(/stop worktree cleanup without removing/i); + expect(body).toMatch(/do not use `--force`/i); + expect(body).toMatch(/do not remove the user's primary working tree/i); }); test("MERGED branch continues to §4b CI auto-deploy detection", () => { @@ -114,10 +110,10 @@ describe("PR #1620 §4a-postfail in land-and-deploy template", () => { test("MERGED branch reconciliation distinguishes branch-absent from check-failed", () => { const body = readTmpl(); // exit 0 + empty output = already clean (idempotent re-runs)... - expect(body).toMatch(/already been cleaned up/); + expect(body).toMatch(/already been cleaned up/i); // ...non-zero exit = unknown state, never read as a clean branch. - expect(body).toMatch(/Couldn't verify remote branch state/); - expect(body).toMatch(/never read a failed check as a clean branch/); + expect(body).toMatch(/couldn't verify remote branch state/i); + expect(body).toMatch(/never read a failed check as a clean branch/i); }); test("OPEN branch checks autoMergeRequest before treating as failure", () => { @@ -128,15 +124,15 @@ describe("PR #1620 §4a-postfail in land-and-deploy template", () => { test("CLOSED branch STOPs", () => { const body = readTmpl(); - expect(body).toMatch(/state == "CLOSED".*[\s\S]{0,200}STOP/); + expect(body).toMatch(/state == "CLOSED"[\s\S]{0,200}\bstop\b/i); }); test("Hard rule: no replay after MERGED and only one guarded direct fallback", () => { - const body = readTmpl(); - expect(body).toMatch(/never\s+replay a merge after MERGED/); - expect(body).toContain('one direct fallback'); - expect(body).toContain('There is no fallback from a direct attempt'); - expect(body).toContain('readback has confirmed OPEN, no auto request and no queue entry'); + const body = readTmpl().replace(/\s+/g, " "); + expect(body).toMatch(/never replay a merge after MERGED/i); + expect(body).toMatch(/one direct fallback/i); + expect(body).toMatch(/no fallback from a direct attempt/i); + expect(body).toMatch(/confirmed OPEN, no auto request and no queue entry/i); }); test("Generated merge-and-deploy.md carries the §4a-postfail section (atomic regen per T-Codex-3)", () => {