build: add .cargo/mutants.toml timeout floor + mutation-testing guidance (STORY-147) - #421
Merged
Merged
Conversation
Mechanical rustfmt pass only (whitespace/layout, content-preserving) on the pre-existing Red Gate test file (commit fa23ce0) to satisfy the cargo fmt --check CI gate. No assertion or test-logic changes; all 4 AC-147-001..004 tests re-verified green before and after.
…out floor (F-S147P1-001/-003, AC v2.2)
…nts.toml timeout floor (F-S147P1-002/-004) Deletes the repo-root mutants.toml decoy — cargo-mutants never reads that location by default and silently ignored its jobs=1 setting. Adds .cargo/mutants.toml (the only path cargo-mutants reads), setting a minimum_test_timeout = 300 floor to defend the auto-timeout mechanism against load-induced false 0-missed results. Deliberately omits a jobs key: jobs is not a valid Config field under deny_unknown_fields and would abort every mutation run with a fatal parse error; parallelism is CLI/env -only. Flips AC-147-001/002 and the config conjunct of AC-147-004.
…-verified behavior Rewrites the Mutation testing subsection to match ground truth established by F-S147P1-002/-004/-005 execution evidence: bare cargo mutants is already serial by default (the old note incorrectly attributed that to a repo-root mutants.toml, which cargo-mutants never reads); the incident cause was an explicit --jobs 8, and no config file can override an explicit CLI --jobs flag; the config-file defense is .cargo/mutants.toml's minimum_test_timeout floor, not a parallelism default, since jobs is not a valid config key at all. References PG-MUTANTS-JOBS-001, fix-tls-clienthello-frag F6, and drbothen/vsdd-factory#654. Flips AC-147-003, completes AC-147-004.
…trict numeric parse, rationale markers (F-S147P2-001/-002)
…ST-NAME-SYNC-001)
…set — -common +test_tool (F-S147P3-001/-002)
…(F-S147P4-001, durable anti-drift fix)
…onvention comment (F-S147P5-002)
Records VHS terminal evidence for AC-147-001..004 (config timeout floor, guard-test + real cargo-mutants tool enforcement, CLAUDE.md guidance section, and the both-defenses conjunction self-audit), each with a real success path and a real negative/error path, captured at tip 7ff84f5.
Zious11
added a commit
that referenced
this pull request
Jul 20, 2026
STORY-147 (Repo-Local Mutation-Testing Defaults: .cargo/mutants.toml Timeout Floor + CLAUDE.md Guidance) DELIVERED. PR #421 squash-merged to develop at f0cb737 (human-executed merge, per-PR explicit authorization, DF-MERGE-AUTH-CLASSIFIER-001 satisfied). Feature branch + worktree .worktrees/STORY-147 removed. CI 13/13 (Semantic PR recovered after a GitHub-declared Minor Service Outage). Dual pr-reviewer APPROVE; security CLEAN. Step-4.5 adversary CONVERGED P6/P7/P8 (8 passes). - sprint-state.yaml: STORY-147 status pending->done; pr/merge_commit/ merged_date recorded; branch/worktree cleared. - STORY-INDEX.md v3.80->v3.81: STORY-147 status ready->delivered; wave-84 Delivery Progress row updated (1/3 DELIVERED); changelog entry added. - STATE.md: stories_delivered 113->114; story_index_version v3.81; develop_head f0cb737; EXACT RESUME POINT, Project Metadata, Phase Progress, Concurrent Cycles, and Session Resume Checkpoint updated; Decisions Log D-481 added; Current Phase Steps rolled under last-5 rule (D-478 row archived to cycles/wave-084/burst-log.md; superseded checkpoint archived to cycles/wave-084/session-checkpoints.md). Input-hash: re-baselined 7 stale stories (STORY-164/165, 6th re-baseline of the STORY-INDEX-in-inputs cluster; STORY-175..179, 3rd re-baseline of the STATE.md-in-inputs cluster) via the canonical Python tool (bin/compute-input-hash --write --scan). Final scan: MATCH=132 STALE=0. Ride-alongs (provenance): regression-state.json and sidecar-learning.md were already modified in the .factory worktree prior to this burst, produced by the STORY-147 delivery pipeline's own tooling — regression-state.json holds the latest `cargo test --test repo_mutation_config_tests` regression re-run result (2026-07-20T00:30:28Z, status pass) superseding a stale pre-fix command-line snapshot; sidecar-learning.md accumulated automated session-end markers appended by the session-end hook across the STORY-147 delivery session. Both are included in this commit as pending artifacts with no content authored by state-manager.
Zious11
added a commit
that referenced
this pull request
Jul 20, 2026
…(D-483) D-483 SESSION WRAP (2026-07-20): human-requested pause at clean milestone. Wave-84 2/3 delivered (STORY-147 PR #421 f0cb737, STORY-166 PR #426 fa9be70). This session (D-480..D-482, exhaustive): E-11 upstream disposition burst (D-480), STORY-147 DELIVERED (D-481, placebo-config catch), STORY-166 DELIVERED (D-482, CI-guard false-green catch, anchor-grammar tooling). No in-flight work; no story worktrees; no abandoned sub-agents. STATE.md: pipeline ACTIVE->PAUSED; timestamp refreshed; current_step -> D-483; D-483 added to Current Phase Steps (D-480 row rolled out to cycles/wave-084/burst-log.md) and Decisions Log; Session Resume Checkpoint replaced with D-483 checkpoint (prior STORY-166-delivered checkpoint archived to cycles/wave-084/session-checkpoints.md); EXACT RESUME POINT / Project Metadata / Concurrent Cycles / Historical Content updated for consistency; STORY-INDEX-IN-INPUTS-CHURN drift item updated (3rd STATE.md-cluster re-baseline). input-hash: re-baselined STORY-175..179 (canonical tool; all five list .factory/STATE.md in inputs, re-staled by this commit's STATE.md write). Final scan MATCH=132 STALE=0. sidecar-learning.md rode along (session-end provenance marker).
Merged
10 tasks
Zious11
added a commit
that referenced
this pull request
Jul 20, 2026
…gitignore (STORY-176) (#427) # [STORY-176] Feature-IEC104 Cycle-Close: Local Gate + Tooling Hygiene Sweeps **Epic:** E-11 — Tooling and Self-Improvement **Mode:** maintenance (governance/tooling — NO Rust production change) **Convergence:** CONVERGED after 8 adversarial passes (BC-5.39.001 SATISFIED; streak P6/P7/P8)       This PR delivers three tooling hygiene sweep items from the wave-84 E-11 (Feature-IEC104 Cycle-Close) batch. It extends `bin/check-green-doc-tense` with four stub-era phrase patterns (26–29) that catch compile-only seam vocabulary missed by the original 25-pattern gate, completes the gate's TOKEN LIST docstring (tokens 1..29), and adds a 91-fixture self-test suite with expected-label assertions. Separately it wires a `.gitignore` `mutants.out*/` glob to exclude cargo-mutants output directories from `git status`, guards that glob with a new regression test (`bin/test_gitignore_mutants_glob.py`), and extends the `bin-selftest` CI job to execute that file (closing PG-W74-CI-BIN-SELFTEST recurrence F-S176P4-001). No Rust production code is changed; all three deliverables are governance/tooling files. --- ## Architecture Changes ```mermaid graph TD CI["ci.yml\n(bin-selftest job)"] -->|runs| T1["bin/test_check_green_doc_tense.py\n91 fixtures"] CI -->|runs NEW| T2["bin/test_gitignore_mutants_glob.py\n2 fixtures"] T1 -->|exercises| Gate["bin/check-green-doc-tense\n+4 patterns (26-29)\n+TOKEN LIST complete"] Gate -->|scans| RS["*.rs tracked files\n(114 files, 0 FP)"] T2 -->|asserts| GI[".gitignore\nmutants.out*/"] style T2 fill:#90EE90 style GI fill:#90EE90 ``` <details> <summary><strong>Architecture Decision Record</strong></summary> ### ADR: Extend Gate Vocabulary Rather Than Allowlist **Context:** The green-doc-tense gate (patterns 1–25) already guards Rust source files against stale RED-phase comment headers. Wave-84 Phase-1 spec crystallization identified four additional stub-era phrase patterns (compile-only seam, skeleton compiles, are currently compile-only, until … wired) found in production Rust files and not covered by any existing pattern. **Decision:** Add patterns 26–29 as regex entries in `bin/check-green-doc-tense`, completing the TOKEN LIST docstring (1..29) and adding expected-label assertions to the self-test suite. A separate fabricated "allowlist" mechanism described in the v2.2 story was identified as nonexistent during pre-Pass-1 spec-route remediation (v2.2→v2.3) and was not implemented. **Rationale:** Extending the pattern list is the exact mechanism already used by patterns 1–25; no new infrastructure is required. Zero-FP constraint is enforced by running the gate against all 114 tracked Rust files and verifying zero hits before committing. **Alternatives Considered:** 1. Separate allowlist mechanism — rejected: does not exist in the gate's design; spec-route remediation confirmed fabrication and removed the claim. 2. New gate binary — rejected: overkill for four additional regex patterns in a Python script. **Consequences:** - Four additional stub-era phrase categories blocked from Rust files going forward. - gate zero-FP: 114 files, 0 false positives confirmed. - PG-W74-CI-BIN-SELFTEST recurrence (F-S176P4-001) closed: `bin/test_gitignore_mutants_glob.py` is now a first-class citizen of the `bin-selftest` CI job. </details> --- ## Story Dependencies ```mermaid graph LR S147["STORY-147\n✓ merged PR #421"] --> S176["STORY-176\n→ this PR"] S166["STORY-166\n✓ merged PR #426"] --> S176 S176 --> WAVE84CLOSE["wave-84 gate\n(all 3 stories delivered)"] style S176 fill:#FFD700 style S147 fill:#90EE90 style S166 fill:#90EE90 ``` STORY-176 has no explicit `depends_on` entries in the STORY-INDEX; it is the third and final story in wave-84 batch alongside the already-merged STORY-147 (#421) and STORY-166 (#426). No downstream stories depend on this PR (STORY-177/178/179 are superseded). --- ## Spec Traceability ```mermaid flowchart LR BC001["BC-5.39.001\nAdversarial convergence\n3-clean-streak"] --> AC001["AC-176-001\nGate patterns 26-29\n+ TOKEN LIST + 91-fixture self-test"] PG_VOCAB["PG-GATE-VOCAB-BLINDSPOT\n(wave-84 trigger)"] --> AC001 AC001 --> T1["bin/test_check_green_doc_tense.py\n91 fixtures, expected-label assertions"] T1 --> GATE["bin/check-green-doc-tense\npatterns 26-29 added"] PG_CI["PG-W74-CI-BIN-SELFTEST\n(recurrence F-S176P4-001)"] --> AC003["AC-176-003\nmutants.out*/ glob + regression guard\n+ CI wiring"] AC003 --> T2["bin/test_gitignore_mutants_glob.py\n2 fixtures"] T2 --> GI[".gitignore\nmutants.out*/"] T2 --> CI["ci.yml\nbin-selftest job extended"] AC002["AC-176-002\nDelivery-doc re-baseline note\n(factory-artifacts branch)"] --> NOTES[".factory/maintenance/\ndelivery-doc-currency-protocol.md\n(NOT in this develop PR)"] ``` | BC / Process Gap | AC | Test File | Implementation | Status | |------------------|----|-----------|----------------|--------| | BC-5.39.001 + PG-GATE-VOCAB-BLINDSPOT | AC-176-001 | `bin/test_check_green_doc_tense.py` | `bin/check-green-doc-tense` patterns 26-29 | PASS | | PG-W74-CI-BIN-SELFTEST (F-S176P4-001) | AC-176-003 | `bin/test_gitignore_mutants_glob.py` | `.gitignore` + `ci.yml` bin-selftest | PASS | | AC-176-002 | Factory-artifacts deliverable | N/A (grep evidence) | `.factory/maintenance/delivery-doc-currency-protocol.md` re-baseline note | PASS (factory-artifacts branch) | --- ## Test Evidence ### Coverage Summary | Metric | Value | Threshold | Status | |--------|-------|-----------|--------| | Green-doc-tense self-test | 91 / 91 pass | 100% | PASS | | Gitignore glob test | 2 / 2 pass | 100% | PASS | | Gate zero-FP scan | 114 files, 0 FP | 0 FP | PASS | | Cargo test suites | 94 / 94 suites | 100% | PASS | | SHA pins | 18 / 18 identical | 100% | PASS | | Clippy | 0 warnings | 0 | PASS | | fmt | clean | clean | PASS | | Holdout evaluation | N/A — governance/tooling | N/A | N/A | | Mutation kill rate | N/A — no production Rust changes | N/A | N/A | ### Test Flow ```mermaid graph LR SelfTest["91 self-test fixtures\n(bin/test_check_green_doc_tense.py)"] GitignoreTest["2 gitignore fixtures\n(bin/test_gitignore_mutants_glob.py)"] CargoTest["94 cargo test suites"] GateScan["Gate zero-FP scan\n114 files"] SelfTest -->|91/91| Pass1["PASS"] GitignoreTest -->|2/2| Pass2["PASS"] CargoTest -->|94/94| Pass3["PASS"] GateScan -->|0 FP| Pass4["PASS"] style Pass1 fill:#90EE90 style Pass2 fill:#90EE90 style Pass3 fill:#90EE90 style Pass4 fill:#90EE90 ``` | Metric | Value | |--------|-------| | **New tests** | 91 added (test_check_green_doc_tense.py fixtures) + 2 added (test_gitignore_mutants_glob.py) | | **Total gate self-test suite** | 91 pass in <1s | | **Gitignore regression guard** | 2 pass in <1s | | **Cargo suites** | 94 suites, all green (no new Rust tests — no production Rust changes) | | **Regressions** | 0 | <details> <summary><strong>Detailed Test Results (row-verified per PG-W74-PRDESC-ROW-VERIFY)</strong></summary> ### Row-Verified Test Entries (PG-W74-PRDESC-ROW-VERIFY: ≥3 rows verified) | Test | Source File | Fixture Type | Result | Duration | |------|-------------|--------------|--------|----------| | Pattern 26 `skeleton compiles?\b` — positive | `bin/test_check_green_doc_tense.py` | Expected-label assertion (PATTERN_26) | PASS | <1ms | | Pattern 26 `skeleton compiles?\b` — negative (`compiled` suffix excluded) | `bin/test_check_green_doc_tense.py` | Expected-label assertion (NOT-PATTERN-26) | PASS | <1ms | | Pattern 27 `(exposes\|is a\|are) compile-only seam(s)` — positive | `bin/test_check_green_doc_tense.py` | Expected-label assertion (PATTERN_27) | PASS | <1ms | | Pattern 28 `(are\|is) (currently) compile-only` — positive | `bin/test_check_green_doc_tense.py` | Expected-label assertion (PATTERN_28) | PASS | <1ms | | Pattern 29 `until … wired` bare form — positive (`fails until wired`) | `bin/test_check_green_doc_tense.py` | Expected-label assertion (PATTERN_29) | PASS | <1ms | | Pattern 29 — negative lookahead excludes `wired it` | `bin/test_check_green_doc_tense.py` | Expected-label assertion (NOT-PATTERN-29) | PASS | <1ms | | `.gitignore` has `mutants.out*/` glob line | `bin/test_gitignore_mutants_glob.py` | Presence assertion | PASS | <1ms | | `mutants.out*/` glob matches `mutants.out` and `mutants.out.j4-invalid` | `bin/test_gitignore_mutants_glob.py` | `fnmatch` pattern assertion | PASS | <1ms | | Full suite 91/91 pass (convergence report verification) | `bin/test_check_green_doc_tense.py` | Aggregate count | PASS | <1s | **Aggregate count cross-check (PG-W74-PRDESC-ROW-VERIFY):** The convergence report records `91/0 pass (exit 0)` for the self-test suite (Final Verification Evidence table). The CHANGELOG entry states "91 passed, 0 failed". These two independently recorded values are consistent. The gitignore test count (2/0) is consistent across the convergence report and CHANGELOG. No count inflation is present. ### Coverage Analysis | Metric | Value | |--------|-------| | Lines added | 727 insertions across 6 production/test files + demo evidence | | Production Rust lines | 0 (no Rust files modified) | | New Python gate lines | ~244 (bin/check-green-doc-tense +129 lines, bin/test_check_green_doc_tense.py +165 lines) | | New Python test file | 80 lines (bin/test_gitignore_mutants_glob.py new) | | Uncovered paths | None — all new pattern branches exercised by expected-label assertions | ### Mutation Testing | Module | Mutants | Killed | Survived | Kill Rate | |--------|---------|--------|----------|-----------| | Production Rust (no change) | N/A | N/A | N/A | N/A | | bin/check-green-doc-tense (Python tooling) | Not run — out of scope for cargo-mutants | N/A | N/A | N/A | </details> --- ## Demo Evidence 5 recordings captured per AC (scrub-gate: PASS — zero absolute host paths): | AC | Demo File | Evidence | Result | |----|-----------|----------|--------| | AC-176-001 (gate success path) | `docs/demo-evidence/STORY-176/AC-176-001-gate-success.{gif,webm,tape}` | `python3 bin/check-green-doc-tense` exits 0, 114 files scanned | PASS | | AC-176-001 (self-test) | `docs/demo-evidence/STORY-176/AC-176-001-gate-selftest.{gif,webm,tape}` | `python3 bin/test_check_green_doc_tense.py` → 91 passed, 0 failed | PASS | | AC-176-001 (negative path) | `docs/demo-evidence/STORY-176/AC-176-001-gate-negative.{gif,webm,tape}` | Gate detects `skeleton compiles` → exits 1; cleanup → gate returns to PASS | PASS | | AC-176-002 (re-baseline note) | `docs/demo-evidence/STORY-176/AC-176-002-rebaseline-note.{gif,webm,tape}` | grep shows 3 re-baseline lines in delivery-doc-currency-protocol.md | PASS | | AC-176-003 (gitignore glob) | `docs/demo-evidence/STORY-176/AC-176-003-gitignore-glob.{gif,webm,tape}` | `.gitignore` has `mutants.out*/`; dirs invisible to `git status`; test 2/0; CI wiring confirmed | PASS | --- ## Holdout Evaluation N/A — evaluated at wave gate. This story delivers governance/tooling with no behavioral user-facing output. Holdout evaluation is not applicable (E-11 process-gap codification pattern, consistent with STORY-147 and STORY-166). --- ## Adversarial Review | Pass | Verdict | HIGH | MED | LOW | Status | |------|---------|------|-----|-----|--------| | Pre-P1 spec audit | SPEC-ROUTE | — | — | — | v2.2→v2.3 remediation (fabricated allowlist + wrong locus deleted) | | P1 | FAIL_FINDINGS | 0 | 3 | 5 | Fixed (commits 61f6db4, 08fc7d8) | | P2 | FAIL_FINDINGS | 0 | 1 | 2 | Fixed (commit b583c4b) | | P3 | FAIL_FINDINGS | 0 | 1 | 0 | Fixed (story v2.5) | | P4 | FAIL_FINDINGS | 0 | 1 | 2 | Fixed (commit ea4bcd8 — PG-W74-CI-BIN-SELFTEST recurrence) | | P5 | FAIL_FINDINGS | 0 | 1 | 1 | Fixed (story v2.7) | | P6 | NITPICK_ONLY | 0 | 0 | 0 | Streak 1/3 | | P7 | NITPICK_ONLY | 0 | 0 | 0 | Streak 2/3 | | P8 | NITPICK_ONLY | 0 | 0 | 0 | Streak 3/3 — CONVERGED (BC-5.39.001 SATISFIED) | **Convergence:** BC-5.39.001 SATISFIED — 3 consecutive NITPICK_ONLY passes (P6/P7/P8). Spec evolved v2.2→v2.7 across 8 passes. Final code tip `ea4bcd8e` unchanged since Pass 4. <details> <summary><strong>High-Severity Findings & Resolutions</strong></summary> ### F-S176P1-001 (MEDIUM) — Pattern-29 negative lookahead too narrow - **Location:** `bin/check-green-doc-tense` - **Category:** pattern-logic - **Problem:** Original `until.*is wired` missed bare "fails until wired" form. - **Resolution:** Replaced with `until.*wired` + negative lookahead excluding object pronouns/articles. Commit `61f6db4c`. - **Test added:** expected-label assertion PATTERN_29 (bare form fixture) ### F-S176P1-002 (MEDIUM) — Pattern-26 missing trailing `\b` word-boundary anchor - **Location:** `bin/check-green-doc-tense` - **Category:** pattern-logic - **Problem:** Pattern matched "compiled" (past tense) inside compound identifiers. - **Resolution:** Added trailing `\b` after `compiles?`. Commit `61f6db4c`. - **Test added:** NOT-PATTERN-26 negative fixture for "compiled" suffix. ### F-S176P1-003 (MEDIUM) — Stale RED-phase prose in gate's own test files - **Location:** `bin/test_check_green_doc_tense.py` (3 loci including STORY-174 sibling) - **Category:** spec-fidelity - **Problem:** Gate test harness contained exactly the stub-era language the gate was designed to catch; past-tense rewording required. - **Resolution:** Past-tense prose reframe at 3 loci. Commit `08fc7d88`. ### F-S176P4-001 (MEDIUM) — PG-W74-CI-BIN-SELFTEST recurrence - **Location:** `.github/workflows/ci.yml` - **Category:** CI coverage gap - **Problem:** New `bin/test_gitignore_mutants_glob.py` not wired into bin-selftest CI job; test file never executed by CI provides no regression guarantee. - **Resolution:** Extended bin-selftest job; renamed job count-free to prevent future count-stale drift. Commit `ea4bcd8e`. PG-W84-011 filed. </details> --- ## Security Review ```mermaid graph LR Critical["Critical: 0"] High["High: 0"] Medium["Medium: 0"] Low["Low: 1 (SEC-001, pre-existing)"] style Critical fill:#90EE90 style High fill:#90EE90 style Medium fill:#90EE90 style Low fill:#87CEEB ``` **Verdict: APPROVE** — No CRITICAL/HIGH findings. One LOW finding (SEC-001) is a pre-existing defense-in-depth gap not introduced by this PR; does not block merge. <details> <summary><strong>Security Scan Details</strong></summary> ### SEC-001 (LOW) — CWE-22 Path Prefix Confusion in `_collect_rust_files` - **File:** `bin/check-green-doc-tense` (pre-existing; not introduced by this PR) - **CWE:** CWE-22 (Path Traversal) - **Problem:** `startswith` check on resolved paths allows a crafted git index entry with a prefix-overlapping path (e.g. `../wirerust-sibling/file.rs`) to pass containment check. Impact: file content disclosure in CI logs only; no code execution. - **Exploitability:** Theoretical — requires prior compromise of the git index. - **Recommended follow-up:** Replace `str(p).startswith(str(resolved_root))` with `p.is_relative_to(resolved_root)` (Python 3.9+). Does not block this PR. ### Injection Review — CLEAN - `subprocess.run` calls use list form, no `shell=True`, no user-controlled input. - Patterns 26-29 are source literals; no nested quantifiers; no ReDoS risk. ### CI Workflow Review — CLEAN - New step is `run:` only — no new `uses:` action reference. - `bin-selftest` job retains `permissions: contents: read` (unchanged). - No new secrets referenced or exposed. ### A08 Supply Chain — CLEAN - No new external `uses:` references; all existing refs remain SHA-pinned. - No new Python dependencies (stdlib only: `re`, `subprocess`, `sys`, `pathlib`). ### Dependency Audit - No new Python dependencies. - No Rust dependency changes; `cargo audit` baseline unchanged. ### Formal Verification N/A — no Rust production code. Python tooling scripts are not in scope for Kani/proptest/fuzz. </details> --- ## Risk Assessment & Deployment ### Blast Radius - **Systems affected:** CI pipeline (`bin-selftest` job), developer tooling gate (`bin/check-green-doc-tense`), `.gitignore` cleanliness. - **User impact:** If the gate extension introduces false positives, developers running `check-green-doc-tense` would see spurious failures on valid Rust files. This is mitigated by the zero-FP scan over 114 tracked files. - **Data impact:** None. - **Risk Level:** LOW — tooling-only change; no production Rust code modified; zero-FP verified. ### Performance Impact | Metric | Before | After | Delta | Status | |--------|--------|-------|-------|--------| | Gate scan time (114 files) | ~0.3s | ~0.3s | negligible | OK | | CI bin-selftest job | ~5s | ~6s | +1s (new test file) | OK | | cargo test | 94 suites baseline | 94 suites (no change) | 0 | OK | <details> <summary><strong>Rollback Instructions</strong></summary> **Immediate rollback (< 2 min):** ```bash git revert 62b7918 git push origin develop ``` The revert removes the four new patterns and restores `bin/check-green-doc-tense` to its pre-PR state. The `.gitignore` glob removal is the only user-visible change that requires attention: any `mutants.out*` directories will reappear in `git status` after rollback. **Verification after rollback:** - Run `python3 bin/check-green-doc-tense` — should pass with the original 25 patterns. - Run `python3 bin/test_check_green_doc_tense.py` — will revert to pre-PR fixture count. - Run `cargo test --all-targets` — should remain green (no Rust changes to revert). </details> ### Feature Flags None — this change is shipped unconditionally as a tooling extension. --- ## Traceability | Process Gap / Requirement | Story AC | Test | Verification | Status | |---------------------------|---------|------|-------------|--------| | PG-GATE-VOCAB-BLINDSPOT (pattern 26 — `skeleton compiles?\b`) | AC-176-001 | `test_check_green_doc_tense.py` PATTERN_26 fixture | Expected-label assertion | PASS | | PG-GATE-VOCAB-BLINDSPOT (pattern 27 — `compile-only seam`) | AC-176-001 | `test_check_green_doc_tense.py` PATTERN_27 fixture | Expected-label assertion | PASS | | PG-GATE-VOCAB-BLINDSPOT (pattern 28 — `currently compile-only`) | AC-176-001 | `test_check_green_doc_tense.py` PATTERN_28 fixture | Expected-label assertion | PASS | | PG-GATE-VOCAB-BLINDSPOT (pattern 29 — `until … wired`) | AC-176-001 | `test_check_green_doc_tense.py` PATTERN_29 fixture | Expected-label assertion | PASS | | PG-W74-CI-BIN-SELFTEST recurrence (F-S176P4-001) | AC-176-003 | `bin/test_gitignore_mutants_glob.py` | CI bin-selftest job execution | PASS | | mutants.out*/ git hygiene | AC-176-003 | `bin/test_gitignore_mutants_glob.py` glob assertions | fnmatch pattern test | PASS | <details> <summary><strong>Full VSDD Contract Chain</strong></summary> ``` PG-GATE-VOCAB-BLINDSPOT -> AC-176-001 -> test_check_green_doc_tense.py (91 fixtures) -> bin/check-green-doc-tense (patterns 26-29) -> ADV-P8-CONVERGED PG-W74-CI-BIN-SELFTEST -> AC-176-003 -> test_gitignore_mutants_glob.py (2 fixtures) -> .gitignore (mutants.out*/) + ci.yml (bin-selftest extended) -> ADV-P8-CONVERGED AC-176-002 (factory-artifacts) -> delivery-doc-currency-protocol.md re-baseline note -> ADV-P8-CONVERGED (factory-artifacts branch; NOT in this develop PR) ``` </details> --- ## AI Pipeline Metadata <details> <summary><strong>Pipeline Details</strong></summary> ```yaml ai-generated: true pipeline-mode: maintenance factory-version: "1.0.0-rc.23" pipeline-stages: spec-crystallization: completed story-decomposition: completed tdd-implementation: completed holdout-evaluation: N/A (governance/tooling) adversarial-review: completed formal-verification: N/A (no Rust production code) convergence: achieved convergence-metrics: adversarial-passes: 8 clean-streak: [P6, P7, P8] criterion: BC-5.39.001 final-code-tip: ea4bcd8 story-version: v2.7 spec-novelty: N/A test-kill-rate: N/A (tooling-only) holdout-satisfaction: N/A (governance/tooling) models-used: builder: claude-sonnet-4-6 adversary: (VSDD factory adversary) wave: 84 story-points: 2 epic: E-11 generated-at: "2026-07-20T23:59:00Z" ``` </details> --- ## Pre-Merge Checklist - [x] All CI status checks passing (local verification: green-doc-tense-gate PASS, bin-selftest PASS, cargo test 94/94, clippy clean, fmt clean, SHA pins 18/18, changelog-gate PASS) - [x] Zero false positives verified on 114 tracked Rust files - [x] No critical/high security findings (tooling-only; no production Rust changes) - [x] Rollback procedure documented - [x] No feature flags required - [x] Adversarial convergence achieved (BC-5.39.001 SATISFIED, 8 passes, P6/P7/P8 clean streak) - [x] Demo evidence: 5 recordings, 1 per AC coverage path, scrub-gate PASS - [x] CHANGELOG [Unreleased] entry present (bin/ trigger set — required per AC-158-001) - [x] PG-W72-BREAKING-HOLDOUT-SWEEP: N/A (no behavioral/output-format change) - [ ] Human merge authorization (AUTHORIZE_MERGE=NO — DF-MERGE-AUTH-CLASSIFIER-001; wave-84 pattern)
Zious11
added a commit
that referenced
this pull request
Jul 20, 2026
#427 595cdba) STORY-176 squash-merged to develop 2026-07-20T21:46:45Z (human-executed, DF-MERGE-AUTH-CLASSIFIER-001 satisfied; wave-84 #421/#426/#427 pattern match). CI 13/13; pr-reviewer APPROVE; security APPROVE 0C/0H/0M/1L pre-existing; 8-pass adversary CONVERGED P6/P7/P8 (BC-5.39.001 SATISFIED). Story v2.7/6ec8772. Wave-84 DELIVERY COMPLETE (3/3: STORY-147 #421 + STORY-166 #426 + STORY-176 #427). Integration gate + S-7.02 cycle-close remain (DF-CONVERGENCE-BEFORE-MERGE-001). Files updated: - STATE.md: D-485 decision; frontmatter (develop_head 595cdba, stories_delivered 116, story_index_version v3.84, timestamp 2026-07-21T03:20:00Z); EXACT RESUME POINT; Project Metadata; Phase Progress wave-84 (DELIVERY COMPLETE); Concurrent Cycles; CPS (D-485 DELIVERED row added, STORY-166 DELIVERED row rolled to burst-log, STORY-176 CONVERGED row status updated to DELIVERED/CONVERGED); Decisions Log D-485; Session Resume Checkpoint (next=wave-84 integration gate); Historical Content (+2 rows). - stories/STORY-INDEX.md: v3.83→v3.84 (STORY-176 ready→delivered, wave-84 3/3 DELIVERED, stories_delivered 115→116). - stories/sprint-state.yaml: STORY-176 status pending→done; pr:427, merge_commit:595cdba8, merged_date:2026-07-20. - cycles/wave-084/burst-log.md: D-485 burst narrative appended; STORY-166 DELIVERED CPS row archived (rolled out under last-5 rule). - cycles/wave-084/session-checkpoints.md: STORY-176 Step-4.5 CONVERGED checkpoint archived (superseded by D-485 STORY-176 DELIVERED burst checkpoint). Count-propagation sweep: stories_delivered 115→116 propagated to STATE.md + STORY-INDEX.md. story_index_version v3.83→v3.84 propagated to STATE.md frontmatter + story_index_note. Remaining fa9be70/v3.83 hits in file are intentional historical changelog entries (immutable).
Zious11
added a commit
that referenced
this pull request
Jul 24, 2026
PR #437 feat(iec104): detect timed control command TypeIDs 58–64 squash-merged to develop 2026-07-24T18:44:47Z, human-executed post-classifier-halt. DF-MERGE-AUTH-CLASSIFIER-001 satisfied (wave-84 pattern #421/#426/#427/#437). Changes: - STATE.md: D-507 appended; frontmatter vp_index_version v2.46→v2.47, story_index_version v3.91→v3.92, stories_delivered 116→117, develop_head updated to 421bf57; EXACT RESUME POINT, Project Metadata, Phase Progress wave-85, Convergence Status, Concurrent Cycles, CPS last-5 (D-507 added, D-502 rolled off), Decisions Log D-507 added, Active Carry-Forwards IEC104-TIMED-CMD-GAP-001 + CV-008 RESOLVED and removed, Session Resume Checkpoint updated. - stories/STORY-180.md: status ready→delivered (3 loci), version 1.1→1.2, changelog 1.2 row added, input-hash 8ddf419→e87befe (canonical Python; BC-2.19.029 v1.3 + BC-2.19.030 v1.2 changed; PG-HASH-HOOK-DIVERGENCE advisory-only). - stories/STORY-INDEX.md: v3.91→v3.92, STORY-180 row ready→delivered, wave-85 delivery row 1/2 DELIVERED. - specs/verification-properties/VP-INDEX.md: v2.46→v2.47, VP-047 source_bc += BC-2.19.029/030 (CV-008 RESOLVED). - stories/sprint-state.yaml: STORY-180 status in-progress→done, pr: 437, merge_commit: 421bf57, merged_date: 2026-07-24. Count-propagation sweep (S-7.02): grep for old counts (v3.91, v2.46, 116 delivered) across STATE.md, STORY-INDEX.md, VP-INDEX.md, ARCH-INDEX.md, BC-INDEX.md, prd.md — 0 files with stale strings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[STORY-147] Repo-Local Mutation-Testing Defaults: .cargo/mutants.toml Timeout Floor + CLAUDE.md Guidance
Epic: E-11 — Tooling and Self-Improvement
Mode: maintenance (governance/config-only story; no BCs authored — E-11 convention)
Convergence: CONVERGED after 8 adversarial passes (clean streak P6/P7/P8)
Encodes lesson PG-MUTANTS-JOBS-001 (fix-tls-clienthello-frag F6, 2026-07-01 — a
--jobs 8mutation run reported a false "0 missed" because infinite-loop mutantspegged all cores and inflated other mutants' wall-clock past the auto-timeout,
hiding two real survivors) into two repo-local defenses: (1)
.cargo/mutants.toml— the only path cargo-mutants actually reads by default — setting
minimum_test_timeout = 300as a timeout floor, and (2) aCLAUDE.md"Mutationtesting" note warning against high
--jobsand explaining why. A 9-test guardsuite (
tests/repo_mutation_config_tests.rs) enforces both defenses stay presentand valid on every
cargo testrun.Architecture Changes
This is a configuration/documentation-only story — no
src/changes. No runtimecomponent graph is affected; the "architecture" here is repo tooling configuration.
graph TD DevMachine["Developer machine"] -->|runs| CargoMutants["cargo-mutants 27.0.0 binary"] CargoMutants -->|reads by default| MutantsToml[".cargo/mutants.toml<br/>(NEW: minimum_test_timeout=300)"] ClaudeMd["CLAUDE.md<br/>(NEW: Mutation testing note)"] -.->|human-facing guidance| DevMachine GuardTests["tests/repo_mutation_config_tests.rs<br/>(NEW: 9 tests)"] -->|enforces content validity of| MutantsToml GuardTests -->|enforces content validity of| ClaudeMd style MutantsToml fill:#90EE90 style ClaudeMd fill:#90EE90 style GuardTests fill:#90EE90Architecture Decision Record
ADR: Timeout-floor config file, not a parallelism default
Context: PG-MUTANTS-JOBS-001 — an explicit
cargo mutants --jobs 8runsilently dropped two real mutation survivors because infinite-loop mutants
pegged all cores and pushed other mutants' wall-clock past the auto-timeout,
producing a false "0 missed" result.
Decision: Ship a
.cargo/mutants.tomlwithminimum_test_timeout = 300(a timeout-floor defense) plus a
CLAUDE.mdnote recommending low-parallelisminvocation (bare
cargo mutants, already serial by default, or explicit--jobs 1).Rationale: cargo-mutants 27.0.0's
Configstruct has nojobsfield andis
#[serde(default, deny_unknown_fields)]— ajobskey in any config fileis a FATAL parse error that aborts every run. Parallelism is CLI/env-only
(
--jobs/-j,CARGO_MUTANTS_JOBS) and no config file can override anexplicit CLI flag. The only config-expressible defense against the actual
failure mode (load-induced false timeouts) is raising the timeout floor.
Alternatives Considered:
mutants.tomlwithjobs = 1(the original v2.1 story design) —rejected: execution-verified against the installed cargo-mutants 27.0.0
(Pass-1 adversarial finding F-S147P1-002/-004/-005) that cargo-mutants never
reads a repo-root
mutants.toml(silently ignored) andjobsis not avalid key at all — this design would have shipped a placebo that either did
nothing or fatally aborted every run.
[package.metadata.mutants]inCargo.toml— rejected: also not a locationcargo-mutants reads.
Consequences:
cargo mutantsnow has a real,machine-enforced defense against the PG-MUTANTS-JOBS-001 failure mode.
config-enforceable — documented explicitly in
CLAUDE.mdand AC-147-003/004rather than silently assumed solved.
Story Dependencies
STORY-147 has no dependencies (
depends_on: []) and is not a dependency of anyother in-flight story.
graph LR STORY147["STORY-147<br/>🟡 this PR"] style STORY147 fill:#FFD700Spec Traceability
E-11 convention: this is a governance/config-only story with no authored BCs.
Traceability runs AC → Test → Source directly.
flowchart LR AC1["AC-147-001<br/>.cargo/mutants.toml timeout floor"] --> T1["test_AC_147_001_dot_cargo_mutants_toml_sets_timeout_floor"] AC2["AC-147-002<br/>content validity + no decoy + key allowlist"] --> T2["test_AC_147_002_config_content_valid_and_no_decoy_present"] AC2 --> T2b["test_AC_147_002_config_keys_are_all_in_v27_allowlist"] AC3["AC-147-003<br/>CLAUDE.md Mutation testing note"] --> T3["test_AC_147_003_claude_md_has_mutation_testing_section"] AC4["AC-147-004<br/>conjunction: both defenses present"] --> T4["test_AC_147_004_both_real_defenses_present_simultaneously"] T1 --> S1[".cargo/mutants.toml"] T2 --> S1 T2b --> S1 T3 --> S2["CLAUDE.md"] T4 --> S1 T4 --> S2Test Evidence
Coverage Summary
src/lines addedTest Flow
graph LR Unit["9 Guard Tests<br/>(5 AC-anchored + 4 scanner self-checks)"] Unit -->|repo_mutation_config_tests.rs| Pass1["PASS"] style Pass1 fill:#90EE90src/lines changedsrc/files touched)Detailed Test Results
New Tests (This PR) —
tests/repo_mutation_config_tests.rs(9 tests)test_AC_147_001_dot_cargo_mutants_toml_sets_timeout_floor.cargo/mutants.tomlexists withminimum_test_timeout >= 300test_AC_147_002_config_content_valid_and_no_decoy_presentmutants.tomlat repo root / no[package.metadata.mutants]test_AC_147_002_config_keys_are_all_in_v27_allowlistConfigallowlisttest_AC_147_003_claude_md_has_mutation_testing_sectiontest_AC_147_004_both_real_defenses_present_simultaneouslytest_F_S147P2_002_quoted_minimum_test_timeout_does_not_parse_as_validminimum_test_timeout = "300"(quoted) is rejected as a TOML type errortest_F_S147P2_002_unquoted_minimum_test_timeout_still_parsestest_F_S147P2_001_allowlist_scan_flags_unrecognized_keytest_F_S147P2_001_allowlist_scan_accepts_all_pinned_v27_0_0_keysRow-verification (PG-W74-PRDESC-ROW-VERIFY): rows 1, 4, 5, and 8 above were
row-verified against
tests/repo_mutation_config_tests.rson the PR HEAD commit(
c5feae4b) viagrep -n '^fn \|#\[test\]':test_AC_147_001_dot_cargo_mutants_toml_sets_timeout_floorconfirmed at line 217.test_AC_147_003_claude_md_has_mutation_testing_sectionconfirmed at line 375.test_AC_147_004_both_real_defenses_present_simultaneouslyconfirmed at line 447.test_F_S147P2_001_allowlist_scan_flags_unrecognized_keyconfirmed at line 522.Aggregate count "9 tests" cross-checked against actual CI/local run output below.
Coverage Analysis
No
src/files were added or modified by this PR (.cargo/mutants.toml,CLAUDE.md, andtests/repo_mutation_config_tests.rsonly) — line/branchcoverage metrics are not applicable in the usual sense; the new test file
itself is 100% exercised by its own 9
#[test]functions running to completion.Mutation Testing
N/A — this story's deliverable is mutation-testing configuration; running
cargo mutantsagainst a guard-test file that reads config/doc files is not ameaningful self-referential exercise. Convergence relied on adversarial review
(8 passes) instead.
Holdout Evaluation
N/A — evaluated at wave gate (wave-084 gate not yet closed at PR time).
Demo Evidence
Recorded at commit
7ff84f56(post adversarial-convergence, P6/P7/P8 clean) underdocs/demo-evidence/STORY-147/. 5 VHS recordings (GIF + WebM) covering all 4 ACs,including negative/revert paths; PG-W70-DEMO-SCRUB path-scrub gate passed. Full
report:
docs/demo-evidence/STORY-147/evidence-report.md.AC-147-001-config-file-timeout-floor.{gif,webm}cat .cargo/mutants.tomlshowsminimum_test_timeout = 300, nojobskey. Negative path:ls mutants.tomlat repo root fails — confirms the decoy location does not exist.AC-147-002-guard-test-success-negative-revert.{gif,webm}cargo test9/9 green; invalidjobs = 1injected → 3 tests FAIL with allowlist/fatal-key messages; reverted → 9/9 green again.AC-147-002-cargo-mutants-tool-enforcement.{gif,webm}cargo mutants --list→ TOML parse error); reverted → succeeds again with real mutant candidates printed.AC-147-003-claude-md-mutation-section.{gif,webm}cargo test ... test_AC_147_003green, thengrep -A 12 "### Mutation testing" CLAUDE.mdrenders the full section. Negative path:sed-deletes thePG-MUTANTS-JOBS-001line → guard test FAILS with the exact missing-reference message; reverted → green again.AC-147-004-conjunction-both-defenses.{gif,webm}cargo test ... test_AC_147_004green, combined view of both defenses side by side. Negative path: injecting the invalidjobskey breaks the config defense → conjunction test FAILS; reverted → both defenses restored, green again.Coverage: at least 1 recording per AC (AC-147-002 has 2, covering both the guard
test and the real cargo-mutants binary independently). All negative paths are
real mutations of the actual shipped files followed by a real revert — no
hand-written terminal output.
Adversarial Review
Convergence: CONVERGED per BC-5.39.001 — 3 consecutive clean passes (P6/P7/P8,
all NITPICK_ONLY, held code tip
7ff84f56with zero code churn). Full report:.factory/cycles/wave-084/STORY-147/convergence-report.md.High-Severity Findings & Resolutions
Finding F-S147P1-002/-004/-005 (HIGH, Pass 1) — placebo config design
mutants.tomlwith a
jobs = 1key. Execution probes against the installed cargo-mutants27.0.0 (plus 27.1.0 docs/source research) established cargo-mutants never
reads a repo-root
mutants.tomlandjobsis not a validConfigfield —shipping this design would have produced either a silently-ignored file or a
fatal parse error aborting every mutation run.
.cargo/mutants.tomlwithminimum_test_timeout = 300, a timeout-floordefense against the actual load-induced-false-timeout failure mode. AC-147-001
through AC-147-004 rewritten accordingly.
test_AC_147_001_dot_cargo_mutants_toml_sets_timeout_floor,test_AC_147_002_config_content_valid_and_no_decoy_presentNon-blocking residual: F-S147P8-001 (LOW, Pass 8)
tests/repo_mutation_config_tests.rstimeout_multiplierandbuild_timeout_multiplierinto one referenced field name.ratification per DF-CONVERGENCE-BEFORE-MERGE-001 — not a merge blocker.
Listed here for reviewer visibility, not resolved in this PR.
Security Review
graph LR Critical["Critical: 0"] High["High: 0"] Medium["Medium: 0"] Low["Low: 0"] style Critical fill:#90EE90 style High fill:#90EE90 style Medium fill:#90EE90 style Low fill:#90EE90Verdict: CLEAN — zero findings at any severity. Reviewed full diff (all 4
changed/added paths:
.cargo/mutants.toml,CLAUDE.md,tests/repo_mutation_config_tests.rs554 lines, and the 5
.tapedemo-recording sources plus byte-scan of the 10binary GIF/WebM recordings) at head
c5feae4b.Security Scan Details
Manual/SAST-equivalent review
env!(CARGO_MANIFEST_DIR)/Users/,/home/,~, username/email, or secret-prefix matches across both text and binary demo artifacts; tapes use a<REPO-ROOT>placeholder inside VHSHideblocks; the cargo-mutants absolute-path error line is confirmed sed-scrubbed with no leakage into the recorded binaries.cargo/mutants.tomlis a benign single-key config (minimum_test_timeout = 300); no risk surfaceCLAUDE.mdaddition is docs-only, no executable contentDependency Audit
Cargo.toml.Formal Verification
src/invariants changed.Redundant second review: a second security-review agent (
security-review-story147-b)was also dispatched in parallel as a cross-check; its result, if independently
returned, will be reconciled with the above before merge if it surfaces any
discrepancy.
Risk Assessment & Deployment
Blast Radius
.cargo/mutants.tomlonly affectslocal/CI invocations of the
cargo-mutantsbinary (not part of the shippedproduct);
CLAUDE.mdis documentation only; the new test file only assertsagainst those two files' contents.
src/changes, no behavior change to thewirerustbinary or library.Performance Impact
N/A — no runtime code changed.
cargo test --all-targetsgains 9 fastfilesystem-read-and-assert tests (sub-second each).
Rollback Instructions
Immediate rollback (< 5 min):
No feature flag applicable — config/docs-only change.
Verification after rollback:
cargo test --all-targetsstill green (guard tests removed along with thefiles they check).
.cargo/mutants.tomland the CLAUDE.md note absent again.Feature Flags
None — not applicable to this change.
Traceability
test_AC_147_001_dot_cargo_mutants_toml_sets_timeout_floortest_AC_147_002_config_content_valid_and_no_decoy_present,test_AC_147_002_config_keys_are_all_in_v27_allowlisttest_AC_147_003_claude_md_has_mutation_testing_sectiontest_AC_147_004_both_real_defenses_present_simultaneouslyFull VSDD Contract Chain
Note: this is a governance/config-only story (E-11 convention — no BCs authored,
per story frontmatter comment
# BC status: E-11 convention).AI Pipeline Metadata
Pipeline Details
Pre-Merge Checklist
src/lines changed)git revert, no flags).cargo/,CLAUDE.md,tests/,docs/) are all outside thesrc/|Cargo.toml|bin/triggerset (AC-158-001). No
[Unreleased]CHANGELOG entry required or included..factory/merge-config.yaml)