From ff54f3c9555cdffaffee336f12f64c122177aca4 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 01:02:23 +0000 Subject: [PATCH] test(W7h): drop issue-number pins in land-and-deploy-postfail, match guards case-insensitively W7h (t09 F12, F13). One test file. Removed assertion groups: - `cli/cli#3442` / `cli/cli#13380` pins (t09 F12). Invariant: none of its own (upstream archaeology; the IDs stay in the template, only the pin goes). The behavior they decorated, "after any non-zero `gh pr merge` exit, query authoritative state before retrying", is now a kept free meaning check. - `Universal invariant` label pin. Invariant: query-before-retry. Remaining protection: the new case-insensitive check `/non-zero exit from `gh pr merge`, query authoritative PR state before retrying/i` (stronger: the mutation that inverts the rule now goes red; the old test stayed green). Loosened to case-insensitive meaning checks (kept, W7 keep list, data-loss and destructive-op guards): STOP worktree cleanup without removing, no `--force`, primary working tree never removed, CLOSED -> stop, never replay a merge after MERGED, one direct fallback, no fallback from a direct attempt, the OPEN/no-auto/no-queue fallback precondition, branch-absent vs check-failed messages. Gate-tier E2E also covering the flow: land-and-deploy-workflow (gate), judge `land-and-deploy/SKILL.md workflow` (gate lane). Cosmetic pins dropped (no control needed): capitals on STOP / Do NOT. Mutation log: .context/mutation-land-and-deploy-postfail.md (12 mutations, 0 unexpected: reorder, field delete and 7 safety deletes red; 3 rewordings green). --- test/land-and-deploy-postfail.test.ts | 38 ++++++++++++--------------- 1 file changed, 17 insertions(+), 21 deletions(-) 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)", () => {