validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true)\nPY_FILES=$(echo \"$CHANGED\" | rg '\\.py$|pyproject\\.toml$|requirements.*\\.txt

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true)\nSH_FILES=$(echo \"$CHANGED\" | rg '\\.sh$|\\.githooks' || true)\nGRAMMAR_FILES=$(echo \"$CHANGED\" | rg '\\.(lark|peg|g4)

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true)\n```\n\nArea routing table:\n\n| Area | File patterns | Verification type |\n|------|---------------|-------------------|\n| Rust | `*.rs`, `Cargo.toml`, `Cargo.lock` | cargo build + per-crate test |\n| Python | `*.py`, `pyproject.toml` | pytest per changed module |\n| Shell | `*.sh`, `.githooks/*` | shellcheck |\n| Grammar | `*.lark`, `*.peg`, `*.g4` | language-specific lint |\n| Build/config | `*.yaml`, `*.json`, `*.toml` | parse check |\n\n## Step 2: Generate and Execute Steps per Area\n\nFor each non-empty area, generate and run at least one verification step.\nAssign `[E1]`, `[E2]`, ... labels to each captured output.\n\n### Rust\n\n```bash\n# Build with default features\ncargo build --workspace 2>&1\n# Evidence: [En] → \"0 errors, 0 warnings\"\n\n# Build with --all-features\ncargo build --workspace --all-features 2>&1\n# Evidence: [En+1]\n\n# Per-crate test for each changed crate\n# Extract crate directory from changed path, e.g. crates/token-types/src/lib.rs\nCHANGED_CRATES=$(echo \"$RUST_FILES\" \\\n | rg -o '(?:crates|src)/[^/]+' \\\n | sort -u \\\n | xargs -I{} basename {})\nfor CRATE in $CHANGED_CRATES; do\n cargo test -p \"$CRATE\" 2>&1\ndone\n```\n\n### Python\n\n```bash\n# Targeted test per changed module\nfor PY_FILE in $PY_FILES; do\n MODULE=$(basename \"${PY_FILE%.py}\")\n TEST_FILE=\"tests/test_${MODULE}.py\"\n if [[ -f \"$TEST_FILE\" ]]; then\n uv run pytest \"$TEST_FILE\" -v 2>&1\n fi\ndone\n\n# Or project-specific runner if Makefile target exists\nmake test 2>&1 || uv run pytest tests/ -v 2>&1\n```\n\n### Shell\n\n```bash\nfor SH_FILE in $SH_FILES; do\n [[ -f \"$SH_FILE\" ]] && shellcheck \"$SH_FILE\" 2>&1\ndone\n```\n\n### Build/config parse check\n\n```bash\n# YAML files\nfor YML in $(echo \"$CHANGED\" | rg '\\.ya?ml

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true); do\n [[ -f \"$YML\" ]] && python3 -c \"import yaml; yaml.safe_load(open('$YML'))\" \\\n && echo \"PASS: $YML\" || echo \"FAIL: $YML\"\ndone\n\n# JSON files\nfor JSON_F in $(echo \"$CHANGED\" | rg '\\.json

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true); do\n [[ -f \"$JSON_F\" ]] && python3 -m json.tool \"$JSON_F\" > /dev/null \\\n && echo \"PASS: $JSON_F\" || echo \"FAIL: $JSON_F\"\ndone\n```\n\n## Step 3: Revert-Test Quality Check\n\nProve at least one test is a genuine guard, not a dead assertion.\n\n**Safety: abort if the working tree has uncommitted changes.**\n\n```bash\nif ! git diff --exit-code > /dev/null 2>&1; then\n echo \"[RT] SKIP: working tree dirty — revert-test unsafe\"\n # Mark INCONCLUSIVE and continue\nfi\n```\n\n**Algorithm (one representative fix):**\n\n1. From the changed source files, find one that has a corresponding test.\n - Rust: a `#[test]` in the same crate that exercises a changed function.\n - Python: `tests/test_\u003cmodule>.py` for a changed `\u003cmodule>.py`.\n - Shell: a test harness that invokes the changed script.\n2. Identify the specific changed line or block from the diff.\n3. Edit that line to revert the fix to its broken state.\n4. Run the targeted test: confirm it **FAILS** (expected).\n5. Restore: `git checkout — \u003cfile>` (git-based restore, safe on interrupt).\n6. Run the targeted test again: confirm it **PASSES**.\n7. If any step cannot complete, mark INCONCLUSIVE with the reason.\n\n**Revert-test output format:**\n\n```\n[RT-1] Target: \u003cfile>:\u003cline> — \u003cdescription of fix>\n[RT-2] Broke fix: \u003cedit description>\n[RT-3] Ran: \u003ctest command> → \u003ctest name> FAILED (expected)\n[RT-4] Restored: git checkout -- \u003cfile>\n[RT-5] Ran: \u003ctest command> → \u003ctest name> PASSED\nResult: PASS — test is a genuine guard\n```\n\n**When no covering test exists:**\n\n```\nRevert-test: INCONCLUSIVE — no covering test for \u003cchanged area>\nRecommendation: add a test for \u003cchanged function or behaviour>\n```\n\n## Step 4: Final Full-Suite Run\n\nAfter all area checks and the revert-test:\n\n```bash\n# Rust workspace\ncargo test --workspace 2>&1\n\n# Python project\nuv run pytest tests/ -v 2>&1\n\n# Mixed project: run both\ncargo test --workspace 2>&1 && uv run pytest tests/ -v 2>&1\n```\n\nCapture full output as final evidence `[En]`.\n\n## Step 5: Produce Summary Table\n\n```markdown\n### validate-mr: \u003cMR title or number>\n\n| Area | Step | Evidence | Result |\n|------|------|----------|--------|\n| Rust: token-types | cargo build --workspace | [E1] 0 errors | PASS |\n| Rust: token-types | cargo test -p token-types | [E2] 12 passed | PASS |\n| Rust: token-types | cargo build --all-features | [E3] 0 errors | PASS |\n| Shell: hooks/pre-commit | shellcheck | [E4] 0 issues | PASS |\n| Revert-test: lib.rs:45 | break/fail/restore | [RT-1..5] genuine guard | PASS |\n| Final: cargo test --workspace | full suite | [E5] 694 passed, 0 failed | PASS |\n\n**Totals**: 6 steps — 6 PASS, 0 FAIL, 0 INCONCLUSIVE\n```\n\n## Step 6: Posting (--post flag only)\n\nWhen `--post` is given, post the summary table as a PR comment:\n\n```bash\ngh pr comment \"$MR_NUMBER\" --body \"$(cat /tmp/validate-mr-summary.md)\"\n```\n\nSkip posting when invoked from `/fix-pr` — results feed into the Gate 3\nsummary comment instead.\n\n## Failure Behaviour\n\nWhen any step produces **FAIL**:\n\n- Surface the failures in the summary table with the evidence reference.\n- When called from `/fix-pr`: halt before Step 6 (Complete). The user must\n fix the failures or pass `--skip-validate` to `/fix-pr` to bypass.\n- When called standalone: report failures and exit with non-zero status.\n\nINCONCLUSIVE results are reported but do not halt the workflow.\n\n## Exit Criteria\n\n- [ ] `gh pr diff --name-only` returned a non-empty file list (diff fetched)\n- [ ] Every detected area has at least one row in the summary table\n- [ ] Every row shows an Evidence reference (`[E1]`, `[E2]`, etc.) with the\n actual command output, not fabricated\n- [ ] Revert-test attempted for at least one area with a covering test, or\n documented as INCONCLUSIVE with reason\n- [ ] Final full-suite run appears in the summary table\n- [ ] Summary table is present with columns: Area, Step, Evidence, Result\n- [ ] Any FAIL result halts `/fix-pr` before Step 6 when called from fix-pr\n- [ ] Working tree is clean after skill completes (git checkout restore\n confirmed successful for any revert-test mutation)\n---","attachment_filenames":[],"attachments":[],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"validate-mr: Diff-Derived Test Plan","type":"text"}]},{"type":"paragraph","content":[{"text":"Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic \"tests pass\" with area-targeted evidence and revert-test quality checks that prove tests catch regressions.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When To Use","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"End of ","type":"text"},{"text":"/fix-pr","type":"text","marks":[{"type":"code_inline"}]},{"text":" Step 5 (Validate), before Step 6 (Complete)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Standalone after any MR fix, to generate targeted validation evidence","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When you need proof that revert-tests are genuine guards","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When NOT To Use","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"--scope minor","type":"text","marks":[{"type":"code_inline"}]},{"text":" with only formatting or doc changes (no logic changed)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No diff available (clean branch, nothing changed)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"--skip-validate","type":"text","marks":[{"type":"code_inline"}]},{"text":" passed to ","type":"text"},{"text":"/fix-pr","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Algorithm","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"fetch diff -> group by area -> generate steps -> execute -> revert-test -> table","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Step 1: Fetch Diff and Detect Areas","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Get changed file list from the MR\nMR_NUMBER=\u003cnumber from invocation or current branch>\nCHANGED=$(gh pr diff \"$MR_NUMBER\" --name-only)\n# Fallback when no MR number:\n# CHANGED=$(git diff \"origin/$(git rev-parse --abbrev-ref HEAD@{upstream})...HEAD\" \\\n# --name-only 2>/dev/null)","type":"text"}]},{"type":"paragraph","content":[{"text":"Group changed files into areas using ripgrep (grep if rg unavailable):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"RUST_FILES=$(echo \"$CHANGED\" | rg '\\.rs$|Cargo\\.(toml|lock)

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true)\nPY_FILES=$(echo \"$CHANGED\" | rg '\\.py$|pyproject\\.toml$|requirements.*\\.txt

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true)\nSH_FILES=$(echo \"$CHANGED\" | rg '\\.sh$|\\.githooks' || true)\nGRAMMAR_FILES=$(echo \"$CHANGED\" | rg '\\.(lark|peg|g4)

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true)","type":"text"}]},{"type":"paragraph","content":[{"text":"Area routing table:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Area","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"File patterns","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Verification type","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Rust","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"*.rs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"Cargo.toml","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"Cargo.lock","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cargo build + per-crate test","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Python","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"*.py","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"pyproject.toml","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pytest per changed module","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Shell","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"*.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".githooks/*","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"shellcheck","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Grammar","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"*.lark","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"*.peg","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"*.g4","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"language-specific lint","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build/config","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"*.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"*.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"*.toml","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"parse check","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Step 2: Generate and Execute Steps per Area","type":"text"}]},{"type":"paragraph","content":[{"text":"For each non-empty area, generate and run at least one verification step. Assign ","type":"text"},{"text":"[E1]","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"[E2]","type":"text","marks":[{"type":"code_inline"}]},{"text":", ... labels to each captured output.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Rust","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Build with default features\ncargo build --workspace 2>&1\n# Evidence: [En] → \"0 errors, 0 warnings\"\n\n# Build with --all-features\ncargo build --workspace --all-features 2>&1\n# Evidence: [En+1]\n\n# Per-crate test for each changed crate\n# Extract crate directory from changed path, e.g. crates/token-types/src/lib.rs\nCHANGED_CRATES=$(echo \"$RUST_FILES\" \\\n | rg -o '(?:crates|src)/[^/]+' \\\n | sort -u \\\n | xargs -I{} basename {})\nfor CRATE in $CHANGED_CRATES; do\n cargo test -p \"$CRATE\" 2>&1\ndone","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Python","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Targeted test per changed module\nfor PY_FILE in $PY_FILES; do\n MODULE=$(basename \"${PY_FILE%.py}\")\n TEST_FILE=\"tests/test_${MODULE}.py\"\n if [[ -f \"$TEST_FILE\" ]]; then\n uv run pytest \"$TEST_FILE\" -v 2>&1\n fi\ndone\n\n# Or project-specific runner if Makefile target exists\nmake test 2>&1 || uv run pytest tests/ -v 2>&1","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Shell","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"for SH_FILE in $SH_FILES; do\n [[ -f \"$SH_FILE\" ]] && shellcheck \"$SH_FILE\" 2>&1\ndone","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Build/config parse check","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# YAML files\nfor YML in $(echo \"$CHANGED\" | rg '\\.ya?ml

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true); do\n [[ -f \"$YML\" ]] && python3 -c \"import yaml; yaml.safe_load(open('$YML'))\" \\\n && echo \"PASS: $YML\" || echo \"FAIL: $YML\"\ndone\n\n# JSON files\nfor JSON_F in $(echo \"$CHANGED\" | rg '\\.json

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…

|| true); do\n [[ -f \"$JSON_F\" ]] && python3 -m json.tool \"$JSON_F\" > /dev/null \\\n && echo \"PASS: $JSON_F\" || echo \"FAIL: $JSON_F\"\ndone","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Step 3: Revert-Test Quality Check","type":"text"}]},{"type":"paragraph","content":[{"text":"Prove at least one test is a genuine guard, not a dead assertion.","type":"text"}]},{"type":"paragraph","content":[{"text":"Safety: abort if the working tree has uncommitted changes.","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"if ! git diff --exit-code > /dev/null 2>&1; then\n echo \"[RT] SKIP: working tree dirty — revert-test unsafe\"\n # Mark INCONCLUSIVE and continue\nfi","type":"text"}]},{"type":"paragraph","content":[{"text":"Algorithm (one representative fix):","type":"text","marks":[{"type":"strong"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"From the changed source files, find one that has a corresponding test.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rust: a ","type":"text"},{"text":"#[test]","type":"text","marks":[{"type":"code_inline"}]},{"text":" in the same crate that exercises a changed function.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Python: ","type":"text"},{"text":"tests/test_\u003cmodule>.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" for a changed ","type":"text"},{"text":"\u003cmodule>.py","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Shell: a test harness that invokes the changed script.","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Identify the specific changed line or block from the diff.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Edit that line to revert the fix to its broken state.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run the targeted test: confirm it ","type":"text"},{"text":"FAILS","type":"text","marks":[{"type":"strong"}]},{"text":" (expected).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Restore: ","type":"text"},{"text":"git checkout — \u003cfile>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (git-based restore, safe on interrupt).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run the targeted test again: confirm it ","type":"text"},{"text":"PASSES","type":"text","marks":[{"type":"strong"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If any step cannot complete, mark INCONCLUSIVE with the reason.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Revert-test output format:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"[RT-1] Target: \u003cfile>:\u003cline> — \u003cdescription of fix>\n[RT-2] Broke fix: \u003cedit description>\n[RT-3] Ran: \u003ctest command> → \u003ctest name> FAILED (expected)\n[RT-4] Restored: git checkout -- \u003cfile>\n[RT-5] Ran: \u003ctest command> → \u003ctest name> PASSED\nResult: PASS — test is a genuine guard","type":"text"}]},{"type":"paragraph","content":[{"text":"When no covering test exists:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Revert-test: INCONCLUSIVE — no covering test for \u003cchanged area>\nRecommendation: add a test for \u003cchanged function or behaviour>","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Step 4: Final Full-Suite Run","type":"text"}]},{"type":"paragraph","content":[{"text":"After all area checks and the revert-test:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Rust workspace\ncargo test --workspace 2>&1\n\n# Python project\nuv run pytest tests/ -v 2>&1\n\n# Mixed project: run both\ncargo test --workspace 2>&1 && uv run pytest tests/ -v 2>&1","type":"text"}]},{"type":"paragraph","content":[{"text":"Capture full output as final evidence ","type":"text"},{"text":"[En]","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Step 5: Produce Summary Table","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"markdown"},"content":[{"text":"### validate-mr: \u003cMR title or number>\n\n| Area | Step | Evidence | Result |\n|------|------|----------|--------|\n| Rust: token-types | cargo build --workspace | [E1] 0 errors | PASS |\n| Rust: token-types | cargo test -p token-types | [E2] 12 passed | PASS |\n| Rust: token-types | cargo build --all-features | [E3] 0 errors | PASS |\n| Shell: hooks/pre-commit | shellcheck | [E4] 0 issues | PASS |\n| Revert-test: lib.rs:45 | break/fail/restore | [RT-1..5] genuine guard | PASS |\n| Final: cargo test --workspace | full suite | [E5] 694 passed, 0 failed | PASS |\n\n**Totals**: 6 steps — 6 PASS, 0 FAIL, 0 INCONCLUSIVE","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Step 6: Posting (--post flag only)","type":"text"}]},{"type":"paragraph","content":[{"text":"When ","type":"text"},{"text":"--post","type":"text","marks":[{"type":"code_inline"}]},{"text":" is given, post the summary table as a PR comment:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"gh pr comment \"$MR_NUMBER\" --body \"$(cat /tmp/validate-mr-summary.md)\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Skip posting when invoked from ","type":"text"},{"text":"/fix-pr","type":"text","marks":[{"type":"code_inline"}]},{"text":" — results feed into the Gate 3 summary comment instead.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Failure Behaviour","type":"text"}]},{"type":"paragraph","content":[{"text":"When any step produces ","type":"text"},{"text":"FAIL","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Surface the failures in the summary table with the evidence reference.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When called from ","type":"text"},{"text":"/fix-pr","type":"text","marks":[{"type":"code_inline"}]},{"text":": halt before Step 6 (Complete). The user must fix the failures or pass ","type":"text"},{"text":"--skip-validate","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"/fix-pr","type":"text","marks":[{"type":"code_inline"}]},{"text":" to bypass.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When called standalone: report failures and exit with non-zero status.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"INCONCLUSIVE results are reported but do not halt the workflow.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Exit Criteria","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"gh pr diff --name-only","type":"text","marks":[{"type":"code_inline"}]},{"text":" returned a non-empty file list (diff fetched)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Every detected area has at least one row in the summary table","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Every row shows an Evidence reference (","type":"text"},{"text":"[E1]","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"[E2]","type":"text","marks":[{"type":"code_inline"}]},{"text":", etc.) with the actual command output, not fabricated","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Revert-test attempted for at least one area with a covering test, or documented as INCONCLUSIVE with reason","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Final full-suite run appears in the summary table","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Summary table is present with columns: Area, Step, Evidence, Result","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Any FAIL result halts ","type":"text"},{"text":"/fix-pr","type":"text","marks":[{"type":"code_inline"}]},{"text":" before Step 6 when called from fix-pr","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Working tree is clean after skill completes (git checkout restore confirmed successful for any revert-test mutation)","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"validate-mr","role":"entrypoint","tags":["pr","mr","validation","test-plan","diff","revert-test","evidence"],"tools":[],"author":"@skillopedia","source":{"stars":298,"repo_name":"claude-night-market","origin_url":"https://github.com/athola/claude-night-market/blob/HEAD/plugins/sanctum/skills/validate-mr/SKILL.md","repo_owner":"athola","body_sha256":"012fe8ceb147ac81c50d373874a07ad63c80e95e0f0909bb49a346be6f908c02","cluster_key":"d85283be03d223fa26561b9fe9b4c80141ce3d03d80bc7cbf1ec302b6e7485ee","clean_bundle":{"format":"clean-skill-bundle-v1","source":"athola/claude-night-market/plugins/sanctum/skills/validate-mr/SKILL.md","bundle_sha256":"962d9898d307846951e2636f51ef56b75c4323f07664800b52af5f3aa529d8a7","attachment_count":0,"text_attachments":0,"binary_attachments":0},"cluster_size":1,"skill_md_path":"plugins/sanctum/skills/validate-mr/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"testing-qa","category_label":"Testing"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"testing-qa","complexity":"intermediate","import_tag":"clean-skills-v1","model_hint":"standard","alwaysApply":false,"description":"Use when you need a diff-derived test plan for an MR — reads the diff, groups changes by area, runs targeted verifications, and proves revert-tests are genuine guards, not dead assertions.","dependencies":["leyline:git-platform","imbue:proof-of-work"],"usage_patterns":["diff-derived-test-plan","revert-test-quality-check","evidence-capture"],"estimated_tokens":650,"progressive_loading":false}},"renderedAt":1782986935275}

validate-mr: Diff-Derived Test Plan Generate and self-execute a validation plan matched to what actually changed in an MR. Replaces generic "tests pass" with area-targeted evidence and revert-test quality checks that prove tests catch regressions. When To Use - End of Step 5 (Validate), before Step 6 (Complete) - Standalone after any MR fix, to generate targeted validation evidence - When you need proof that revert-tests are genuine guards When NOT To Use - with only formatting or doc changes (no logic changed) - No diff available (clean branch, nothing changed) - passed to Algorithm Step 1:…