v1.21.1
[1.21.1] - 2026-08-05
The inert-control release — three days of "the rule was there, the probe wasn't."
An external audit spec (seven classes beyond our five) and two commissioned research
reports were taken in, and the recurring finding was the same each time: the library
stated the BUILD rule and had never written the AUDIT probe. It said "unit tests
touch no sockets" in three places and offered no way to find out that they do; it
governed the numbers a tool prints and not the words; it declared instruments to be
controls without ever turning that recursion on guards. The inert-control family is
now three files — rules/10 catalogs, rules/11 sweeps, rules/12 proves a control
works and distrusts whatever did the proving.
Front door checked: negative control · metamorphic · oracle problem · rules/12
Nothing here is measured; no lift is claimed for any of it. The AUDIT arm remains
at +0.00 across seven instruments, and none of this changes that.
Naming the prior art, and the four gaps two research reports found. Two
commissioned reports on inert controls were evaluated against the tree. They agree
on the headline — the missing layer is a control shown capable of failing — and
they are not of equal quality: one misquotes NIST SSDF PO.3.3, over-generalises the
formal-verification vacuity statistic from hardware to software, and sources
aviation self-test to Scribd uploads. Every claim that became library text was
checked against a primary source first, which is why four gaps landed out of
thirteen proposals. Full verdicts, both rejections, and the misquote are in
docs/ADOPTION-LOG.md (entry 2026-08-05).
Nothing here is measured; no lift is claimed for any of it.
Added
rules/12§3 — per-target kill verification. A guard protects a
population. Watching it reject one member proves the predicate can fire and
says nothing about the other 19; the real shape is a tripwire that fired for 2
of 20 targets and stayed green for 18, indistinguishable from full coverage on
any single-instance test. Inject the defect into each member. For a security
gate the bar is a 100% kill rate — unlike a code mutation score, where
surviving mutants are triaged and a number below 1.0 is normal.rules/12§2.4 — evidence the subject supplies about itself. An instrument
that accepts the evaluated party's own report is transcribing, not measuring.
The anchor is now measured: across 1.5M assets and 128K agents, "over 84% of
approved assets bypass quality checks using vacuous tests (e.g.console.log())"
(arXiv:2605.25815) — the platform accepted
each agent's own execution log as proof. Notably the other report asserts no
such corpus exists; this one found it.rules/11§2.6 — when you cannot state the right answer, state how it must
change. A metamorphic relation as a liveness oracle for a tool: commit a
fixture with N known items, assert the count is N, assert it rises when you add
one. The only diagnostic in that file that catches an analyser emitting an
empty-but-well-formed artifact while exiting 0.sota-devsecopsrules/05 §5.6 — what the standards ask for, and the one thing
none of them ask. SSDF PW.8.2/PO.3.3 and CRA Annex VII require a
record that the scan ran; OpenSSF Scorecard's SAST check detects tool
presence only, and its Dependency-Update-Tool check says outright it "does not
ensure that the tool is run". None require evidence the gate can fail — SLSA
will sign provenance for a scanner configured to scan zero files. So a passing
compliance check is evidence of process, not protection, and the negative
control has to be a house rule.
Changed
- The cross-discipline lineage is now named. The library had described proof
tests (IEC 61508's dangerous-undetected framing), positive controls, aviation
built-in test, poka-yoke, vacuous satisfaction (Ball & Kupferman, quoting
Beer et al. on hardware verification) and the test oracle problem (Barr,
Harman, McMinn, Shahbaz & Yoo, IEEE TSE 41(5):507–525, 2015) for months
without using any of those words —poka-yokeandoracle problemreturned
zero hits across all 41 skills. Named inrules/12intro + §3 and
rules/11§2.6.
Rejected (recorded so they are not re-litigated)
- A minimum mutation-score threshold in CI — contrary to
sota-testing
rules/07 §7.2 ("never set a global percentage target") and rules/06 §6.3
differential mutation, adopted 2026-07-24. The per-gate kill rate above is
compatible and was adopted; a global score is not. - GSN / assurance-case notation — a notation, not a mechanism, and its own
cited critique (arguments that "assume the conclusion") describes what
sota/rules/01§7 adversarial refutation already prevents.
Not verified, and therefore not asserted
IEC 61508 §3.8.5/§3.8.6 clause text is paywalled — the concept is named and no
clause number is quoted. The CRA Annex VII point number was not confirmed
(EUR-Lex returned only recitals); the sentence was verified against published
copies of the regulation, and rules/05 says so at the point of use.
The rules/12 split — the inert-control family gets a third file. The previous
entry below shipped rules/10 and rules/11 at 493 and 495 of the 500-line cap and
said plainly that the next addition needed a split rather than another squeeze. This
is that split, and the boundary is not arbitrary: rules/10 catalogs inert controls,
rules/11 sweeps for them at scale, and rules/12 is the third move — proving a
specific control works, then turning the same suspicion on everything that did the
proving. That layer was previously split across two files (a mutation procedure at
the end of one, an instrument section at the end of the other) and belonged together.
Added
sota-code-securityrules/12 — Verifying the Verifier (191 lines). Composed
fromrules/10§3 (the mutation probe for a security control) andrules/11§7
(your instrument is a control), plus the guard that is an instance of what it
guards promoted from a bullet to its own §3 with all three forms written out:
the predicate the defect satisfies ("auth=" in linepasses onauth=None), the
guard nested in another gate's success branch, and the denominator counting only
survivors. Its organising asymmetry: a broken feature produces a complaint, but a
broken verifier produces a green tick or a number, and both get believed.rules/11§7 "Then turn the lens around" — a short hand-off replacing the
moved section, stating the rule that motivates the file: a finding produced by an
unvalidated instrument is not yet a finding.
Changed
rules/10renumbered: §3 (vacuous tests) moved out, so §4 → §3 (degradation
helper) and §5 → §4 (evidence rules). All live cross-references repointed —
rules/11×4,sota-devsecopsrules/03, README,docs/CONVENTIONS-LEDGER.md,
evals/README.md×2, and a comment inscripts/check-invariants.sh. Historical
CHANGELOG and ADOPTION-LOG entries were deliberately not rewritten: they
record what shipped at the version they describe.### 7.1 Four failure modeslisted five bullets — count-rot introduced by the
previous entry when the guard bullet was added without updating the heading. Fixed
structurally rather than by editing the number: the guard is now its own section
and 7.1 (rules/12§2.1) is back to four.- The router's library map had never listed
rules/11.skills/sota/SKILL.md
stopped at "10 silent control failure"; it now lists 10, 11 and 12. Invariant 7
gates skills against the router, not rules files, so this drifted unnoticed —
andsota/SKILL.mdis itself at exactly 500 lines, so the entry was rewritten to
fit the same four lines rather than growing the file. rules/11§2.2 — the runners disagree, which is the point. Both verified by
running them:go test ./...over a package with no test files exits 0, while
pyteston the same empty scope exits 5 — as it does for a file with no test
functions and for a-kselector that deselects everything (pytest 9.1.1). One
fails closed, one fails green, so no folklore about "runners exit 0 when they find
nothing" tells you which you have. (The previous entry deliberately omitted the
pytest half as unverified; it is now measured.)- README file count 297 → 298 (invariant 6 again), and the "your own scorer"
class now points atrules/12.
Family headroom after the split
rules/10 468, rules/11 415, rules/12 191 — from 12 lines of combined headroom
to 426.
The audit half of a rule we already had. An external inert-control audit spec
(seven classes beyond our five) was evaluated against the tree class by class. Two
were already covered end to end and stay rejected; the rest split into a pattern
worth naming: we had stated the build rule and never written the probe. The
library said "unit tests touch no sockets" in three places and offered no way to
find out that they do; it governed the numbers a tool prints and not the words;
it declared instruments to be controls without ever turning that recursion on
guards. Full reasoning, including the five candidates rejected as already ours, is
in docs/ADOPTION-LOG.md (entry 2026-08-04).
Nothing here is measured; no lift is claimed for any of it.
Added
sota-code-securityrules/10 §2.10 — unearned claims are words, not just
numbers. The section governed literals in reporting output. It now also
governs the verbs:verified,confirmed,reachable from,tainted,
sanitized, and any severity or confidence set from a constant. The test is
"which line would have to succeed for this word to be true, and can I make that
line fail?" — with both traps stated, because keyword-hedging every message
saying "tainted" leaves the identical claim phrased "reachable from input", and
"TLS certificate not verified" is correct English describing the analysed code.sota-code-securityrules/10 §2.14 — a control parked in observe-only mode.
KyvernoAudit, PSAwarn, WAF detection-only,SCMP_ACT_LOG, CSP
report-only, DMARCp=none,--soft-fail. Each is correct as a rollout stage
and inert as a destination, and renders identically to an enforcing control on
every dashboard. Ships with an owner and an expiry, enforced somewhere that
fails — the disciplinesota-testingrules/07 §7.1 puts on a quarantined test.
The staged ladders already existed insota-devsecopsrules/07 and
sota-network-securityrules/06; the inert-control framing did not.sota-code-securityrules/11 §3.4 — contract drift by interaction. Neither
component is wrong: a producer change silently alters a layout its consumer
depends on, and both sides' isolation tests pass while the seam is broken. The
distinguishing feature is that no schema declares this seam, so nothing
exists for a registry or compat check to compare — every contract rule we own
presumes a declared contract. The high-yield trigger is a config-level backend
or frontend swap that changes the output layout as a side effect. Rule: run the
consumer on the producer's real output before merging.sota-code-securityrules/11 §7.1 — the guard that is an instance of what it
guards. §7 already said an instrument is a control; it never turned the
recursion on guards. Three forms: a coverage test whose scope is narrower than
the population and whose predicate the defect satisfies ("auth=" in line
passes onauth=None); a tripwire nested inside another gate's success branch;
a denominator counting only the items that survived earlier filtering. §2.2
catches an empty scope — this catches one merely wrong, and a predicate merely
weak.sota-code-securityrules/11 §7.2 — three rules for the auditor's own
instrument. Sample and read before you count (a regex over prose reported 50
unearned claims where reading found 8); a control validated on inputs that
cannot produce the failure proves nothing, which is the negative control's
twin; when a wrapper reports an empty reason, go one layer down.sota-code-securityrules/11 §6 — run every script before reading any of
them. A measurement tool nobody has executed this quarter is presumed dead
until it prints something; the ones needing credentials, a daemon, a rules
directory or a network fail in precisely the way a clean result looks, and one
environment change kills them all at once.sota-testingrules/02 §2.6 — prove hermeticity, don't assert it. Block
egress and run the suite; anything that fails was not the unit test it claimed
to be. What this catches is not a slow test but one passing for the wrong
reason, its usual mechanism being a config object the SUT never reads (it
resolves from the environment instead —rules/11§6.7). Plus: check each
surviving assertion against the test's own name.sota-testingrules/02 §2.7 — resource optimism added as its own smell, and
mystery guest restored to its standard external-resource sense. Ours had
narrowed a standard catalog term to a readability defect — record rot in our own
file, found while auditing for it.
Changed
rules/10§2.13 now cites the platform mechanic. Per
GitHub Docs,
a skipped job reports its status as Success and "will not prevent a pull
request from merging, even if it is a required check" — strictly worse than
§2.13's existing "all-skipped is not all-green". A required gate whoseif:
condition stops matching turns green, not pending.rules/11§2.2 gained the instance everyone meets.go test ./...over a
package with no test files prints? x [no test files]and exits 0
(verified this session). Gate on a floor for tests actually executed, never on
the runner's exit code — and check your runner rather than assuming, since
they differ.rules/11§3 is now "Four classes rules/10 does not cover", with the
matching count inrules/10's header pointer; bothSKILL.mdrouting rows and
the README's~62k linesfigure updated (invariant 6 caught that one).
Note for the next contributor
rules/10 and rules/11 now sit at 493 and 495 of the 500-line cap. That
pair is effectively full: the next addition to this family needs a rules/12
split, not another round of trimming.