core/tests/test_verified_contract.py
Shay ec7c680cfc feat(epistemic-disclosure): P1-A — the VERIFIED contract + meaningful-fail tests
Defines what it MEANS for a result to earn DisclosureClaim.VERIFIED /
EpistemicState.VERIFIED — the soundness≠correctness gate the whole VERIFIED lane
rests on. Contract ONLY: no producer, no reader, no solver, no serving, no
verify.py, no verified_serving_enabled, no claim emission in any serving path.

core/epistemic_disclosure/verified_contract.py:
- VerificationObligation — the declarative contract (4 load-bearing flags);
  VERIFICATION_OBLIGATION is fully strict.
- VerificationProof — the replayable proof SHAPE P1-B+ will fill (two reads kept
  separate: distinct lineages for independence, matching digests for convergence).
- evaluate_verification(proof, *, limitation, obligation) -> VerificationResult —
  refuse-preferring: VERIFIED only if EVERY obligation survives.
- disclosure_for_verification(result) — the ONLY sanctioned route to
  (EpistemicState.VERIFIED, DisclosureClaim.VERIFIED); anything else -> UNDETERMINED/NONE.

The mechanism that makes the lane safe: VERIFIED requires TWO INDEPENDENT reads
(distinct lineages) that CONVERGE on one canonical structure. A faithful solve of a
WRONG read is caught because the independent read disagrees (back-substitution alone
cannot catch a read error); "same answer twice" is rejected as not independent.
Neither gold-agreement nor no-refusal nor a second solver over one read can verify.

15 tests, all non-vacuous. THE central test rejects a faithful solve of a wrong read;
one proves the wrong-read obligation is load-bearing (relax it -> poison slips the
check); the full chain composes proof -> contract -> (VERIFIED, VERIFIED) -> P0-3
DISCLOSE, and the poison degrades to COMMIT. Off-serving; smoke 90/0.
2026-06-08 16:20:19 -07:00

201 lines
8.6 KiB
Python

"""P1-A — tests for the VERIFIED contract.
The central, non-negotiable test is :func:`test_verified_contract_rejects_faithful_solve_of_wrong_read`:
a wrong semantic read that is arithmetically faithfully solved (back-substitutes,
boundary-clear) must NOT verify, because an independent read disagrees. Every other
test pins one obligation. The contract is contract-only — no producer, no serving.
"""
from __future__ import annotations
import ast
import pathlib
from dataclasses import replace
from core.epistemic_disclosure.disclosure_claim import DisclosureClaim
from core.epistemic_disclosure.disposition import (
ServedDisposition,
choose_served_disposition,
)
from core.epistemic_disclosure.limitation import LimitationAssessment
from core.epistemic_disclosure.verified_contract import (
REASON_BOUNDARY_FIRED,
REASON_CONTRADICTION_PRESENT,
REASON_INCOMPLETE_PROOF,
REASON_NO_BACK_SUBSTITUTION,
REASON_READS_DISAGREE,
REASON_READS_NOT_INDEPENDENT,
REASON_UNRESOLVED_LIMITATION,
VERIFICATION_OBLIGATION,
VerificationProof,
VerificationVerdict,
disclosure_for_verification,
evaluate_verification,
)
from core.epistemic_state import EpistemicState
def _valid_proof(**overrides) -> VerificationProof:
"""A proof that survives the full contract: two independent reads converging on one
canonical structure, a faithful derivation that back-substitutes, no boundary, no
contradiction. Override one field to construct each poison case."""
base = dict(
source_problem_digest="prob#1",
primary_reader_lineage="reader_primary",
independent_reader_lineage="reader_independent",
primary_read_digest="canonical_structure_C",
independent_read_digest="canonical_structure_C",
derivation_digest="deriv#1",
back_substitution_digest="backsub#1",
boundary_clear=True,
contradiction_clear=True,
)
base.update(overrides)
return VerificationProof(**base)
# --- the positive case: the ONLY route to VERIFIED --------------------------------- #
def test_fully_valid_proof_verifies():
result = evaluate_verification(_valid_proof(), limitation=None)
assert result.verdict is VerificationVerdict.VERIFIED
assert result.failed_checks == ()
# --- THE central hazard ------------------------------------------------------------ #
def test_verified_contract_rejects_faithful_solve_of_wrong_read():
"""A WRONG primary read, an arithmetically faithful solve over it (back-substitutes
into the wrong structure, no boundary fires) — but the INDEPENDENT read sees the
correct structure and disagrees. Must NOT verify. This is the gate that stops P1-B
from degenerating into a 'second solver agrees' rubber stamp."""
poison = _valid_proof(
primary_read_digest="structure_from_WRONG_read",
independent_read_digest="structure_from_CORRECT_read", # the reads disagree
)
result = evaluate_verification(poison, limitation=None)
assert result.verdict is VerificationVerdict.NOT_VERIFIED
assert REASON_READS_DISAGREE in result.failed_checks
def test_verified_requires_independent_read_not_same_read_twice():
same_read_twice = _valid_proof(
primary_reader_lineage="reader_X",
independent_reader_lineage="reader_X", # same lineage → not independent
)
result = evaluate_verification(same_read_twice, limitation=None)
assert result.verdict is VerificationVerdict.NOT_VERIFIED
assert REASON_READS_NOT_INDEPENDENT in result.failed_checks
# --- each remaining obligation ----------------------------------------------------- #
def test_verified_requires_back_substitution():
result = evaluate_verification(_valid_proof(back_substitution_digest=""), limitation=None)
assert result.verdict is VerificationVerdict.NOT_VERIFIED
assert REASON_NO_BACK_SUBSTITUTION in result.failed_checks
def test_verified_requires_boundary_clear():
result = evaluate_verification(_valid_proof(boundary_clear=False), limitation=None)
assert result.verdict is VerificationVerdict.NOT_VERIFIED
assert REASON_BOUNDARY_FIRED in result.failed_checks
def test_contradiction_blocks_verification():
result = evaluate_verification(_valid_proof(contradiction_clear=False), limitation=None)
assert result.verdict is VerificationVerdict.NOT_VERIFIED
assert REASON_CONTRADICTION_PRESENT in result.failed_checks
def test_incomplete_proof_digest_blocks_verification():
for field in ("source_problem_digest", "derivation_digest"):
result = evaluate_verification(_valid_proof(**{field: ""}), limitation=None)
assert result.verdict is VerificationVerdict.NOT_VERIFIED, field
assert REASON_INCOMPLETE_PROOF in result.failed_checks, field
def test_verified_rejects_any_limitation_assessment():
blocking = LimitationAssessment(
limitation_kind="missing_information",
resolution_action="ask_question",
epistemic_state=EpistemicState.UNDETERMINED,
owner_organ="r2",
blocking_reason="cmb_underdetermined",
)
result = evaluate_verification(_valid_proof(), limitation=blocking)
assert result.verdict is VerificationVerdict.NOT_VERIFIED
assert REASON_UNRESOLVED_LIMITATION in result.failed_checks
# --- the obligations are LOAD-BEARING (schema-obligation discipline) ---------------- #
def test_canonical_obligation_is_fully_strict():
assert VERIFICATION_OBLIGATION.requires_independent_read
assert VERIFICATION_OBLIGATION.rejects_wrong_read_even_if_solved
assert VERIFICATION_OBLIGATION.requires_back_substitution
assert VERIFICATION_OBLIGATION.requires_boundary_clear
def test_relaxing_wrong_read_obligation_would_admit_the_poison():
"""Proves ``rejects_wrong_read_even_if_solved`` is load-bearing, not decoration: the
canonical obligation catches the poison; relaxing exactly that one flag stops the
check from firing (CLAUDE.md: a test must fail under the violation it guards)."""
poison = _valid_proof(independent_read_digest="different_structure")
canonical = evaluate_verification(poison, limitation=None)
assert canonical.verdict is VerificationVerdict.NOT_VERIFIED
assert REASON_READS_DISAGREE in canonical.failed_checks
relaxed = replace(VERIFICATION_OBLIGATION, rejects_wrong_read_even_if_solved=False)
relaxed_result = evaluate_verification(poison, limitation=None, obligation=relaxed)
assert REASON_READS_DISAGREE not in relaxed_result.failed_checks
# --- the sanctioned route to the verified state/claim ------------------------------ #
def test_verified_claim_requires_epistemic_state_verified():
verified = evaluate_verification(_valid_proof(), limitation=None)
state, claim = disclosure_for_verification(verified)
assert state is EpistemicState.VERIFIED
assert claim is DisclosureClaim.VERIFIED
def test_not_verified_routes_to_safe_defaults():
poison = evaluate_verification(_valid_proof(independent_read_digest="diff"), limitation=None)
state, claim = disclosure_for_verification(poison)
assert state is not EpistemicState.VERIFIED
assert claim is not DisclosureClaim.VERIFIED
assert (state, claim) == (EpistemicState.UNDETERMINED, DisclosureClaim.NONE)
# --- composition with the Phase-0 bus (the whole chain) ---------------------------- #
def test_verified_proof_routes_through_bus_to_disclose():
"""proof → contract → (VERIFIED state, VERIFIED claim) → P0-3 disposition = DISCLOSE."""
result = evaluate_verification(_valid_proof(), limitation=None)
state, claim = disclosure_for_verification(result)
disp = choose_served_disposition(epistemic_state=state, limitation=None, disclosure_claim=claim)
assert disp is ServedDisposition.DISCLOSE
def test_unverified_proof_never_discloses_through_bus():
result = evaluate_verification(_valid_proof(independent_read_digest="diff"), limitation=None)
state, claim = disclosure_for_verification(result)
disp = choose_served_disposition(epistemic_state=state, limitation=None, disclosure_claim=claim)
assert disp is not ServedDisposition.DISCLOSE
assert disp is ServedDisposition.COMMIT
# --- hygiene ----------------------------------------------------------------------- #
def test_verified_contract_does_not_import_serving_or_verify():
import core.epistemic_disclosure.verified_contract as mod
module_path = mod.__file__
assert module_path is not None
src = pathlib.Path(module_path).read_text()
mods = [n.module or "" for n in ast.walk(ast.parse(src)) if isinstance(n, ast.ImportFrom)]
forbidden = [
m for m in mods if "generate.derivation" in m or "reliability_gate" in m or m.endswith("verify")
]
assert forbidden == []