No open questions and no blocking questions; implementation binding present, verifier binding present, and expected-outcome oracle present.
A validator that stops firing reports nothing, and an empty report looks like a clean graph unless a test asserts the refusal. A validator that refuses every input is just as useless. Refusing and accepting inputs, one probe world per direction, tell the two failures apart, so the check families are themselves checked. No validator checks this discipline, because the Protocol's checks concern conformance and honesty, never the delivery process.
An audit keeps the discipline whole. Scattered tests can cover every check today and miss the next one, so the audit holds one probe pair per finding id in one table and fails when the table and the engine's registries disagree. Extraction refusals count: they carry the conformance family, refuse carriers in the same validation run, and go silent in the same way. The accepting probe is a near miss rather than an empty input, because an empty input passes a validator that refuses too much.
Intent
outcome
Keep a validator that has silently stopped firing from reading as a clean build.
Rule
The world runs the audit function on the shipped probe table, on that table without the pair for the named check, or on that table with the named check's pair written twice, over the shipped registries and the scanned source. A check that behaves silently has its findings removed from every probe's run; one that behaves overeagerly has a finding added to every probe's run. A source that also writes an id adds it to the scanned source ids, and nothing adds none. The named ids are joined by a comma and a space, or nothing when the audit names none.
The discipline is evidence over the two check families, never a check of its own; no validator checks whether another validator carries tests, and no report, graph fact or delivery fact records the audit.
The audit covers every finding id a validation run can report: each graph validator's and each extraction finding's, the Markdown and Gherkin carriers' included. Contract generation and import report outside a validation run and stay outside the audit.
The audit holds one probe pair per finding id: a refusing probe the id must report, and an accepting probe, a near miss that differs from the refusing probe only in the construct the check reads, that the id must leave unreported.
The audit's table and the engine's registries agree exactly: a registered id without a pair, an id paired twice, a pair for an id no registry lists, a finding id written in the engine's source outside every registry, and a finding id a probe run reports outside every registry each fail the audit.
The audit reads the engine's source as code, so a comment never counts and every quote form does, and it fails on a finding id it cannot read whole, such as an id prefix joined to a value at run time.
The audit runs every probe through the entry a validation run uses, graph validation for a graph probe and extraction for a carrier probe, and fails for each id its refusing probe does not report and each id its accepting probe reports; it reads the finding id alone, never the message.
The audit is a test in the repository's own suite, so the gate runs it on every change. It fails by naming each id at fault, writes no tracked file and no durable result, and may create and remove a temporary extraction root for a carrier probe.
Given the audit reads {table: "the shipped table with one pair twice"}
Given the check {findingId: "conformance/orphans"} behaves {behavior: "as shipped"}
Given the engine source also writes {extraSourceId: "nothing"}
When the audit runs
Then the audit {verdict: "fails"}
Then the audit names {named: "conformance/orphans"} as {list: "duplicatePairs"}
Given
the audit reads {table: "the shipped table with one pair twice"}
the check {findingId: "conformance/orphans"} behaves {behavior: "as shipped"}
the engine source also writes {extraSourceId: "nothing"}
When
the audit runs
Then
the audit {verdict: "fails"}
the audit names {named: "conformance/orphans"} as {list: "duplicatePairs"}
Given the audit reads {table: "the shipped probe table"}
Given the check {findingId: "conformance/orphans"} behaves {behavior: "overeagerly"}
Given the engine source also writes {extraSourceId: "nothing"}
When the audit runs
Then the audit {verdict: "fails"}
Then the audit names {named: "conformance/orphans"} as {list: "overeager"}
Given
the audit reads {table: "the shipped probe table"}
the check {findingId: "conformance/orphans"} behaves {behavior: "overeagerly"}
the engine source also writes {extraSourceId: "nothing"}
When
the audit runs
Then
the audit {verdict: "fails"}
the audit names {named: "conformance/orphans"} as {list: "overeager"}
Given the audit reads {table: "the shipped probe table"}
Given the check {findingId: "conformance/orphans"} behaves {behavior: "as shipped"}
Given the engine source also writes {extraSourceId: "nothing"}
When the audit runs
Then the audit {verdict: "passes"}
Then the audit names {named: "nothing"} as {list: "none"}
Given
the audit reads {table: "the shipped probe table"}
the check {findingId: "conformance/orphans"} behaves {behavior: "as shipped"}
the engine source also writes {extraSourceId: "nothing"}
When
the audit runs
Then
the audit {verdict: "passes"}
the audit names {named: "nothing"} as {list: "none"}
Given the audit reads {table: "the shipped probe table"}
Given the check {findingId: "conformance/orphans"} behaves {behavior: "silently"}
Given the engine source also writes {extraSourceId: "nothing"}
When the audit runs
Then the audit {verdict: "fails"}
Then the audit names {named: "conformance/orphans"} as {list: "silent"}
Given
the audit reads {table: "the shipped probe table"}
the check {findingId: "conformance/orphans"} behaves {behavior: "silently"}
the engine source also writes {extraSourceId: "nothing"}
When
the audit runs
Then
the audit {verdict: "fails"}
the audit names {named: "conformance/orphans"} as {list: "silent"}
Given the audit reads {table: "the shipped table without one pair"}
Given the check {findingId: "conformance/orphans"} behaves {behavior: "as shipped"}
Given the engine source also writes {extraSourceId: "nothing"}
When the audit runs
Then the audit {verdict: "fails"}
Then the audit names {named: "conformance/orphans"} as {list: "unpaired"}
Given
the audit reads {table: "the shipped table without one pair"}
the check {findingId: "conformance/orphans"} behaves {behavior: "as shipped"}
the engine source also writes {extraSourceId: "nothing"}
When
the audit runs
Then
the audit {verdict: "fails"}
the audit names {named: "conformance/orphans"} as {list: "unpaired"}
Given the audit reads {table: "the shipped probe table"}
Given the check {findingId: "conformance/orphans"} behaves {behavior: "as shipped"}
Given the engine source also writes {extraSourceId: "conformance/unlisted-check"}
When the audit runs
Then the audit {verdict: "fails"}
Then the audit names {named: "conformance/unlisted-check"} as {list: "unregistered"}
Given
the audit reads {table: "the shipped probe table"}
the check {findingId: "conformance/orphans"} behaves {behavior: "as shipped"}
the engine source also writes {extraSourceId: "conformance/unlisted-check"}
When
the audit runs
Then
the audit {verdict: "fails"}
the audit names {named: "conformance/unlisted-check"} as {list: "unregistered"}
Given the audit reads {table:"the shipped probe table"|"the shipped table without one pair"|"the shipped table with one pair twice"}
Given the check {findingId:string} behaves {behavior:"as shipped"|"silently"|"overeagerly"}
Given the engine source also writes {extraSourceId:string}
When the audit runs
Then the audit {verdict:"passes"|"fails"}
Then the audit names {named:string} as {list:"none"|"unpaired"|"duplicatePairs"|"unregistered"|"silent"|"overeager"}
graphValidatorIds and extractFindingIds; the Markdown extractor's extract/invalid-markdown-structure, extract/unrecognized-heading and extract/invalid-frontmatter join extractFindingIds, so one registry lists every extraction finding id.
{ id: string; refusing: Probe; accepting: Probe }, with type Probe = { graph: GraphSchema } | { carriers: Readonly<Record<string, string>> }, a graph for a graph validator and root-relative carrier files for an extraction finding.
auditValidatorEvidence(table: readonly ProbeEntry[], run: (probe: Probe) => readonly Finding[], registered: readonly string[], source: SourceScan): AuditAnswer, where run is graph validation or extraction as the probe needs, so a world can wrap it to silence one id or report it everywhere; every finding id any probe run reports outside registered is unregistered.
{ unpaired: string[]; duplicatePairs: string[]; strayPairs: string[]; unregistered: string[]; unresolved: string[]; silent: string[]; overeager: string[] }, each sorted in code-unit order and each id listed once; the audit passes when all seven are empty and otherwise fails with the non-empty lists in its message.
scanFindingIds(srcRoot: string): SourceScan, with type SourceScan = { ids: string[]; unresolved: string[] }, reads every .ts file under src/ with the TypeScript scanner, so comments are skipped. A string literal or a template literal without substitutions whose whole text matches ^(conformance|honesty|extract)/[a-z][a-z-]*$ is an id, and one outside every registry is unregistered. A literal whose text matches ^(conformance|honesty|extract)/[a-z-]*$ but is no whole id, or a template literal whose text before its first substitution matches it, is unresolved, named <file>:<line>. The gate suite scans the real source tree.
spec:validation.validator-self-testing.shipped-checks-paired · Every shipped check reports its refusing probe and leaves its near miss alone · declared · example enabled · specs/validation/validator-self-testing.shipped-checks-paired.sdp.md
table · "the shipped probe table" | "the shipped table without one pair" | "the shipped table with one pair twice" · declared by the audit reads {table}
findingId · string · declared by the check {findingId} behaves {behavior}
behavior · "as shipped" | "silently" | "overeagerly" · declared by the check {findingId} behaves {behavior}
extraSourceId · string · declared by the engine source also writes {extraSourceId}
the audit reads {table:"the shipped probe table"|"the shipped table without one pair"|"the shipped table with one pair twice"}
the check {findingId:string} behaves {behavior:"as shipped"|"silently"|"overeagerly"}
the engine source also writes {extraSourceId:string}
When
the audit runs
Then
the audit {verdict:"passes"|"fails"}
the audit names {named:string} as {list:"none"|"unpaired"|"duplicatePairs"|"unregistered"|"silent"|"overeager"}
Composing needs the script.
Design view
Requirement drawing
Requirement drawing for spec:validation.validator-self-testingThe diagram as text
spec:validation.validator-self-testing: Every validator ships evidence in both directions · declared Spec
spec:validation.validator-self-testing.duplicate-pair-named: A check paired twice is named · declared Spec
spec:validation.validator-self-testing.overeager-check-named: A check that reports its near miss is named overeager · declared Spec
spec:validation.validator-self-testing.shipped-checks-paired: Every shipped check reports its refusing probe and leaves its near miss alone · declared Spec
spec:validation.validator-self-testing.silent-check-named: A check that stops reporting is named silent · declared Spec
spec:validation.validator-self-testing.unpaired-check-named: A registered check without a probe pair is named unpaired · declared Spec
spec:validation.validator-self-testing.unregistered-id-named: A finding id the source writes outside every registry is named · declared Spec
spec:validation.two-check-families: Validation separates well-formedness from non-pretending · declared Spec
impl:protocol.validator-probe-table: declares the refusing and accepting probes for every registered finding id · anchored code · test/helpers/validator-probes.ts:372
impl:protocol.validator-self-testing: audits the finding registries against source literals and paired probes · anchored code · test/helpers/validator-audit.ts:86
Preferred syntax: requirementDiagram. Chosen syntax: flowchart TB because models, folds require exact labels unavailable in requirement syntax.
Decisions
No decision record named.
Runtime
impl:protocol.validator-probe-table · declares the refusing and accepting probes for every registered finding id · test/helpers/validator-probes.ts:372
Uses
None.
impl:protocol.validator-self-testing · audits the finding registries against source literals and paired probes · test/helpers/validator-audit.ts:86
Uses
None.
Runtime observation: not tracked.
Evidence
Runtime observation: not tracked.
Build attestations: not tracked.
Deployments: not tracked.
Bills of materials: not tracked.
Impact
Relations of spec:validation.validator-self-testingThe diagram as text
spec:validation.two-check-families: Validation separates well-formedness from non-pretending
spec:validation.validator-self-testing: Every validator ships evidence in both directions
spec:validation.validator-self-testing.duplicate-pair-named: A check paired twice is named
spec:validation.validator-self-testing.overeager-check-named: A check that reports its near miss is named overeager
spec:validation.validator-self-testing.shipped-checks-paired: Every shipped check reports its refusing probe and leaves its near miss alone
spec:validation.validator-self-testing.silent-check-named: A check that stops reporting is named silent
spec:validation.validator-self-testing.unpaired-check-named: A registered check without a probe pair is named unpaired
spec:validation.validator-self-testing.unregistered-id-named: A finding id the source writes outside every registry is named
impl:protocol.validator-probe-table · declares the refusing and accepting probes for every registered finding id · test/helpers/validator-probes.ts:372 · role contract
impl:protocol.validator-self-testing · audits the finding registries against source literals and paired probes · test/helpers/validator-audit.ts:86 · role validator
spec:validation.validator-self-testing.shipped-checks-paired · Every shipped check reports its refusing probe and leaves its near miss alone · declared · specs/validation/validator-self-testing.shipped-checks-paired.sdp.md · example enabled