The ratified capability, through the existing mutation owner only:
- teaching/proof_promotion.py — pure decider. Fresh-reads every premise AND
the claim from the store (claim_entry_index; forms never proposer-supplied),
strict status compares (no parse-defaulting), reading_certified must be the
boolean True, engine certification via the pinned deductive engine,
proposer_payload accepted and provably never read (del before use; poisoned-
mapping test), certificate digest emitted for D4 trace-hash folding. Zero
mutation; zero vault.store calls; zero status writes (proven with the
INV-21/INV-29 detectors themselves).
- vault/store.py::apply_certified_promotion — the single transition site.
Independently re-verifies: byte-for-byte replay under DEDUCTIVE_ENGINE_PIN,
promotion_positive, live claim form/reading/status cross-checks, live
premise form/reading/status cross-checks (staleness refuses). Fabricated or
tampered certificates flip nothing; authority is live store state plus
recomputation, never the artifact.
- generate/proof_chain/engine_pin.py — DEDUCTIVE_ENGINE_PIN mirrors the
deductive_logic_v1 lane SHA; sync pinned by AST test against
scripts/verify_lane_shas.py.
- Consistency fix found in lookback: both promotion sites now stamp
epistemic_state alongside epistemic_status (the ADR-0148 site left the
stored state tag stale; recall recomputed it, but the stored key lied).
Obligations: all six strict-xfail markers retired and live (O1/O2
strengthened to prove the transition through the vault owner); the
module-existence pin deleted per its own docstring; the two remaining
honesty pins kept. INV-21 allowlist unchanged; INV-29 allowlist unchanged
({vault/store.py}); INV-29's 29c visibility floor raised 2 -> 3 to cover the
new site.
No runtime turn path calls promotion; the deterministic demo is PR D.
Validation: new suite 49 passed; obligations 8 passed (0 xfail remaining);
invariants 66 passed; certificate 27 passed; 0148 6 passed; epistemic 20
passed; smoke files green; lane SHAs verified.
68 lines
2.8 KiB
Python
68 lines
2.8 KiB
Python
"""Epistemic Grade Policy — typed status surface per ADR-0021.
|
|
|
|
`EpistemicStatus` is a *position in the revision graph*, not a trust tier.
|
|
Source labels (peer_consensus, outsider_empirical, established,
|
|
unauthoritative) are deliberately not part of this enum — they would
|
|
re-import the bias ADR-0021 refuses.
|
|
|
|
The four positions form an open lattice under review. No member carries
|
|
a "hardened" or "permanent" flag (non-hardening invariant, ADR-0021 §2).
|
|
Every claim remains revisable; a Stage-3 inversion path is always
|
|
available for `FALSIFIED` claims.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from enum import Enum, unique
|
|
|
|
|
|
@unique
|
|
class EpistemicStatus(Enum):
|
|
"""Position of a claim in the reviewed revision graph.
|
|
|
|
Coherence is the only admission signal (ADR-0021 §3): a status is a
|
|
function of coherence with the existing reviewed field, never of
|
|
source authority, credentials, or the system's own asserted output.
|
|
|
|
The *judgment behind* a transition is curator-mediated by default —
|
|
``review_correction`` carries the resulting status as an input, it does
|
|
not compute it. One arm of ADR-0021's "Named gap (v2 work)" is now
|
|
wired (ADR-0218, ratified 2026-06-11): for the deductively *entailed*
|
|
subclass, ``teaching/proof_promotion.py`` certifies entailment over an
|
|
all-COHERENT, curator-certified premise set via the sound
|
|
``deductive_logic_v1`` engine, and
|
|
``VaultStore.apply_certified_promotion`` owns the SPECULATIVE→COHERENT
|
|
transition after independent re-verification. No runtime turn path
|
|
invokes it yet. Every other transition remains curator-mediated — see
|
|
``docs/issues/proof-carrying-coherence-promotion.md``.
|
|
"""
|
|
|
|
COHERENT = "coherent"
|
|
CONTESTED = "contested"
|
|
SPECULATIVE = "speculative"
|
|
FALSIFIED = "falsified"
|
|
|
|
|
|
# Statuses that admit a claim as evidence in downstream inference.
|
|
# `SPECULATIVE` is admissible only as a candidate, not as evidence.
|
|
# `CONTESTED` is admissible but cannot drive inferences depending on its truth.
|
|
# `FALSIFIED` is retained for provenance and Stage-3 inversion, not evidence.
|
|
ADMISSIBLE_AS_EVIDENCE: frozenset[EpistemicStatus] = frozenset({
|
|
EpistemicStatus.COHERENT,
|
|
})
|
|
|
|
|
|
def parse_status(value: str | None) -> EpistemicStatus:
|
|
"""Parse a serialised status string, defaulting to SPECULATIVE.
|
|
|
|
SPECULATIVE is the safe default at proposal creation per ADR-0021
|
|
§Schema impact: "transitions to COHERENT / CONTESTED / FALSIFIED only
|
|
via the review path." An absent or unknown value must not silently
|
|
promote a claim to COHERENT.
|
|
"""
|
|
if value is None or value == "":
|
|
return EpistemicStatus.SPECULATIVE
|
|
for status in EpistemicStatus:
|
|
if status.value == value:
|
|
return status
|
|
return EpistemicStatus.SPECULATIVE
|