From f50119e4f3ec6f926cff09de1d4727ed243b9c23 Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Tue, 14 Jul 2026 13:15:19 -0500 Subject: [PATCH 1/4] chore(workflow): harden deck-contribute verify + commit hygiene MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Gate A (check-parser-combinators.sh) now takes the explicit upstream/main merge-base; the script's default base is the stale fork origin/main, which false-flags pre-existing nom-combinator debt in untouched files. - Enum-variant note: keep clippy workspace-wide (never -p engine) and also test -p phase-ai, since phase-ai/engine-wasm match engine enums exhaustively and a -p engine check misses non-exhaustive-match breaks that fail CI. - Discard build-regenerated data artifacts (known-tokens.toml, engine-inventory.json, oracle-subtypes.json) before 'git add -A' — a local mtgjson env regenerates them destructively, producing large drift diffs that conflict with main and are not CI-checked. Set-agnostic workflow hardening surfaced while running the pipeline at volume. --- .claude/workflows/deck-contribute.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.claude/workflows/deck-contribute.js b/.claude/workflows/deck-contribute.js index 74adb0a237..aa4a0cbcaf 100644 --- a/.claude/workflows/deck-contribute.js +++ b/.claude/workflows/deck-contribute.js @@ -435,10 +435,19 @@ function clusterVerifyPrompt(mechanic, cards) { `order, fixing in-loop on failure (max ${MAX_VERIFY_RETRIES} retries per ` + `command):\n` + `1. cargo fmt --all\n` + - `2. ./scripts/check-parser-combinators.sh (Gate A)\n` + + `2. ./scripts/check-parser-combinators.sh "$(git merge-base upstream/main HEAD)" (Gate A) — ` + + `pass the upstream/main merge-base explicitly. The script's DEFAULT base is the stale fork ` + + `origin/main, which diffs the whole tree and false-flags pre-existing nom-combinator debt in ` + + `files this change never touched. Scoped to the correct base it only checks THIS change's lines; ` + + `treat a non-zero exit as a failure ONLY if a flagged line is in a file this change modified.\n` + `3. If \`tilt get uiresource clippy >/dev/null 2>&1\` succeeds: ` + `./scripts/tilt-wait.sh --timeout 240 clippy test-engine card-data ; else ` + `cargo clippy-strict && cargo test -p engine && ./scripts/gen-card-data.sh\n` + + ` (If this change adds or removes a variant on an engine enum — Effect, TriggerMode, ` + + `StaticCondition, GameEvent, EffectKind — keep clippy WORKSPACE-wide, never narrowed to ` + + `\`-p engine\`, and also run \`cargo test -p phase-ai\`: phase-ai and engine-wasm match these ` + + `enums exhaustively, so a \`-p engine\`-only check cannot observe a non-exhaustive-match break ` + + `in those crates that fails CI's Rust-lint / WASM-compile jobs.)\n` + `4. cargo coverage — confirm EACH of these cards is now supported:true gap:0; ` + `list the ones that are in cardsSupported:\n${cards.map((c) => `- ${c}`).join('\n')}\n` + `5. cargo semantic-audit — confirm none of these cards has findings -> ` + @@ -468,6 +477,11 @@ function clusterPrPrompt(mechanic, cards, { impl, verify, partial }) { return ( `Commit the working-tree change for the "${mechanic}" mechanic, push the ` + `branch to your fork, and open a PR to phase-rs/phase with base main.\nRun:\n` + + `FIRST discard build-regenerated data artifacts — they are NOT part of any card fix, a ` + + `partial/local mtgjson env regenerates them DESTRUCTIVELY, and they produce large drift diffs ` + + `that conflict with main and are not CI-checked: ` + + `git checkout -- crates/engine/data/known-tokens.toml data/engine-inventory.json crates/engine/data/oracle-subtypes.json 2>/dev/null . ` + + `Confirm none are staged (\`git diff --cached --name-only | grep -cE 'known-tokens|engine-inventory|oracle-subtypes'\` must print 0) before committing. Then:\n` + `git add -A && git commit -m ${JSON.stringify(title)} && git push -u origin HEAD\n` + `Then: gh pr create --base main --title ${JSON.stringify(title)} --body ` + `(do NOT pass --label; the upstream auto-labeler handles it).\n\n` + From 5bb085bce34f29d99f09f12b203c132789c6b200 Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Tue, 14 Jul 2026 14:44:44 -0500 Subject: [PATCH 2/4] fix(workflow): drop trailing '.' pathspec from the discard command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The discard step read 'git checkout -- 2>/dev/null .' — the trailing dot (intended as sentence punctuation) is a pathspec argument that would discard the ENTIRE working tree, including the card implementation. Terminate the command at 2>/dev/null and add an explicit warning never to append a bare '.'. Caught by Gemini review. --- .claude/workflows/deck-contribute.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.claude/workflows/deck-contribute.js b/.claude/workflows/deck-contribute.js index aa4a0cbcaf..5a9af2f8d6 100644 --- a/.claude/workflows/deck-contribute.js +++ b/.claude/workflows/deck-contribute.js @@ -480,7 +480,8 @@ function clusterPrPrompt(mechanic, cards, { impl, verify, partial }) { `FIRST discard build-regenerated data artifacts — they are NOT part of any card fix, a ` + `partial/local mtgjson env regenerates them DESTRUCTIVELY, and they produce large drift diffs ` + `that conflict with main and are not CI-checked: ` + - `git checkout -- crates/engine/data/known-tokens.toml data/engine-inventory.json crates/engine/data/oracle-subtypes.json 2>/dev/null . ` + + `git checkout -- crates/engine/data/known-tokens.toml data/engine-inventory.json crates/engine/data/oracle-subtypes.json 2>/dev/null\n` + + `(pass ONLY those three explicit paths — NEVER append a bare '.' pathspec, which would discard the ENTIRE working tree including the card fix; the trailing 2>/dev/null only suppresses git's "did not match" noise).\n` + `Confirm none are staged (\`git diff --cached --name-only | grep -cE 'known-tokens|engine-inventory|oracle-subtypes'\` must print 0) before committing. Then:\n` + `git add -A && git commit -m ${JSON.stringify(title)} && git push -u origin HEAD\n` + `Then: gh pr create --base main --title ${JSON.stringify(title)} --body ` + From e3192479a6ae6322d8672102670b4d5997745a29 Mon Sep 17 00:00:00 2001 From: matthewevans Date: Thu, 16 Jul 2026 21:07:28 -0700 Subject: [PATCH 3/4] fix(PR-5829): harden deck contribution verification --- .claude/workflows/deck-contribute.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.claude/workflows/deck-contribute.js b/.claude/workflows/deck-contribute.js index 5a9af2f8d6..74a70d8a65 100644 --- a/.claude/workflows/deck-contribute.js +++ b/.claude/workflows/deck-contribute.js @@ -439,15 +439,15 @@ function clusterVerifyPrompt(mechanic, cards) { `pass the upstream/main merge-base explicitly. The script's DEFAULT base is the stale fork ` + `origin/main, which diffs the whole tree and false-flags pre-existing nom-combinator debt in ` + `files this change never touched. Scoped to the correct base it only checks THIS change's lines; ` + - `treat a non-zero exit as a failure ONLY if a flagged line is in a file this change modified.\n` + + `treat any non-zero exit as a verification failure.\n` + `3. If \`tilt get uiresource clippy >/dev/null 2>&1\` succeeds: ` + - `./scripts/tilt-wait.sh --timeout 240 clippy test-engine card-data ; else ` + - `cargo clippy-strict && cargo test -p engine && ./scripts/gen-card-data.sh\n` + + `./scripts/tilt-wait.sh --timeout 240 clippy test-engine test-ai wasm card-data ; else ` + + `cargo clippy-strict && cargo test -p engine && cargo test -p phase-ai && cargo wasm && ./scripts/gen-card-data.sh\n` + ` (If this change adds or removes a variant on an engine enum — Effect, TriggerMode, ` + `StaticCondition, GameEvent, EffectKind — keep clippy WORKSPACE-wide, never narrowed to ` + - `\`-p engine\`, and also run \`cargo test -p phase-ai\`: phase-ai and engine-wasm match these ` + - `enums exhaustively, so a \`-p engine\`-only check cannot observe a non-exhaustive-match break ` + - `in those crates that fails CI's Rust-lint / WASM-compile jobs.)\n` + + `\`-p engine\`; in the Tilt branch, wait for \`test-ai\` and \`wasm\`, and in the no-Tilt fallback ` + + `run \`cargo test -p phase-ai\` and \`cargo wasm\`: phase-ai and engine-wasm match these enums ` + + `exhaustively, so an engine-only check cannot observe a non-exhaustive-match break in those crates.)\n` + `4. cargo coverage — confirm EACH of these cards is now supported:true gap:0; ` + `list the ones that are in cardsSupported:\n${cards.map((c) => `- ${c}`).join('\n')}\n` + `5. cargo semantic-audit — confirm none of these cards has findings -> ` + From beeb0203cb5cf2d8dee3ce52ad19faf788c1f046 Mon Sep 17 00:00:00 2001 From: matthewevans Date: Sat, 18 Jul 2026 19:22:17 -0700 Subject: [PATCH 4/4] ci: give Rust lint cold-cache headroom --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 170b49d1c6..6eeb6d5534 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,9 @@ jobs: rust-lint: name: Rust lint (fmt, clippy, parser gate) runs-on: ubuntu-latest - timeout-minutes: 15 + # Clippy can consume the former 15-minute ceiling on a cold hosted cache; + # retain a bounded job while leaving room for the remaining lint gates. + timeout-minutes: 20 steps: - uses: actions/checkout@v4 with: