skill-vetting hardening — failure archaeology
Dead ends from the PR #83 campaign (branch workstream-b-skill-vetting-2026-07-25,
merged 7cd2af6 2026-07-26). Most were caught PRE-MERGE by cross-family review,
so the residue is in commit history and in-code comments, not reverts. Read the
disposition tag first — it says what kind of corpse this is.
What to DO at any tripwire below (the Done for every entry). When a tripwire
fires: (1) STOP the proposed mechanism/idea; (2) read the entry's disposition tag,
standing rule, and residue; (3) load the owning skill the entry names, or — most
entries name none — the skill that owns the affected surface (a live invariant →
skill-vetting-security-invariants; the harness/evidence →
mutation-matrix-evidence-discipline; neither → follow the fallback); (4) either
satisfy that skill's Done-check for the real change, or record the item unresolved
and escalate. Done: no dead mechanism survives in the plan or diff, AND either a
named owning-rule check passes or the item is recorded unresolved with its
disposition. An entry with no explicit Residue line has none tracked — treat
that absence as "no residue recorded", not "nothing to check".
Owner map (each dead end → the installed rule that owns its current surface):
quoting → skill-vetting-security-invariants INV-7; normpath & dot-path → INV-4;
transient/steady-state ordering → INV-3 (partial/skip_baseline); unreachable/
equivalent → mutation-matrix-evidence-discipline R3; evidence-artifacts
(tee/record) → R4; CI ordering → the harness suites (mutation-matrix) +
.github/workflows/checks.yml; doc-drift → R7/R8 or operational-rigor §5
twin-sweep. No installed owner (follow the fallback — record unresolved + escalate):
the config-dir scratch-write hygiene (its inspect-only procedure is UNCERTAINTY #9,
review-only — inline it if you act) and the deliberately-not-done D1–D5 designs.
The one meta-signal above all — recurring-trap
A fix invented as a NEW MECHANISM at fold time, under review pressure, is the
defect. Of round-6's twelve fixes, 3 were defective and 6 more incomplete; the
3 defective ones shared exactly one property — each was a new mechanism invented
while folding, not a mechanical correction
(reviews/2026-07-25-skill-vetting-round8-design.md, the round-5/6/7 table).
Standing rule: when a fix requires inventing a mechanism (a new lock scheme, a
shape heuristic, a path guard), do not fold it under pressure — design it, attack
the design first, THEN implement. Three-defects-one-mechanism (operational-rigor
§5) is the signal: the mechanism, not the patch list, is wrong.
- Tripwire: any fold that adds a novel algorithm rather than correcting an
existing one.
Dead ends
dead + recurring-trap — quoting to stop shell injection (commit 550689d)
- Tried: double-quoting the candidate-name placeholders in SKILL.md §3;
commit
550689d message CLAIMED the RCE fixed.
- Why it died: double quotes do not stop
$(...), backticks, ${…}, or an
embedded "; the RCE stayed live. The author's own verification used a
candidate named with only ; — the one class quotes DO neutralize — so the
test was chosen to agree. Five independent round-7 lenses reproduced the bypass
(b427bf8).
- Standing rule: quoting/escaping is the wrong abstraction for
attacker-controlled shell input; its failure mode is invisible, so it is not a
control. Verify an injection fix with
$()/backtick samples, never a ;-only
one. The real fix is structural (bytes never reach the shell as syntax).
- Residue:
550689d kept in history, corrected in the next commit
(b427bf8) by owner decision — not rewritten. Residue, not in-progress work.
- Tripwire: "just add quotes / escape the name."
dead — os.path.normpath for symlink/trailing-slash laundering (round 5)
- Tried:
normpath to canonicalize a trailing-slash symlink laundering case.
- Why it died:
normpath does textual .. folding (wrong across symlinks)
AND normpath(b"") == b".", so an empty/unset path (e.g. $SKILL_DIR unset)
became a clean digest of the CWD with exit 0 — a fail-closed→fail-open
regression, straight onto §3's SAFE-TO-PROPOSE green light.
- Standing rule: never borrow a general path util for a security path — write
the minimal function that does only what is needed (
_strip_trailing). Empty and
unset paths fail CLOSED; dot-resolution is gated on ARRIVAL EVIDENCE, not on the
.. spelling (a .. that resolves to the current non-symlink $PWD passes —
see skill-vetting-security-invariants INV-4; "just reject .." is the refuted
narrow fix in the next entry).
- Tripwire: "normpath will clean this path up."
recurring-trap — dot-path addressing, mis-fixed one spelling at a time
- Tried: guard
.. laundering by rejecting the reported spelling; reviewers
proposed "unconditionally reject ..".
- Why it died: each narrow fix left a sibling spelling open —
<link>/sub/../. (the /. stripped back to ..), unset $PWD laundering with
bare ., $PWD≠cwd. "Reject .." closed only ~1/3.
- Standing rule: a guard that compares two derived values must be tested
against EVERY input class that makes the compare vacuous; converge on "evidence
of arrival" (
$PWD is the candidate, non-symlink), not on enumerating bad
spellings. _resolve_dot_base is the converged form.
- Tripwire: "just reject the
.. case the reviewer found."
recurring-trap — transient-vs-steady-state classification, mis-fixed 3×
- Tried (three axes): round-6 "anomalous vs clean" → pass-8 "transient vs
steady-state" → pass-9 "will THIS run's baseline advance consume it".
- Why the first two died: a
partial candidate is "new" every run (never
consumed), so classifying it transient let it re-claim the front display slots
forever and starve a genuinely new skill.
- Standing rule: display/notification priority keys on "is this event consumed
this run" (
skip_baseline), not on how it looks; a one-shot signal missed is
lost forever, a steady-state one only delayed. When a subtle classifier is
"not wrong, just not narrow enough" twice, suspect the third fix too.
- Tripwire: editing
delta_lines/anomaly_lines ordering or MAX_LISTED.
dead — "this branch is unreachable, no test needed"
- Tried: marking the
_resolve_dot_base except OSError branch an equivalent
mutant on call-graph reasoning.
- Why it died: deleting the working directory makes
os.getcwd() raise
FileNotFoundError (an OSError) — reachable — and the mutant failed OPEN.
- Standing rule: "unreachable/equivalent" is empirical; prove it with the
input that would reach it before excluding it from testing.
- Tripwire: "mark it equivalent / it can't be reached."
dead — evidence artifacts that lie (tee exit code, commit-named records)
- Tried:
echo "exit=$?" | tee to capture a subprocess exit code; per-mutant
records named only by commit hash.
- Why they died: the pipeline's status is
tee's, not the tool's (forced a
child exit 7, wrapper still reported 0); a later partial run on the same commit
silently overwrote a 55-row record down to 1 — after the closure report cited
its hash.
- Standing rule: capture exit status without a pipe (
status=$?; … ; exit "$status"); name evidence by RUN id + exclusive-create. (Full set:
mutation-matrix-evidence-discipline R4.)
- Tripwire: "the sidecar/record proves it."
recurring-trap — scratch writes into the real config dir (twice)
- Tried: ad-hoc verification commands without setting
CLAUDE_CONFIG_DIR.
- Why it recurred: the isolation var was inherited-or-forgotten; the SECOND
occurrence was a real product bug — the
_log fallback hard-coded ~/.claude
instead of honoring CLAUDE_CONFIG_DIR — and was caught by a third-party review
lens finding stray files in the real home dir.
- Standing rule: every test/verify subprocess touching config/state paths sets
CLAUDE_CONFIG_DIR explicitly; audit the real dir after any manual repro. The
_log bug is fixed + regression-tested.
- Residue: two stray files were left in the real
~/.claude/skill-vetting/
during the session and moved out; the session reported the component was not
installed there (so they would be inert), but that cannot be confirmed from the
repo — a maintainer inspects the real dir on the session machine (UNCERTAINTY #9
gives the inspect-only, do-not-delete procedure). Operator hygiene,
history-only.
- Tripwire: any repro command writing under
~/.claude.
mooted — CI ordering hid the real Linux failure
- Tried: running
hooks/test-*.sh in glob (alphabetical) order under set -e.
- Why it died:
test-mutation_matrix.sh sorts BEFORE the two product suites
its own pristine control depends on, so on Linux the first failure surfaced in
the harness's control, set -e aborted, and the product suites never ran
standalone — their real failure never appeared in the log.
- Standing rule: a suite whose control depends on other suites runs LAST; a
diagnostic must preserve the underlying suite's output. Made moot by reordering
the CI job (
.github/workflows/checks.yml runs the matrix suite last).
- Tripwire: "just run all the test scripts in a loop."
recurring-trap — one claim restated in many files drifts (~14×)
- Tried: correcting an overclaim by fixing the file the review pointed at.
- Why it recurred: the same claim lived in code comments, docstrings, README
×2, the threat model, and test-failure strings; ~14 passes each fixed the
nearest copy and left a farther, more-authoritative one stale — twice a commit
message claimed "all N fixed" when it wasn't.
- Standing rule: correct an overclaim by searching the WHOLE repo for the
concept (not the literal string — paraphrases evade grep), fixing every
restatement, and verifying zero residue before claiming "fixed everywhere."
(
test-and-doc-consistency if that skill is present; else operational-rigor §5
twin-sweep.)
- Tripwire: "fixed the doc the reviewer flagged."
Deliberately NOT done (do not "helpfully" finish these)
The round-8 design reviews/2026-07-25-skill-vetting-round8-design.md (D1–D5) is
an unimplemented DESIGN. It exists to be attacked BEFORE it is written,
because the campaign proved that folding these under pressure produces defective
fixes. None shipped in PR #83.
- D1 self-minted selector addressing / D4 export-then-review (closes G3-SHELL).
❌ "I'll just add the
--select/export subcommands, the design is right
there." — containment-by-enumeration, the --dest attack surface, and
export/live digest coherence were ANSWERED by the round-8 first pass and folded
in (round8-design.md:462-483); the ACTUAL still-open questions
(:485-505) are flock portability on network mounts, false-BLOCKs from
candidates that legitimately ship a symlink, the reviewer-attention cost of
tokenized paths, unbounded growth of prior_adverse_digests, and whether the
collapsed one-line judged-unsafe summary is informative enough. Implement only
through a fresh design-then-attack gate that addresses those.
- D2
fcntl.flock (I11 serialization). ❌ "swap the hand-rolled lock for
flock, done." — the design lists five things flock still gets wrong (never
unlink on release, one lock path for hook+record, hold scope, network-mount
no-op, merge-correctness). A naive swap reopens dual-holders.
- D3 names-out-of-the-advisory (G3 prose injection). ❌ "add a length/
separator cap." — measured net-negative and REVERTED: it blocked legitimate
names while admitting CamelCase imperatives. A shape heuristic cannot separate
an identifier from compact natural language (3 lenses converged).
- D5 judged-unsafe state machine (adverse verdict stays loud). ❌ "make BLOCK
re-advise every session." — the design shows the naive form is a fresh budget
poisoner and is rename-erasable by ADV-1; it needs content-keyed stickiness,
slot reservation + collapse, and a clearing path.
Rejected options (do not refight)
- Subprocess separation of hook↔primitive — no isolation gain at equal
privilege; adds the argv/JSON encoding surface I1 exists to kill.
- No baseline / advise everything every session — permanent alarm noise trains
users to ignore the tripwire (round-1 cry-wolf, "SV-8"); owner chose
silent-when-clean.
- Baseline advances only on recorded vetting verdicts (round-2 R2-08 strong
form) — converts an advisory tripwire into an enforcement loop, nags first-party
authors, no integrity gain vs ADV-2. Its intent is honored non-naggingly by the
status/record lifecycle (untested — reconsider only with new evidence, not
a re-proposal).
When NOT to use
Current shipped invariants → skill-vetting-security-invariants. Harness/evidence
mechanics → mutation-matrix-evidence-discipline. Running the review campaign →
security-hardening-review-ops.
Re-verify (HEAD = 79ca49c)
git show 550689d --stat && git show b427bf8 --stat # the false-claim + its correction, both in history
grep -rn "NOT MET\|STILL_OPEN\|D1\|D2\|D3\|D4\|D5" reviews/2026-07-25-skill-vetting-*.md
If D1–D5 have since been implemented, the "deliberately not done" section is
stale — move each landed item to the invariants skill and re-verify its tests.
1---2name: skill-vetting-hardening-archaeology3description: Load before re-attempting any skill-vetting fix or design, or when reaching for a buried idea — "just add quotes / escape the name", "normpath will clean this path up", "just reject the .. case the reviewer found", "mark it equivalent / it can't be reached", "the sidecar/record proves it", "the commit message says it's fixed", "just run all the test scripts in a loop", "fixed the doc the reviewer flagged", a repro command writing under ~/.claude, editing delta_lines/anomaly_lines ordering, a fold that adds a novel algorithm, or "let me finish the D1–D5 design". Do NOT load to learn the current invariants (skill-vetting-security-invariants) or harness rules (mutation-matrix-evidence-discipline).4---56# skill-vetting hardening — failure archaeology78Dead ends from the PR #83 campaign (branch `workstream-b-skill-vetting-2026-07-25`,9merged `7cd2af6` 2026-07-26). Most were caught PRE-MERGE by cross-family review,10so the residue is in commit history and in-code comments, not `revert`s. Read the11disposition tag first — it says what kind of corpse this is.1213**What to DO at any tripwire below (the Done for every entry).** When a tripwire14fires: (1) STOP the proposed mechanism/idea; (2) read the entry's disposition tag,15standing rule, and residue; (3) load the owning skill the entry names, or — most16entries name none — the skill that owns the affected surface (a live invariant →17`skill-vetting-security-invariants`; the harness/evidence →18`mutation-matrix-evidence-discipline`; neither → follow the fallback); (4) either19satisfy that skill's Done-check for the real change, or record the item unresolved20and escalate. **Done:** no dead mechanism survives in the plan or diff, AND either a21named owning-rule check passes or the item is recorded unresolved with its22disposition. An entry with no explicit **Residue** line has none tracked — treat23that absence as "no residue recorded", not "nothing to check".2425**Owner map (each dead end → the installed rule that owns its current surface):**26quoting → `skill-vetting-security-invariants` INV-7; normpath & dot-path → INV-4;27transient/steady-state ordering → INV-3 (`partial`/`skip_baseline`); unreachable/28equivalent → `mutation-matrix-evidence-discipline` R3; evidence-artifacts29(tee/record) → R4; CI ordering → the harness suites (mutation-matrix) +30`.github/workflows/checks.yml`; doc-drift → R7/R8 or operational-rigor §531twin-sweep. No installed owner (follow the fallback — record unresolved + escalate):32the config-dir scratch-write hygiene (its inspect-only procedure is UNCERTAINTY #9,33review-only — inline it if you act) and the deliberately-not-done D1–D5 designs.3435## The one meta-signal above all — `recurring-trap`3637**A fix invented as a NEW MECHANISM at fold time, under review pressure, is the38defect.** Of round-6's twelve fixes, 3 were defective and 6 more incomplete; the393 defective ones shared exactly one property — each was a new mechanism invented40while folding, not a mechanical correction41(`reviews/2026-07-25-skill-vetting-round8-design.md`, the round-5/6/7 table).42**Standing rule:** when a fix requires inventing a mechanism (a new lock scheme, a43shape heuristic, a path guard), do not fold it under pressure — design it, attack44the design first, THEN implement. Three-defects-one-mechanism (operational-rigor45§5) is the signal: the mechanism, not the patch list, is wrong.46- **Tripwire:** any fold that adds a novel algorithm rather than correcting an47 existing one.4849## Dead ends5051### `dead` + `recurring-trap` — quoting to stop shell injection (commit 550689d)52- **Tried:** double-quoting the candidate-name placeholders in SKILL.md §3;53 commit `550689d` message CLAIMED the RCE fixed.54- **Why it died:** double quotes do not stop `$(...)`, backticks, `${…}`, or an55 embedded `"`; the RCE stayed live. The author's own verification used a56 candidate named with only `;` — the one class quotes DO neutralize — so the57 test was chosen to agree. Five independent round-7 lenses reproduced the bypass58 (`b427bf8`).59- **Standing rule:** quoting/escaping is the wrong abstraction for60 attacker-controlled shell input; its failure mode is invisible, so it is not a61 control. Verify an injection fix with `$()`/backtick samples, never a `;`-only62 one. The real fix is structural (bytes never reach the shell as syntax).63- **Residue:** `550689d` kept in history, corrected in the next commit64 (`b427bf8`) by owner decision — not rewritten. **Residue, not in-progress work.**65- **Tripwire:** "just add quotes / escape the name."6667### `dead` — `os.path.normpath` for symlink/trailing-slash laundering (round 5)68- **Tried:** `normpath` to canonicalize a trailing-slash symlink laundering case.69- **Why it died:** `normpath` does textual `..` folding (wrong across symlinks)70 AND `normpath(b"") == b"."`, so an empty/unset path (e.g. `$SKILL_DIR` unset)71 became a clean digest of the CWD with exit 0 — a fail-closed→fail-open72 regression, straight onto §3's SAFE-TO-PROPOSE green light.73- **Standing rule:** never borrow a general path util for a security path — write74 the minimal function that does only what is needed (`_strip_trailing`). Empty and75 unset paths fail CLOSED; dot-resolution is gated on ARRIVAL EVIDENCE, not on the76 `..` spelling (a `..` that resolves to the current non-symlink `$PWD` passes —77 see `skill-vetting-security-invariants` INV-4; "just reject `..`" is the refuted78 narrow fix in the next entry).79- **Tripwire:** "normpath will clean this path up."8081### `recurring-trap` — dot-path addressing, mis-fixed one spelling at a time82- **Tried:** guard `..` laundering by rejecting the reported spelling; reviewers83 proposed "unconditionally reject `..`".84- **Why it died:** each narrow fix left a sibling spelling open —85 `<link>/sub/../.` (the `/.` stripped back to `..`), unset `$PWD` laundering with86 bare `.`, `$PWD`≠cwd. "Reject `..`" closed only ~1/3.87- **Standing rule:** a guard that compares two derived values must be tested88 against EVERY input class that makes the compare vacuous; converge on "evidence89 of arrival" (`$PWD` is the candidate, non-symlink), not on enumerating bad90 spellings. `_resolve_dot_base` is the converged form.91- **Tripwire:** "just reject the `..` case the reviewer found."9293### `recurring-trap` — transient-vs-steady-state classification, mis-fixed 3×94- **Tried (three axes):** round-6 "anomalous vs clean" → pass-8 "transient vs95 steady-state" → pass-9 "will THIS run's baseline advance consume it".96- **Why the first two died:** a `partial` candidate is "new" every run (never97 consumed), so classifying it transient let it re-claim the front display slots98 forever and starve a genuinely new skill.99- **Standing rule:** display/notification priority keys on "is this event consumed100 this run" (`skip_baseline`), not on how it looks; a one-shot signal missed is101 lost forever, a steady-state one only delayed. When a subtle classifier is102 "not wrong, just not narrow enough" twice, suspect the third fix too.103- **Tripwire:** editing `delta_lines`/`anomaly_lines` ordering or `MAX_LISTED`.104105### `dead` — "this branch is unreachable, no test needed"106- **Tried:** marking the `_resolve_dot_base` `except OSError` branch an equivalent107 mutant on call-graph reasoning.108- **Why it died:** deleting the working directory makes `os.getcwd()` raise109 `FileNotFoundError` (an `OSError`) — reachable — and the mutant failed OPEN.110- **Standing rule:** "unreachable/equivalent" is empirical; prove it with the111 input that would reach it before excluding it from testing.112- **Tripwire:** "mark it equivalent / it can't be reached."113114### `dead` — evidence artifacts that lie (tee exit code, commit-named records)115- **Tried:** `echo "exit=$?" | tee` to capture a subprocess exit code; per-mutant116 records named only by commit hash.117- **Why they died:** the pipeline's status is `tee`'s, not the tool's (forced a118 child exit 7, wrapper still reported 0); a later partial run on the same commit119 silently overwrote a 55-row record down to 1 — after the closure report cited120 its hash.121- **Standing rule:** capture exit status without a pipe (`status=$?; … ; exit122 "$status"`); name evidence by RUN id + exclusive-create. (Full set:123 `mutation-matrix-evidence-discipline` R4.)124- **Tripwire:** "the sidecar/record proves it."125126### `recurring-trap` — scratch writes into the real config dir (twice)127- **Tried:** ad-hoc verification commands without setting `CLAUDE_CONFIG_DIR`.128- **Why it recurred:** the isolation var was inherited-or-forgotten; the SECOND129 occurrence was a real product bug — the `_log` fallback hard-coded `~/.claude`130 instead of honoring `CLAUDE_CONFIG_DIR` — and was caught by a third-party review131 lens finding stray files in the real home dir.132- **Standing rule:** every test/verify subprocess touching config/state paths sets133 `CLAUDE_CONFIG_DIR` explicitly; audit the real dir after any manual repro. The134 `_log` bug is fixed + regression-tested.135- **Residue:** two stray files were left in the real `~/.claude/skill-vetting/`136 during the session and moved out; the session reported the component was not137 installed there (so they would be inert), but that cannot be confirmed from the138 repo — a maintainer inspects the real dir on the session machine (UNCERTAINTY #9139 gives the inspect-only, do-not-delete procedure). **Operator hygiene,140 history-only.**141- **Tripwire:** any repro command writing under `~/.claude`.142143### `mooted` — CI ordering hid the real Linux failure144- **Tried:** running `hooks/test-*.sh` in glob (alphabetical) order under `set -e`.145- **Why it died:** `test-mutation_matrix.sh` sorts BEFORE the two product suites146 its own pristine control depends on, so on Linux the first failure surfaced in147 the harness's control, `set -e` aborted, and the product suites never ran148 standalone — their real failure never appeared in the log.149- **Standing rule:** a suite whose control depends on other suites runs LAST; a150 diagnostic must preserve the underlying suite's output. Made moot by reordering151 the CI job (`.github/workflows/checks.yml` runs the matrix suite last).152- **Tripwire:** "just run all the test scripts in a loop."153154### `recurring-trap` — one claim restated in many files drifts (~14×)155- **Tried:** correcting an overclaim by fixing the file the review pointed at.156- **Why it recurred:** the same claim lived in code comments, docstrings, README157 ×2, the threat model, and test-failure strings; ~14 passes each fixed the158 nearest copy and left a farther, more-authoritative one stale — twice a commit159 message claimed "all N fixed" when it wasn't.160- **Standing rule:** correct an overclaim by searching the WHOLE repo for the161 concept (not the literal string — paraphrases evade grep), fixing every162 restatement, and verifying zero residue before claiming "fixed everywhere."163 (`test-and-doc-consistency` if that skill is present; else operational-rigor §5164 twin-sweep.)165- **Tripwire:** "fixed the doc the reviewer flagged."166167## Deliberately NOT done (do not "helpfully" finish these)168169The round-8 design `reviews/2026-07-25-skill-vetting-round8-design.md` (D1–D5) is170an **unimplemented DESIGN**. It exists to be attacked BEFORE it is written,171because the campaign proved that folding these under pressure produces defective172fixes. None shipped in PR #83.173174- **D1 self-minted selector addressing / D4 export-then-review** (closes G3-SHELL).175 ❌ "I'll just add the `--select`/`export` subcommands, the design is right176 there." — containment-by-enumeration, the `--dest` attack surface, and177 export/live digest coherence were ANSWERED by the round-8 first pass and folded178 in (`round8-design.md:462-483`); the ACTUAL still-open questions179 (`:485-505`) are flock portability on network mounts, false-BLOCKs from180 candidates that legitimately ship a symlink, the reviewer-attention cost of181 tokenized paths, unbounded growth of `prior_adverse_digests`, and whether the182 collapsed one-line judged-unsafe summary is informative enough. Implement only183 through a fresh design-then-attack gate that addresses those.184- **D2 `fcntl.flock`** (I11 serialization). ❌ "swap the hand-rolled lock for185 flock, done." — the design lists five things flock still gets wrong (never186 unlink on release, one lock path for hook+`record`, hold scope, network-mount187 no-op, merge-correctness). A naive swap reopens dual-holders.188- **D3 names-out-of-the-advisory** (G3 prose injection). ❌ "add a length/189 separator cap." — measured net-negative and REVERTED: it blocked legitimate190 names while admitting CamelCase imperatives. A shape heuristic cannot separate191 an identifier from compact natural language (3 lenses converged).192- **D5 judged-unsafe state machine** (adverse verdict stays loud). ❌ "make BLOCK193 re-advise every session." — the design shows the naive form is a fresh budget194 poisoner and is rename-erasable by ADV-1; it needs content-keyed stickiness,195 slot reservation + collapse, and a clearing path.196197## Rejected options (do not refight)198199- **Subprocess separation of hook↔primitive** — no isolation gain at equal200 privilege; adds the argv/JSON encoding surface I1 exists to kill.201- **No baseline / advise everything every session** — permanent alarm noise trains202 users to ignore the tripwire (round-1 cry-wolf, "SV-8"); owner chose203 silent-when-clean.204- **Baseline advances only on recorded vetting verdicts** (round-2 R2-08 strong205 form) — converts an advisory tripwire into an enforcement loop, nags first-party206 authors, no integrity gain vs ADV-2. Its intent is honored non-naggingly by the207 `status`/`record` lifecycle (untested — reconsider only with new evidence, not208 a re-proposal).209210## When NOT to use211212Current shipped invariants → `skill-vetting-security-invariants`. Harness/evidence213mechanics → `mutation-matrix-evidence-discipline`. Running the review campaign →214`security-hardening-review-ops`.215216## Re-verify (HEAD = 79ca49c)217218```219git show 550689d --stat && git show b427bf8 --stat # the false-claim + its correction, both in history220grep -rn "NOT MET\|STILL_OPEN\|D1\|D2\|D3\|D4\|D5" reviews/2026-07-25-skill-vetting-*.md221```222If D1–D5 have since been implemented, the "deliberately not done" section is223stale — move each landed item to the invariants skill and re-verify its tests.