The Veridict Standard — v1.0.0-draft

Date: 2026-09-10. Status: DRAFT for public review (Phase 3 deliverable, §8). Normative language: MUST / MUST NOT / SHOULD / MAY per RFC 2119. Reference implementation: this repository (veridict/ package) at the commit introducing this file. Where the standard and the reference implementation diverge, the divergence MUST be recorded in §14 (registry errata) until resolved.

Veridict answers one question with evidence that survives verification: what did this actor claim, what did independent producers find, and who decided the residual risk? Everything below exists to make that answer append-only, falsifiable, and honestly inconclusive when it must be.


1. Conformance targets

Level Who MUST satisfy
Core ledger, schema, ladder, policy, certificate, dossier §2–§5, §7–§13
Verifier built-in W1a/W1b producers §2–§5; W1a/W1b ceilings
Watcher third-party producers §2, §4, §6 (+ conformance kit §6.7)
Resolver human-facing decision surfaces (CLI/UX) §10, §12, §13

A conforming Core implementation MUST be verifiable offline: replay of a certificate MUST require only the ledger file, the certificate file, and Core-level code (§11.4).

2. Canonical data model

2.1 Canonical JSON. canonical_json(obj) = JSON with sorted keys, compact separators, ASCII escaping. All digests and signatures are computed over canonical form. Two implementations that disagree on canonical form cannot interoperate — this is the single most load-bearing rule.

2.2 Digests. payload_digest(payload) = sha256(canonical_json(payload)). Identifiers are sha256(<dotted preimage>)[:N] with N fixed per type (§4.2, §11.1).

2.3 Ledger. An append-only JSONL sequence of entries. Each entry carries at minimum: seq (0-based, contiguous), ts, entry_type, author (ActorRef: kind, identity, version), payload, payload_hash (= payload_digest), prev_hash, entry_hash. The preimage of entry_hash MUST bind all prior fields including prev_hash; the genesis entry's prev_hash MUST be a fixed sentinel. ts MUST be an ISO-8601 UTC string — floats MUST NOT occupy hashed positions, because canonical float formatting is language-fragile while string formatting is not; seq carries the ordering and ts carries provenance. An implementation MUST refuse to load a line that is not valid JSON (a truncated tail is a crash artifact, not a silent gap) — it MUST raise a chain error naming the line number (§7.3 m2).

2.4 Authoritative kinds. The entry-type registry (§14) is append-only. v1.0.0 registers: key.enrolled, task.started, actor.output, claim.registered, evidence.recorded, divergence.flagged, deliberation.rounded, calibration.updated, escalation.requested, dossier.issued, escalation.resolved, policy.fail_safe, policy.decision, watch.observed, policy.passed, checkpoint.anchored, certificate.issued, watcher.registered, watcher.revoked.

2.5 Policy-is-data. Every policy decision MUST embed the policy_digest of the declaration that produced it. Decisions are reproducible from (policy, claims, evidence) or they are not decisions.

3. Actors and authority

3.1 ActorRef kinds registered in v1.0.0: verifier, jury, watcher, adjudicator, divergence_detector, system, human, watcher_registry.

3.2 Authority disjointness (§5.4): a producer of one kind MUST NOT write another kind's entries. Watchers are authoritative over NOTHING — they return evidence items; the orchestrator records them. The human is authoritative ONLY over escalation.resolved (R3). Automated systems MUST NOT write escalation.resolved (§12.4).

3.3 Abstain ≠ refute. Absence of evidence is never evidence. A producer that errors, times out, or returns an out-of-contract output MUST be recorded as an abstention and MUST NOT produce a REFUTES stance.

4. Claims

4.1 Fields: claim_id, task_id, subject, predicate, scope, summary, derived_from, verifiability, falsifiable_by, critical_class.

4.2 verifiability ∈ {"MACHINE_CHECKABLE", "DOCTRINAL", "MIXED"}. claim_id = sha256(task_id | summary | verifiability)[:16] — the FULL claim body, never a truncated natural-language slug (a truncating id silently merges distinct claims and poisons every downstream join). An implementation MUST reject a duplicate claim_id within one extraction pass (fail-loud, not dedupe-silent).

4.3 A claim without a falsification channel MUST NOT be admitted as MACHINE_CHECKABLE.

5. Evidence and the tier lattice

5.1 Fields: evidence_id, claim_id, evidence_class ∈ {TEST_EXECUTION, REPRODUCIBLE_RUN, FORMAL_PROOF, STATIC_ANALYSIS, JURY_OPINION, WATCHER_REPORT}, tier ∈ {W1a, W1b, W2, W3}, producer, artifact_ref, reproducibility {deterministic, rerun_recipe}, stance ∈ {SUPPORTS, REFUTES}, confidence ∈ [0,1], rationale, schema_version.

5.2 Tier semantics: W1a = executed machine truth; W1b = deterministic static truth; W2 = heterogeneous-jury doctrine; W3 = unverified doctrine.

5.3 The five immutable tier rules (§4.3). A conforming implementation MUST enforce, and MUST NOT offer configuration to disable: 1. Strict ordering W1a > W1b > W2 > W3. 2. Doctrine (W2/W3) can never overturn W1a. 3. A W1b refutation of a claim supported by W1a opens a depth-budgeted meta-claim (coverage question), whose verdicts feed the policy engine and the certificate like any claim's. 4. A SPLIT is information: it is recorded (divergence.flagged) and never averaged away. 5. W3 alone can never yield VERIFIED; a MACHINE_CHECKABLE claim without W1 evidence is at best INCONCLUSIVE.

5.4 Divergence classification (normative). Over the W2/W3 evidence on a claim: if there is no doctrinal evidence, or no REFUTES, or no SUPPORTS, the divergence is UNANIMOUS. Otherwise let m = the minority stance count; if m / |doctrinal| ≤ divergence_tolerance the divergence is MAJORITY, else SPLIT. W1a/W1b conflicts are not divergence — the ladder (§7) handles them directly.

6. Watchers (third-party producers)

6.1 WatcherManifest (registration contract): watcher_id, name, version; producer {identity, maintainer} (anonymous watchers MUST be rejected); capabilities {evidence_classes, max_tier, subscribes_to}; resource_class {timeout_seconds, cost_budget, sandbox_level}; integrity {code_hash, update_policy} (the watcher's own code is pinned).

6.2 The W1a ceiling. max_tier ∈ {"W1b", "W2", "W3"} — a manifest claiming W1a MUST be rejected at construction. W1a is executed machine truth and is reserved to built-in verifiers. Session output tiers map 1:1 from the ceiling; no runtime path may surface W1a from a watcher.

6.3 Blind sessions. The doctrine function receives exactly (claim_summary, artifact_reference) — the artifact REFERENCE (path or digest), never other producers' outputs. The deliberation round (§9) is the only cross-visible exception, and it is jury-only.

6.4 Authority boundary. A watcher session returns evidence items; the orchestrator records them as evidence.recorded with author kind watcher. Abstention (error, timeout, None, out-of-contract stance) yields NO entry from that run — an abstaining watcher MUST NOT block, refute, or flag.

6.5 Resource contract. A declared timeout_seconds > 0 MUST be enforced (deadline → abstain). A hung watcher must never block the audit.

6.6 Registration and revocation. Registration is a watcher.registered entry whose payload binds {manifest, manifest_digest, signature{key_id, algorithm, sig_b64}}, the signature taken over the canonical manifest body with a key enrolled in the SAME ledger (offline parity). Latest registration wins; verification MUST re-check entry integrity, digest-vs-body, signature, and the manifest invariants.

Revocation is a signed watcher.revoked entry naming the watcher and the digest of the revoked manifest. Lifecycle resolution is latest-entry- wins: the most recent watcher.registered or watcher.revoked entry for a watcher determines whether it is active. Revocation is FORWARD-LOOKING: evidence recorded before the revocation stays in the ledger (append-only — no deletion), and certificates anchored before the revocation remain valid; a conforming orchestrator MUST consult the registry and MUST NOT route claims to a revoked watcher (a revoked watcher is not a participant — its silence records neither evidence nor abstention); a marketplace index MUST NOT list watchers whose lifecycle status is revoked.

6.7 Conformance kit (certification precondition). A watcher MUST pass the v1.0.0 kit before marketplace listing: C1 manifest invariants; C2 W1a ceiling; C3 blindness; C4/C5/C6 abstain on error/None/bad-stance; C7 confidence clamp; C8 evidence shape on a benign probe; C9 registry verification; C10 deadline enforcement. The kit probes the CONTRACT, not the watcher's opinions. The kit is a LOWER BOUND on trustworthiness, not a proof: it exercises a watcher's function a bounded number of times, so a stateful function can pass the kit and deviate in production — marketplace certification therefore additionally requires review of the manifest's code_hash. Similarly, deadline enforcement protects the audit, not the host: an expired watcher's thread runs until its function completes (host-side isolation is the control for a function that never returns).

7. Adjudication ladder (normative)

Walk top-down; the first matching rule decides. w1a/w1b = the W1a/W1b evidence sets; "all-SUPPORTS" is over every evidence item on the claim.

Meta-claims: the R1/R2 coverage questions are registered as new DOCTRINAL claims (predicate coverage-of:<parent predicate>), adjudicated by the jury within the remaining depth budget; their verdicts feed the policy engine and the certificate like any claim's.

A first-round split that went through deliberation keeps a visible risk note ("first-round split; post-deliberation consensus" / "… consensus not reached") on its adjudication.

8. Calibration (confidence only)

8.1 When the W1a majority stance on a claim contradicts a W2/W3 producer's stance, a calibration.updated entry records delta −0.1 for that producer identity. A producer agreeing with machine truth after a prior negative records +0.05 (rehabilitation). A tied W1a majority records nothing.

8.2 factor = clamp(1.0 + Σ deltas, 0.5, 1.0) (unknown identity ⇒ 1.0). The factor MUST be applied to W2/W3 confidence at record time. Calibration MUST NOT touch tier or stance — a discounted juror's REFUTES is worth exactly what it was, minus the trust. Meta-claims are excluded (their evidence is the same round).

9. Deliberation (the one blindness exception)

9.1 Gating: only after a first-round SPLIT, and only when policy deliberation_rounds ≥ 1. Default 1; 0 disables.

9.2 Mechanics: each juror receives the OTHERS' first-round opinions (identity-labeled: identity, family, stance, confidence; rationale NOT forwarded) and may revise via its hook; without a hook it keeps its first-round opinion. Revised items carry fresh evidence-id salts.

9.3 Supersession honesty: first-round items STAY in the ledger; deliberation.rounded records {claim_id, first_round, revised, consensus}; the divergence.flagged entry is never removed; adjudication uses the post-deliberation set.

9.4 Replay parity and its scope guard. Offline verification MUST adjudicate on the post-deliberation set: it MUST exclude exactly the first-round item ids named by deliberation.rounded entries at or below the certificate's anchored checkpoint (seq ≤ checkpoint_seq). Exclusions from entries above the anchor MUST be ignored — the signed anchor pins that prefix's chain hash, so pre-issuance deliberation is tamper-evident while a post-issuance fake deliberation entry must never be able to erase refuting evidence from a replay (v1.0.0 erratum D4: the unbounded form of this rule was exploitable and is forbidden).

9.5 Certificate fields are reconciled, never trusted (errata D17, D18, D19, D20). A certificate carries two KINDS of field that are not independent evidence, and a conforming verifier must handle both.

(a) Derived summaries — fields that FOLLOW from the claim verdicts: risk_level, score, divergence_summary (D17, D18). Recompute every one from the verdicts validated in this same pass and reject any divergence. The requirement is stated for the CLASS, not the field names: any future field that summarizes verdicts inherits it without further errata. Two fields that must agree, with no rule checking that they agree, is the same hazard D12 and D15 closed; the exposure is a framing attack (good work shown as risky, or a disagreement hidden as settled), not a pass-through, because the verdicts a summary rests on are themselves recomputed.

(b) Inputs to the verdicts — fields the replay USES rather than derives: policy_ref and its duplicate policy_mode (D19). These are strictly more dangerous than summaries, because forging one changes the verdicts rather than only their description. A conforming verifier MUST NOT replay under the certificate's own description of the policy: it MUST reconcile policy_ref against the policy the ledger records the run actually used (policy.decision carries policy_digest), MUST reject a digest mismatch, and MUST fail closed when the claimed policy_id has no recorded entry — an unrecorded policy is unfalsifiable and the first fix attempt skipped the check entirely, which is the same class as D17 but worse.

Scope note for (b), kept honest: this binds the certificate to the ledger's record of the policy, which is tamper-evident but only as meaningful as the policy the issuer actually ran. An issuer who runs a lenient policy and records it honestly gets a certificate that honestly reflects a lenient policy. The rule removes the ability to claim one policy and have run another; it does not make the claimed policy strict.

(c) The replay scope itself (D20). Reconciliation is only meaningful if the replay reads the same ledger the anchor pins. Every entry the replay trusts — claim.registered, evidence.recorded, the deliberation.rounded supersession set, the policy.decision record — MUST be restricted to the anchored prefix (seq <= checkpoint_seq). The certificate's signed anchor pins that prefix's chain_hash, so entries inside it are tamper-evident; entries appended after issuance are outside the pin and MUST NOT reach the replay. The failure mode is asymmetric in both directions: an appended entry can rescue an unattested certificate (D19) or flip a verdict to match a forged one (D20 — a W1a SUPPORTS item turns an honestly-INCONCLUSIVE claim VERIFIED, because the ladder gives W1a priority over W2). key.enrolled lookup is exempt: next() takes the first matching entry and the ledger is append-only, so the issuer's enrollment always precedes a later duplicate.

10. Policy engine

10.1 Modes: CERTIFICATE (record only), GATE (fail-closed), WATCH (observe-only — never blocks), HYBRID (gate semantics + full record).

10.2 The decision is blocked iff critical_bad ∨ any_REFUTED ∨ blocking_flags under GATE/HYBRID. Registered v1.0.0 flags: coverage-below-threshold, divergence-split:{claim_id}, inconclusive-unresolved:{claim_id}. An INCONCLUSIVE machine-checkable claim MUST surface a flag — a gate consumer MUST be able to distinguish "passed clean" from "passed with an unresolved machine claim".

Erratum D15, second half (§14.2): not every flag is a verdict. meta-coverage-unconfirmed:{claim_id} is advisory — it records that a juror declined to answer its own coverage question. A flag that blocks IS a verdict, and letting an advisory one block hands the deciding vote to the very dissenter §5.3 rule 2 refuses to honor. Measured before the fix: 3/3 clean audits blocked under HYBRID with a jury that refutes everything, because the jury's refusal to confirm coverage blocked the audit it was refusing to cover. The exclusion is from blocking_flags only — the flag stays visible in the decision, so a consumer that wants to treat unconfirmed meta-coverage as a stop signal can, but the gate itself does not. The fail-closed surface does not shrink: a refuted TOP-LEVEL claim still blocks, critical-class claims still block; only the juror's refusal stops deciding.

10.3 WATCH mode records watch.observed and never blocks; the flags are computed identically. Errata (§14.2): v1.0.0 defines WATCH as a policy mode over the same evidence ledger — it does NOT specify a streaming/realtime transport; flag latency budgets for a stream (design §6.5) are a v1.1 candidate, deferred behind a demonstrated need; the divergence.flagged and inconclusive-unresolved flags computed for WATCH claims are still recorded as ledger entries, only the blocking consequence is absent. Erratum D10 (§14.2): a reference transport candidate now exists (veridict/watcher_stream.py) implementing append detection + per- increment flag recomputation over the same §7 ladder, WITHOUT claiming conformance to any latency budget — the normative latency sentence is proposed in §14.2 and deferred to v1.1.

11. Certificates and offline replay

11.1 The certificate body carries: cert_id (sha256(task_id|artifact_digest) [:24]), subject {artifact_digest, task_id, actor_identity}, policy_ref (with the decision-relevant thresholds), claims [{claim_id, verdict_value, divergence, evidence_ids}], jury_composition, disclosure_level, divergence_summary, risk_level, score, scope_limits (MUST include the honesty clause "claim coverage is heuristic, not exhaustive" as its first element), ledger_anchor {checkpoint_seq, chain_hash}, signatures (ed25519 over the canonical body-without-signatures).

11.2 Issuance order is normative: claims and evidence first, then a checkpoint.anchored entry (pinning the chain hash), then certificate.issued.

11.3 Verification outputs {valid, chain_valid, signature_valid, verdicts_match, errors} and MUST check: chain integrity from the file (including refusal on malformed lines); signature against a key enrolled in the ledger; anchor (checkpoint exists at checkpoint_seq, its chain_hash matches the signed body, and a matching certificate.issued entry exists at seq ≥ checkpoint); evidence references (every evidence_ids entry must exist in the ledger — defense-in-depth over the anchor pin); and verdict recompute (replay §5 ladder over ledger evidence for each cert claim, under the cert's policy_ref, with the §9.4 exclusion scope). Any failure ⇒ valid: false with named errors.

11.4 The verifier MUST import Core-level modules only — never jury/verifier implementations.

12. Dossier and resolution (R3)

12.1 On ESCALATED, the system MUST issue a dossier.issued entry after escalation.requested. The dossier is a VIEW over the ledger — never a separate truth. Fields: schema_version, dossier_id (sha256(claim_id|artifact_digest)[:16]), claim {…, verdict, rung: R3, divergence}, summary_page (plain language), risk_frame ("If the REFUTES side is right: …" built from refuting evidence rationales, with an explicit fallback), the FOUR options — accept_with_risk, demand_rerun, narrow_claim, reject — each with an honest consequence, default ("response window expiry triggers policy.fail_safe (R4)"), evidence_links (claim id + evidence ids), response_window_hours.

12.2 Every dossier sentence MUST link to ledger entry ids.

12.3 escalation.resolved records the human's decision (one of the four), decided_by, and an optional risk note, authored by kind human. An unknown decision MUST be rejected.

12.4 Fail-safe. Response-window expiry MUST be recorded as policy.fail_safe with consequence gate_stays_blocked_or_certificate_stamped_unresolved. Silence must never converge to acceptance.

13. Known limitations (normative honesty)

13.1 Certificates are point-in-time statements: evidence appended after issuance legitimately flips a replay verdict (that is tamper-evidence working). Consumers MUST re-verify against the CURRENT ledger.

13.2 Jury heterogeneity is a policy minimum (min_jury_families), not proof of independence; the diversity statement travels in jury_composition.

13.3 Local-jury mode (air-gapped deployments) is conformant if heterogeneity is preserved and the composition is disclosed.

13.4 Formal verification of the Core is a Phase 3 stretch goal and is NOT a v1.0.0 conformance requirement. Partial progress exists (erratum D11: the §7 ladder's five tier rules are machine-checked in Lean 4), but that covers the adjudication logic only — the hash chain, signature layer, and juror honesty remain unproven. Until those are covered too, the core's honesty rests on the canonical-form discipline and the replay algorithm — a stated residual risk.

14. Registry governance

14.1 The entry-type registry and the flag registry are append-only. Adding a type is minor (patch the list, bump patch version). Changing a payload schema, a digest preimage, or a tier rule is MAJOR and requires a migration note.

14.2 Errata. v1.0.0-draft erratum D4 (2026-09-10): replay exclusion of superseded deliberation items was unspecified; §9.4 fixes the scope guard. Erratum D5 (2026-09-10): the entry-hash preimage originally omitted ts and schema_version; §2.3 now binds every stored field (chain format break — ≤0.3.0 ledgers regenerate) and mandates ISO-8601 string timestamps. Erratum D6 (2026-09-10): §7's R4 originally read "anything else ⇒ INCONCLUSIVE", contradicting the reference ladder; §7 now states the doctrinal-consensus rule normatively (VERIFIED on unanimous SUPPORTS, REFUTED on any doctrinal REFUTES even within a majority, INCONCLUSIVE on non-critical SPLIT / W3-only / no evidence); the design's mode-dependent SPLIT handling (§6.2 R2) remains a v1.1 candidate. Erratum D7 (2026-09-10): §9.2 is now explicit — a revision hook that is absent or errors degrades to keep-opinion; a juror MUST NOT be dropped from the revised basis, which would silently erase its first-round REFUTES. Erratum D8 (2026-09-11, certificate mutation differential): the spec-only verifier crashed (IndexError) on a certificate whose signatures array was empty, instead of returning an invalid verdict — a hostile certificate must produce a verdict, never a crash (fail-closed). Fixed in examples/spec_verifier.py; pinned by 16 certificate mutations in tests/test_cert_mutation_parity.py where both verifiers agree. Erratum D9 (2026-09-11, nightly hardening): the static analyzer's file walk did not skip hidden directories — creating a second interpreter environment (.venv312) inside the repository produced thousands of forbidden-call findings from third-party packages, and the §6 fail-closed gate correctly BLOCKED the release on the resulting REFUTES. The gate's behavior was correct; the scanner was not. The walk now skips all dotted directories plus known build directories, pinned by tests/test_verifiers.py::test_static_analyzer_ignores_hidden_dirs. Erratum D10 (2026-09-11, issue #3): the §10.3 WATCH transport gap now has a reference implementation candidate — veridict/watcher_stream.py (poll-based append detection, per-increment §10.2 flag recomputation through the SAME §7 ladder as the batch engine, never blocks, torn trailing lines held back). It does NOT claim conformance to a latency budget yet: no normative latency sentence exists in v1.0.0 and none is added by an implementation unilaterally. The v1.1 candidate sentence proposed: "A conforming WATCH transport MUST surface the flag set recomputed over an appended entry within a bounded detection interval declared by the deployment, and MUST NOT block, alter, or append to the audited ledger." Ratification is deferred to v1.1 (§10.3 errata). Status (2026-09-12): the ratification draft now exists — see 2026-09-12-veridict-standard-v1.1-delta.md (amendment A1 proposes ratifying this exact sentence; the delta stays DRAFT until an independent implementation exercises it). Erratum D10 remains OPEN until v1.1.0 is ratified. Erratum D11 (2026-09-19, issue #8): the §7 ladder's five tier rules are now machine-checked in Lean 4 (proofs/ladder/Ladder.lean, kernel-checked, no bespoke axioms — the agree decision function depends only on propext, Classical.choice, and Quot.sound). The model is cross-checked against the shipped Python ladder over all 28,080 bounded evidence configurations (proofs/ladder/TruthTable.lean, regenerated from the reference implementation per run by scripts/export_lean_truth_table.py), so model/implementation divergence inside the sampled domain fails the proof CI. Limits, stated plainly: this is a proof about the ladder's logic, not about the system. It says the decision function admits no silent pass and no silent gap for the configurations sampled; it does NOT prove the hash chain, the signature layer, or that a deployed juror reported honest evidence — those remain §11.3's verification business, not §7's. A reviewer asking "is the ladder sound?" now gets a checked artifact; a reviewer asking "was this audit truthful?" still gets a certificate to recompute.

14.3 The standard is Apache-2.0 (D8: spec + core + offline verifier are open; hosted platform, certification authority, enterprise integrations are commercial).

Erratum D12 (2026-09-19, jury composition is normative after all): the reference implementation requires a jury of at least two providers drawn from at least two distinct family values before it will issue a certificate, but §5 never stated that requirement as normative text — §5.2 defines only tier semantics. An implementer reading this standard alone could lawfully build a single-provider jury that self-reviews its own output, which is exactly the self-preference the requirement exists to forbid. This closes that gap: a conforming implementation MUST NOT issue a certificate on a jury of fewer than two providers or fewer than two families. The reference implementation additionally excludes any juror from the audited author's own model family before this count and fails closed rather than shrinking to a conflicted panel — implementations MUST do both. Amendment A2 proposes ratifying these sentences; the delta stays DRAFT until an independent implementation exercises it (issue #1's exit criterion). Note the limit: these rules constrain composition, not honesty — two families do not prove either juror reported truthfully, which remains §11.3's business. Status (2026-09-20): the rule is normative here in §14.2 (this erratum) and enforced in the reference implementation at Jury.__init__, which refuses a panel of fewer than two providers or two families BEFORE any certificate is issued — measured, not asserted. The ratification text now exists in 2026-09-12-veridict-standard-v1.1-delta.md (amendment A2, same shape as A1); it stays DRAFT until an independent implementation exercises it. Until then a verifier checking this rule reads it from this erratum, not from a ratified §5.

Erratum D13 (2026-09-19, entry_type taxonomy was implicit): §2 lists entry_type as a field but never enumerated its permitted values, and the JSON Schema described the registry as "open" with only an example list — which omitted task.started, watch.observed, escalation.requested, escalation.resolved, calibration.updated, gate.blocked, and actor.output, all of which the reference implementation emits. An implementer reading the text alone could not know these exist. The schema now enumerates the core types in full. The registry remains open by design, but extensions MUST be namespaced extension.*, so a verifier facing an unknown type abstains instead of silently misparsing it — the same hazard Sester's ERRATUM-K0.2 closed on their side for their event taxonomy. Semantic consumers (any code that totals or nets over entries) MUST understand the core types first: a charge and its refund are distinguished by entry type, not by a payload field, and a consumer that ignores the taxonomy silently diverges.

Erratum D14 (2026-09-20, R4 did not respect W1b outranking doctrine): R4's text reads "with no W1a/W1b on the claim ... ANY doctrinal REFUTES ⇒ REFUTED". The guard is correctly stated for the no-W1 case, but the reference implementation applied the REFUTED branch without re-checking for W1b support, so a claim with deterministic static SUPPORT at W1b could still be turned REFUTED by a juror's dissent. That contradicts §5.3 rule 1 (strict ordering W1a > W1b > W2 > W3): W1b is machine truth, and a doctrinal opinion cannot outrank it, only fail to corroborate it. The implementation now returns VERIFIED when W1b SUPPORTS and only doctrine REFUTES, with the dissent recorded in the divergence field rather than promoted into the verdict. The old behavior was not a security hole — it erred toward blocking, i.e. toward fail-closed — but it converted a juror's uninformed refusal into a decision. The real-LLM canary measured this exactly: 3B jurors REFUTED claims with the rationale "the digest provides no information about the function", and every clean case in the corpus was blocked. Two changes follow: (a) the R4 branch now honors W1b; (b) jurors now receive the artifact's source text, bounded, because a juror that cannot see the code it is judging is not auditing.

Erratum D15 (2026-09-20, coverage meta-claims were decisive at the gate): R1/R2 open a DOCTRINAL meta-claim ("does the W1a evidence actually cover this claim?") precisely because a juror dissented. That meta-claim's only evidence is the same jury round — it carries no W1 truth of its own. The policy engine's blocking rule scanned all claims including meta-claims, so a juror's refusal to answer its own coverage question blocked the gate. The dissenter thereby decided the outcome, nullifying §5.3 rule 2 (doctrine can never overturn W1a) by indirection. Meta-claims are now recorded, adjudicated, and shown in the certificate, and a REFUTED meta-claim is surfaced as meta-coverage-unconfirmed:{id} rather than promoted to a block. Top-level refuted claims still block as before. This is a narrower fail-closed surface, not a weaker one: a genuine top-level machine refutation still blocks, and an unconfirmed coverage question is visible in the certificate and in the run's flags instead of silently deciding it.

Erratum D16 (2026-09-20, the verified-blind spot is real, and it is the honest one): §5.3 rule 2 says doctrine can never overturn W1a machine evidence. That rule is correct and stays. But the real-LLM canary made the consequence concrete rather than theoretical: a defect whose own tests still passes has W1a SUPPORT, so a juror that correctly spots the defect in the code cannot turn the verdict. The 25-class corpus is deliberately built that way — a bug that fails its tests is already caught by W1a and needs no juror — so of 25 defect classes the end-to-end audit catches 2. This is not a bug in the ladder; it is the design's blind spot, named.

The blind spot is in the DESIGN, not the model. Measured with a judgment sonde (scripts/measure_jury_judgment.py) that asks each juror its verdict on the intent claim given the artifact's source, deliberately NOT routed through the ladder: 42/48 measurements correctly REFUTE the defective artifacts (23/24 for qwen2.5:3b, 19/24 for llama3.2:3b), against 2/4 false refutations on clean code. The model sees most of the defects; the verdict still says VERIFIED, because W1a SUPPORT is machine truth and a 3B model that calls half the clean code it sees defective must not be able to turn a verdict on its own. The false-refutation rate IS the justification for rule 2, measured rather than asserted — and the catch rate is the cost of it, measured rather than assumed.

Two consequences, both stated so nobody reads a certificate as more than it says. (a) A VERIFIED certificate is evidence that machine checks passed and jurors did not dissent on the artifact — it is not a proof the artifact is correct, only of what was checked. §13 already says this normatively; D16 records the measurement that makes it load-bearing. (b) The right response to a juror dissent the machine evidence contradicts is not to ignore it and not to let it decide, but to escalate the coverage question — which is what R1's meta-claim does, and what D15 keeps visible. A consumer who wants the dissent to block sets the claim's class critical and gets ESCALATED; a consumer who wants machine truth to decide gets VERIFIED with the dissent recorded. The choice is policy, and both are conforming.

Erratum D17 (2026-09-20, derived summary fields were unverifiable — Tamga ERRATUM-A2 class): a certificate carries summary fields that FOLLOW from the claim verdicts — risk_level and score. §9 required the verifier to recompute the verdicts themselves, and the implementation did. But nothing required it to recompute the summaries, and the reference implementation did not: it validated each verdict_value against the ledger and then trusted risk_level and score as stored. A field that a consumer decides on (the settlement policy gates release on risk_level) was unconstrained by any check.

The consequence is asymmetric, and the asymmetry matters more than the bug. An attacker cannot hide a bad result this way: to make the true risk high a claim verdict must be REFUTED, and verdicts ARE recomputed, so the mismatch fires. What an attacker CAN do is the reverse — write risk_level: "high" over a fully-VERIFIED certificate, or score: 0.0 over a high one. That is a framing attack, not a pass-through: it makes good work look bad, or inflates risk to break a settlement that should have released. It cannot make bad work pass. The honest statement of the exposure is "summary fields could be forged to mislead a consumer", not "bad code could be certified".

§9 now requires: a conforming verifier MUST recompute every derived summary field from the verdicts it validated, and reject any divergence. The reference verifier does. Two fields are derived today; a v1.1 field that summarizes verdicts inherits the same rule without further errata, because the requirement is stated for the class, not the field names. This is the same hazard as D12 and D15 in kind — two fields that must agree, with no rule checking that they do — and was found by the same method: an independent verifier (Tamga) attacking the standard rather than reading the code.

Erratum D18 (2026-09-20, divergence_summary was the second member of D17's class): sweeping the class D17 names found another member in the reference implementation. divergence_summary maps each claim to its adjudication divergence (UNANIMOUS / SPLIT / ...), and the verifier checked the verdict values but not this per-claim summary. Same hazard, same fix: it is recomputed from the same replay the verdicts come from.

Why it matters more than a cosmetic mismatch: a SPLIT is the trigger for deliberation (§9.1), and an honest recorded disagreement is one of the few things a certificate exists to surface. Forging it to UNANIMOUS on a certificate the verifier accepts would present a contested finding as settled — the framing direction of A2', hiding disagreement rather than hiding a bad verdict. It cannot manufacture a REFUTED verdict; the verdict check still fires. It can hide the disagreement.

One member of the class is deliberately NOT recomputed: jury_composition. §9.5 applies to fields whose source IS the replayed evidence. The jury's family composition is established at issuance and enforced there (D12: Jury.__init__ refuses a panel of fewer than two families before any certificate is issued — measured, not asserted), but the ledger carries no record of jury composition independent of the evidence producers, so a verifier has nothing to recompute it from. The attack path is closed at the source instead. A future version that records jury composition into the ledger moves this field under §9.5 with no further erratum, because §9.5 is stated for the class.

Erratum D19 (2026-09-20, policy provenance — the hazard D17's sweep found, and the one that is an INPUT not a consequence): sweeping the class §9.5 names, three more fields were unconstrained in the reference implementation, and one of them is not like the others.

policy_mode is the same value stored twice (top level and inside policy_ref), and the two copies could disagree. Boring duplication — recompute one from the other and reject the mismatch.

policy_ref is the interesting one. Unlike risk_level or divergence_summary, which FOLLOW from the verdicts, policy_ref is used to BUILD the replay policy — it is an input to the verdicts, not a consequence of them. A verifier that reads the policy from the certificate replays under whatever policy the issuer claims to have used, which means the issuer is trusted for the policy, not just for the arithmetic. And the first fix attempt had a fail-open hole exactly here: the check looked up a matching policy.decision entry in the ledger and only compared digests when one existed. A cert claiming a policy_id the ledger never recorded therefore SKIPPED the check — unfalsifiable by construction. That is the same class as D17 but worse, because a forged policy can change verdicts, not just summaries: claim a policy with no critical classes and a tolerant divergence threshold over a ledger whose real policy was strict, and the replay adjudicates leniently.

§9.5 now requires the check to fail closed when no recorded policy matches the claimed policy_id, and to reject a digest mismatch. The verifier reconciles the cert's policy against the policy the ledger records the run actually used (policy.decision carries policy_digest), rather than trusting the certificate's own description of it.

Scope note, kept honest: this binds the certificate to the ledger's record of the policy, which is tamper-evident but is only as meaningful as the policy the issuer actually ran. A issuer who runs a lenient policy and records it honestly gets a certificate that honestly reflects a lenient policy. The fix removes the ability to claim one policy and have run another; it does not make the claimed policy strict.

Erratum D20 (2026-09-20, the replay itself was unscoped — D19's class, found one layer deeper): D19 reconciled the cert against the ledger, but the reconciliation only matters if the replay reads the same ledger the anchor pins. It did not. Three queries fed the replay — claim.registered, evidence.recorded (twice) — and all three scanned the whole ledger, while the analogous D4 guard on deliberation.rounded already restricted itself to the anchored prefix. Same class as D19, same fix, one layer down.

The shape is worth recording because the first PoC attempt against it failed, and the reason it failed is the reason the bug is real. The ladder gives W1a machine evidence absolute priority over W2 jury opinion, so injecting a post-issuance W2 SUPPORTS item cannot move a verdict — the ladder is already robust there. What does move is a W1a item: a claim the honest run adjudicated INCONCLUSIVE (no evidence) can be flipped to VERIFIED by appending a TEST_EXECUTION SUPPORTS entry after the checkpoint. Measured: without the scope guard, replay recomputes VERIFIED over a cert that says INCONCLUSIVE, and verification rejects on the mismatch (detection, not prevention — and a cooperating issuer who ships the cert with the forged verdict gets silent acceptance).

§9.5 now scopes every replay query to the anchored prefix (seq <= checkpoint_seq), the same boundary D4 uses. The verifier sees exactly the in-prefix state the signed anchor pins; post-issuance entries are invisible to it in either direction — they can neither rescue an unattested cert (D19) nor flip a verdict (D20). key.enrolled lookup needs no guard: next() takes the first matching entry and the ledger is append-only, so the issuer's enrollment always precedes an attacker's duplicate.