You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
chore(repo-hygiene): gitignore nested private sibling repo + redact workspace name
(1) Add `cve-assessment-framework/` to .gitignore — the nested private sibling
repo (own .git) was untracked but not ignored, so a broad `git add -A` from the
repo root could embed it as a gitlink and leak its existence to this public repo.
(2) Redact a private Bitbucket workspace name from a Rule #53 provenance note and
a session handoff (replaced with "a private Bitbucket workspace").
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CLAUDE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -477,7 +477,7 @@ These rules were extracted from recurring bugs and failures across 30+ developme
477
477
478
478
**Promotable to Rule-of-Four when:** the next adaptable-extension surface (decoder family, vendor adapter, JTAGTAP family, USB descriptor families, etc.) ships under the same shape — closed-grammar YAML+ plugin escape hatch + walker dispatch table + Rule #44 cross-firmware tool + Rule #46 paired canary + Wave-1+Wave-2 deep research methodology. Promotion date: 2026-05-22 (Rule-of-Three DURABLE BEYOND DEBATE).
479
479
480
-
53. **EXTENDS Rule #46 to the RECOGNIZER side of a substantiation gate: a gate that "recognizes" an exception, clear, or disposition MUST match the POSITIVE EVIDENCE behind it, NEVER a bare conclusion-tag that merely asserts the conclusion — a tag-matching recognizer launders unsubstantiated assertions straight past the gate.** Rule #46 establishes that any absence-asserting check ("0 violations / no drift / X is absent") needs a paired canary that synthesizes a violation and confirms REJECTION; that half is unchanged here — cite #46, don't re-derive it. This rule adds the second failure mode #46 doesn't cover: an absence-gate can have a perfect canary and STILL launder, if its allowlist/skip recognizer keys off a *marker* an upstream step writes rather than the *evidence* that marker is supposed to certify. The load-bearing distinction: a compliant recognizer regex matches a CONTENT token that constitutes proof (`CONFIG_X=n`, a version range, a named-foreign-vendor set, a concrete reachability artifact); a laundering recognizer matches a disposition-enum name or a bracketed rule-id (`[R47-L1]`, `platform_mismatch`, `MISATTR-FP`) as a standalone token. **Resolved-aware SKIP of an adjudication marker is permitted ONLY under a two-part test:** (1) the marker is emitted by a deliberate evidence-recording step in the SAME pipeline (not hand-typed ad hoc), AND (2) the substantiating evidence travels WITH the marker in the very artifact the gate reads — so the gate re-validates the evidence, not the label. A bare-tag membership test that trusts the tag without re-reading the evidence beside it is itself the laundering hole. **Axiom-4 binding** (the guilty-until-proven discipline this campaign runs on): the highest-risk dispositions to launder are the ones that *clear* risk (`not_reachable` / `not_affected` / `safe`), so a recognizer for those MUST key on immutable proof, NEVER on a mutable runtime annotation — "module not loaded" / "service inactive" / "currently unreachable" describe a state that can flip (an autoloadable kernel module, a disabled-but-present daemon), and matching them clears on absence-of-evidence, which Axiom 1 forbids. **Mechanical review-time gate:** grep every recognizer/allowlist regex in your gates for disposition-enum names or rule-id tokens used as standalone matches (vs. as a required prefix to an evidence token); each hit is a laundering candidate. Ship the recognizer's own canary: stamp a bare tag with NO evidence into a synthetic record, run the gate, confirm it FLAGS it (not skips it). **Wairz-native anchor:** the security-gate family (Rule #36 no-execute, Rule #45 no-decrypt, Rule #37 trust-anchor) has the same shape — a gate that trusts a self-asserted `signed=true` / `safe=true` / `no_decrypt_ok` label instead of re-deriving the proof (re-running signify, re-tokenizing the walker source, re-checking the SHA pin) is a tag-matcher; the wairz versions correctly re-derive, and Rule #53 names why that's load-bearing. **Evidence (Rule-of-One-plus; self-introduced + caught by self-audit, which is the honest framing — the discipline's value showed in catching its own violation):** (1) PRIMARY — the CR-1 over-clear gate's `R47-L1` recognizer matched 617 BARE `platform_mismatch [R47-L1]` tags carrying zero CPE evidence and laundered them past the gate (an Axiom-1 false-clear class I introduced); a self-audit caught it; the tags were un-laundered (`7c6f994b`), 20 re-substantiated with real CPE evidence and 597 re-opened guilty. (2) SECONDARY — the discipline then HELD: applying the heads-deepdive `not_reachable` demotions, I deliberately did NOT add a blanket `HEADS-DEEPDIVE` recognizer to CR-1; letting it scrutinize each rationale, it REJECTED 2 weak demotions ("module not loaded" for USB-autoloadable `ath9k_htc`/`gs_usb` — a mutable annotation, not non-reachability proof) and they were re-opened chainable, not laundered (`82f9aae8` arc). This session's `audit_misattribution.py` hardening (`b0aab59a`) operationalizes the two-part SKIP test: `_fp_resolved()` honours a `MISATTR-FP` tag only when ≥30 chars of evidence-matching rationale travels with it, and `_fp_meta_canary()` confirms a bare tag stays flagged. **Provenance note:** the worked examples + SHAs above originate in the sibling `cve-assessment-framework` repo (Bitbucket `surgprodsec`), not wairz — the rule is wairz-canonical because the *shape* (recognizer-vs-evidence, security-gate analog) recurs across both. **Companions:** Rule #46 (the absence-canary half this extends), #17 + #24 (silent-CLI-exit canary — same "tool confirmed nothing vs wasn't looking" family), #35a (pipe-induced exit obfuscation — verification-artifact-that-lies), #35b (mock vs live-canary — "X was called" vs "X was called with the right args"), #19 (evidence-first — clear only on positive evidence), #36 + #45 + #37 (the security-gate analog that must re-derive, not trust a label). Promotable to Rule-of-Two when a second independent tag-matching laundering hole surfaces in any gate. Promotion date: 2026-06-05.
480
+
53. **EXTENDS Rule #46 to the RECOGNIZER side of a substantiation gate: a gate that "recognizes" an exception, clear, or disposition MUST match the POSITIVE EVIDENCE behind it, NEVER a bare conclusion-tag that merely asserts the conclusion — a tag-matching recognizer launders unsubstantiated assertions straight past the gate.** Rule #46 establishes that any absence-asserting check ("0 violations / no drift / X is absent") needs a paired canary that synthesizes a violation and confirms REJECTION; that half is unchanged here — cite #46, don't re-derive it. This rule adds the second failure mode #46 doesn't cover: an absence-gate can have a perfect canary and STILL launder, if its allowlist/skip recognizer keys off a *marker* an upstream step writes rather than the *evidence* that marker is supposed to certify. The load-bearing distinction: a compliant recognizer regex matches a CONTENT token that constitutes proof (`CONFIG_X=n`, a version range, a named-foreign-vendor set, a concrete reachability artifact); a laundering recognizer matches a disposition-enum name or a bracketed rule-id (`[R47-L1]`, `platform_mismatch`, `MISATTR-FP`) as a standalone token. **Resolved-aware SKIP of an adjudication marker is permitted ONLY under a two-part test:** (1) the marker is emitted by a deliberate evidence-recording step in the SAME pipeline (not hand-typed ad hoc), AND (2) the substantiating evidence travels WITH the marker in the very artifact the gate reads — so the gate re-validates the evidence, not the label. A bare-tag membership test that trusts the tag without re-reading the evidence beside it is itself the laundering hole. **Axiom-4 binding** (the guilty-until-proven discipline this campaign runs on): the highest-risk dispositions to launder are the ones that *clear* risk (`not_reachable` / `not_affected` / `safe`), so a recognizer for those MUST key on immutable proof, NEVER on a mutable runtime annotation — "module not loaded" / "service inactive" / "currently unreachable" describe a state that can flip (an autoloadable kernel module, a disabled-but-present daemon), and matching them clears on absence-of-evidence, which Axiom 1 forbids. **Mechanical review-time gate:** grep every recognizer/allowlist regex in your gates for disposition-enum names or rule-id tokens used as standalone matches (vs. as a required prefix to an evidence token); each hit is a laundering candidate. Ship the recognizer's own canary: stamp a bare tag with NO evidence into a synthetic record, run the gate, confirm it FLAGS it (not skips it). **Wairz-native anchor:** the security-gate family (Rule #36 no-execute, Rule #45 no-decrypt, Rule #37 trust-anchor) has the same shape — a gate that trusts a self-asserted `signed=true` / `safe=true` / `no_decrypt_ok` label instead of re-deriving the proof (re-running signify, re-tokenizing the walker source, re-checking the SHA pin) is a tag-matcher; the wairz versions correctly re-derive, and Rule #53 names why that's load-bearing. **Evidence (Rule-of-One-plus; self-introduced + caught by self-audit, which is the honest framing — the discipline's value showed in catching its own violation):** (1) PRIMARY — the CR-1 over-clear gate's `R47-L1` recognizer matched 617 BARE `platform_mismatch [R47-L1]` tags carrying zero CPE evidence and laundered them past the gate (an Axiom-1 false-clear class I introduced); a self-audit caught it; the tags were un-laundered (`7c6f994b`), 20 re-substantiated with real CPE evidence and 597 re-opened guilty. (2) SECONDARY — the discipline then HELD: applying the heads-deepdive `not_reachable` demotions, I deliberately did NOT add a blanket `HEADS-DEEPDIVE` recognizer to CR-1; letting it scrutinize each rationale, it REJECTED 2 weak demotions ("module not loaded" for USB-autoloadable `ath9k_htc`/`gs_usb` — a mutable annotation, not non-reachability proof) and they were re-opened chainable, not laundered (`82f9aae8` arc). This session's `audit_misattribution.py` hardening (`b0aab59a`) operationalizes the two-part SKIP test: `_fp_resolved()` honours a `MISATTR-FP` tag only when ≥30 chars of evidence-matching rationale travels with it, and `_fp_meta_canary()` confirms a bare tag stays flagged. **Provenance note:** the worked examples + SHAs above originate in the sibling `cve-assessment-framework` repo (a private Bitbucket workspace), not wairz — the rule is wairz-canonical because the *shape* (recognizer-vs-evidence, security-gate analog) recurs across both. **Companions:** Rule #46 (the absence-canary half this extends), #17 + #24 (silent-CLI-exit canary — same "tool confirmed nothing vs wasn't looking" family), #35a (pipe-induced exit obfuscation — verification-artifact-that-lies), #35b (mock vs live-canary — "X was called" vs "X was called with the right args"), #19 (evidence-first — clear only on positive evidence), #36 + #45 + #37 (the security-gate analog that must re-derive, not trust a label). Promotable to Rule-of-Two when a second independent tag-matching laundering hole surfaces in any gate. Promotion date: 2026-06-05.
481
481
482
482
54. **A fact with ONE source-of-truth and N DERIVED representations that a downstream consumer ingests drifts SILENTLY when the source is patched in place — derive-don't-hand-maintain, regenerate ALL representations in the same write step, and gate cross-representation consistency (with a source-sanity floor, because a green parity gate proves AGREEMENT, not CORRECTNESS).** Niche carve-out against three neighbours: Rule #47 governs CODE that *reacts* to a state change (consumer hooks to rewire); Rule #35c governs read-boundary *normalization* of a JSONB shape at ingest; Rule #54 governs stale DATA COPIES — exported/rendered derivations (an alternate-format export, a package mirror, a generated report, a hand-typed current-state figure in prose) that a consumer reads directly and that must be regenerated from the source at WRITE time, never patched in the copy. Litmus: a hand-typed number or an alternate-format export = #54; a background poller/hook = #47; an `_normalize_*` at a read site = #35c. **Three sub-rules:** (a) DERIVE don't hand-maintain — wire every current-state figure to the single source via a regenerating span/template (the `<!--C:key-->value<!--/C-->` span + `refresh_package_docs.py` pattern); never hand-type a number that already exists in the canonical record. (b) On ANY source change, regenerate ALL derived representations in the SAME step and run a consistency gate (derived counts == source counts, version stamps agree). (c) The drift is invisible precisely because the source looks perfect — only a cross-representation diff, or a consumer reading the stale copy, reveals it. **SOURCE-SANITY guard clause (the non-obvious half):** "regenerate ALL from source" propagates a WRONG source to every consumer at once and the parity gate reports GREEN (uniformly wrong is still consistent) — strictly worse than visible hand-divergence, because nothing looks off. So the canonical/source record must ITSELF be derived-or-gated against ground truth: the consistency gate MUST include a source-sanity assertion (canonical-state per-device count == the source-export's own count) so a green result means agreement AND correctness, not just agreement. **NOT-APPLY boundary:** archived or date-stamped point-in-time captures stay frozen by design — `output/vex_history/`, dated snapshots, changelogs, postmortems, `*.bak`, and any "as of <date>" prose are deliberate records of a past state, NOT derived current-state, and regenerating them would corrupt the audit trail. Litmus: a version- or date-stamped path is a capture — leave it. **Enforceability / mechanization:** (i) regenerate via a single command with a `--check` mode (`refresh_package_docs.py --check` is the doc-number gate, LANDED — it diffs every span against canonical and exits non-zero on drift, and includes a malformed-span guard so a broken closer can't freeze a value undetected); (ii) the VEX cross-representation gate (`audit_vex_representations.py`, GATE LANDED this session — PARITY across OpenVEX + CycloneDX + the 2 package mirrors AND the SOURCE-SANITY floor, with a Rule #46 meta-canary); (iii) when enumerating "what reads a COPY of this?", use the Rule #31 width-canary grep discipline (narrow patterns under-count derived representations). **Evidence (Rule-of-Two):** (1) the canonical OpenVEX was current (v107/v88/v86; affected 4,739/11,511/6,777) while the CycloneDX exports + package-mirror VEX had drifted to stale versions — the SBOM-consumer / Notified-Body artifacts silently lagged thousands of affected statements; the USER caught it (no gate existed), fixed by regenerating all 6 representations (`2d724d49`) and then shipping the standing `audit_vex_representations.py` gate (`b0aab59a`) so it can't recur. (2) hand-authored current-state numbers across ~10 conformance docs went stale every revision round; the durable fix was span-wiring each to canonical (the malformed-span freeze that defeated a derivation which LOOKED wired but wasn't is the Rule #53 incident, cross-referenced — its derived-value impact belongs here, its laundering-blindness belongs there). **Wairz-native anchor:** Rule #9 (frontend `Record<UnionType, Config>` maps are a DERIVED copy of a backend enum — adding a backend value without regenerating the frontend map is exactly this drift, crashing React with `undefined`); generated SBOM / HBOM exports (a derived view of the components table); Rule #21 (the CLAUDE.md ↔ `.mex/context/conventions.md` Verify Checklist mirror is a derived copy that must be regenerated in the same commit). **Provenance note:** the VEX/canonical SHAs above originate in the sibling `cve-assessment-framework` repo, not wairz; the rule is wairz-canonical because the derived-copy-drift shape recurs across both (frontend enum maps, SBOM exports, the conventions.md mirror). **Companions:** Rule #47 (consumer-hook enumeration — same "enumerate every dependent before changing an invariant" shape, but for reacting code vs stale data), #35c (JSONB single-source normalizer/stamp — read-side dual of this write-side rule), #48 (cross-stack alignment test — the in-repo source-of-truth-agreement analog), #21 (companion-file sync), #9 (frontend Record maps derived from backend enums), #8 + #26 (rebuild stale derived container images — the same drift at the image layer), #46 (the source-sanity floor's meta-canary). Promotable to Rule-of-Three when a third derived-representation drift class surfaces. Promotion date: 2026-06-05.
0 commit comments