core/tests/test_volume_honesty.py
Shay c1d08ff9d5 feat(curriculum): sealed-practice producer for curriculum serving (Phase C)
Builds the producer `chat/curriculum_serve_license.py` already named as the
only writer of the ledger it reads — `evals.curriculum_serve.practice.runner
.seal_ledger` — which did not exist. Until now, authoring curriculum could
not earn a license at any volume.

A band's case space is ENUMERATED, not authored: every exam question that
routes to that subject (resolve_domain) whose relation is in that family, one
committed case per distinct query atom. So `committed == distinct` is not a
property the generator maintains, it is the same fact twice — the structural
form of ADR-0264 R9, and why this producer cannot develop the deduction
producer's exposure (CASES_PER_BAND=720 filled from spaces as small as 28).
CASES_PER_BAND=660 follows `evals/determination_estimation` per
DIVISION-OF-WORK §4: a ceiling on committed volume, not a quota.

11 bands, wrong=0, inflation 1.0 everywhere.

THE LEDGER IS DELIBERATELY NOT COMMITTED. The plan's Phase-1 exit criterion
asked for "a real (still-unearned) ledger"; that state is unreachable.
Reliability is commitment precision and a correct UNKNOWN is a commitment, so
conservative_floor(660,660)=0.990046 clears theta_SERVE on non-commitments
alone. Sealing today licenses FOUR bands on evidence that is 99.0%-99.98%
correct non-commitment — which ADR-0262 §5.1 rules unacceptable and which
ClassTally structurally cannot see (no verdict axis). Writing the artifact is
therefore a ratification and belongs to Phase D's explicit human-run verb.
The open outcome-mix ruling is now blocking, not academic.

Two corrections to my own earlier records, both measured:

- ADR-0264 §4.2 sized bands from per-TERM exclusivity; the router's predicate
  is per-PAIR, which is looser. Every ceiling was understated, and
  systems_software_causal is 720 not 630 — flipping it from "cannot reach
  657" to "can". 4 of 11 bands can reach the floor, not 3. Now pinned as
  measured values in BAND_ATOM_SPACE.
- `then` and `therefore` are taught philosophy_theology lemmas AND control
  words of the argument reader (`therefore` is the conclusion marker). 164
  routable atoms refuse compiled_premises_unreadable — coverage misses, never
  wrongs — in the band Phase F retargets to. The vocabulary boundary is not
  screened against the reader's grammar; a pack teaching and/or/not/if would
  open a much larger hole the same way. Recorded, not fixed (§6.5), pinned as
  a two-lemma bound.

Registers curriculum_serve in AUDIT_SOURCES, retiring the declared `None`
that was Phase C's forcing function, and adds the producer to `deductive`.

[Verification]: in-worktree on canonical CPython 3.12.13 with `uv sync
--locked`: smoke 571 (569 + 1 test + 1 parametrization), deductive 310
(291 + 19). Mutation-checked: injecting the deduction padding pattern into
band_cases turns 5 tests red including the R9 audit and the seal guard.
curriculum_serve lane unchanged at n=32 correct=32 wrong=0 anti_recall=5;
all 11 lane SHA pins match; no ledger written, so no serving change.
2026-07-26 09:52:54 -07:00

412 lines
18 KiB
Python

"""The volume-honesty invariant — practice volume must be distinct evidence.
ADR-0264 R9. `conservative_floor` is a one-sided Wilson lower bound, and Wilson
assumes independent trials. CORE's pipeline is deterministic, so replaying an
identical case is not a second trial — it is the same trial with a guaranteed
outcome. A ledger's ``committed`` count is therefore an upper bound on its
evidence, and the honest figure is its distinct-decision count.
This file is the specification of that invariant, written before the curriculum
practice producer exists (Phase C). It is also the audit instrument, because the
exposure S6 predicted in the abstract
(`docs/research/curriculum-volume-quantification-2026-07-24.md` §1) turned out to
be live and measurable in the deduction ledger — see
:data:`DEDUCTION_DISTINCT_EVIDENCE` and
`docs/research/distinct-evidence-audit-2026-07-25.md`.
Three producers back the three entries in `core.ratified_ledger.CAPABILITY_LEDGERS`:
- **estimation** (ADR-0175) — clean. 660 committed, 660 distinct, inflation 1.0.
``CASES_PER_CLASS = 660`` was evidently chosen just above the 657 a perfect
record needs, on distinct cases. This is the standard the other producers are
measured against, and it is why the deduction finding is a regression from an
established practice rather than a gap nobody had thought about.
- **deduction_serve** (ADR-0256) — 21 of 25 bands do not clear θ_SERVE on
distinct evidence; the worst three inflate 28 distinct cases to 720 committed.
Recorded, pinned, and NOT silently repaired: the ledger is SHA-sealed, ratified,
and gating a live flag, so changing it is Shay's ratification, not a test's.
- **curriculum_serve** (ADR-0262/0264) — clean, and clean *structurally*: the
producer's case identity IS the query atom, so ``committed == distinct`` cannot
drift apart the way it did for deduction, where case identity was a quota index.
Its ledger is deliberately uncommitted — see
``evals/curriculum_serve/practice/runner.py``.
Deliberately narrow. This pins evidence *distinctness*. It does not pin outcome
mix — whether each verdict class needs its own volume is an open ruling recorded
in the research note, and imposing it here would retroactively fail all 25
deduction bands on a criterion no ADR has ratified.
"""
from __future__ import annotations
import json
from collections.abc import Callable, Hashable
from pathlib import Path
import pytest
from core.ratified_ledger import CAPABILITY_LEDGERS
from core.reliability_gate import conservative_floor
from core.reliability_gate.evidence import (
SERVE_VOLUME_AT_THETA_099,
EvidenceAudit,
audit_band,
audit_bands,
below_floor,
format_report,
volume_for_theta,
)
REPO_ROOT = Path(__file__).resolve().parents[1]
#: θ the sealed-practice ledgers are gated at (both ledger notes state it).
THETA_SERVE = 0.99
# ---------------------------------------------------------------------------
# Audit sources, one per licensed-ledger capability.
#
# Keyed by the SAME capability names as `CAPABILITY_LEDGERS` and checked against
# it below, so a new capability cannot be added to the manifest without either an
# audit source or an explicit declaration that its producer does not exist yet.
# A hand-copied list here would fall behind the manifest exactly the way the
# workbench grounding whitelist fell behind `GROUNDING_SOURCES`.
# ---------------------------------------------------------------------------
def _deduction_keys() -> dict[str, list[Hashable]]:
"""Decision keys per band for the deduction practice corpus.
The key is the case TEXT. Two cases with identical text are indisputably the
same decision, so text-identity *under*-reports inflation (a tighter key —
the normalized atom tuple — would collapse spelling variants and report
more). Under-reporting is the correct direction: the measured gap is a floor
on the real gap.
"""
from evals.deduction_serve.practice.gold import all_gold_problems
out: dict[str, list[Hashable]] = {}
for problem in all_gold_problems():
out.setdefault(problem.class_name, []).append(problem.payload["text"])
return out
def _estimation_keys() -> dict[str, list[Hashable]]:
from evals.determination_estimation import all_gold_problems
out: dict[str, list[Hashable]] = {}
for problem in all_gold_problems():
payload = problem.payload
key = repr(sorted(payload.items())) if isinstance(payload, dict) else repr(payload)
out.setdefault(problem.class_name, []).append(key)
return out
def _curriculum_keys() -> dict[str, list[Hashable]]:
"""Decision keys per band for the curriculum practice corpus (Phase C).
The key is the query ATOM, which is also the producer's case identity — so
this audit can only ever report inflation 1.0 while the producer is correct,
and reports the real figure the moment it is not. Contrast the deduction
source above, where the key had to be recovered from case text because the
producer's identity was a quota index.
"""
from evals.curriculum_serve.practice import all_gold_problems
out: dict[str, list[Hashable]] = {}
for problem in all_gold_problems():
out.setdefault(problem.class_name, []).append(problem.payload.key)
return out
#: capability -> keys provider, or ``None`` when the producer is not built.
#: ``None`` is a declaration, not an omission: :func:`test_every_licensed_capability_has_an_audit_source`
#: accepts it only while the capability's ledger is genuinely absent.
AUDIT_SOURCES: dict[str, Callable[[], dict[str, list[Hashable]]] | None] = {
"estimation": _estimation_keys,
"deduction_serve": _deduction_keys,
"curriculum_serve": _curriculum_keys,
}
#: Measured 2026-07-25 at main @ `6ada6f7a`. Every band is 720 committed.
#: This is an EXPOSURE INVENTORY, not an approved baseline: 21 of these 25 do not
#: clear θ_SERVE=0.99 on distinct evidence. It is pinned so the exposure cannot
#: grow or drift unnoticed while the ratification question is open.
DEDUCTION_DISTINCT_EVIDENCE: dict[str, int] = {
"atomic": 98,
"categorical": 294,
"conditional_chain": 294,
"conditional_single": 294,
"disjunctive": 294,
"en_atomic": 474,
"en_conditional_chain": 720,
"en_conditional_single": 474,
"en_condmem_chain": 52,
"en_condmem_conditional": 60,
"en_condmem_disjunctive": 28,
"en_condmem_fused": 60,
"en_disjunctive": 720,
"en_exist_chain": 28,
"en_exist_negative": 28,
"en_exist_universal": 46,
"en_exist_witness": 35,
"en_member_atomic": 60,
"en_member_chain": 52,
"en_member_negative": 52,
"en_member_single": 60,
"en_verb_chain": 308,
"en_verb_fact": 660,
"en_verb_negative": 308,
"en_verb_universal": 660,
}
#: The four that DO clear on distinct evidence. Derived below, not restated.
_EXPECTED_CLEAN = {"en_conditional_chain", "en_disjunctive", "en_verb_fact", "en_verb_universal"}
@pytest.fixture(scope="module")
def deduction_audits() -> tuple[EvidenceAudit, ...]:
return audit_bands(_deduction_keys())
@pytest.fixture(scope="module")
def estimation_audits() -> tuple[EvidenceAudit, ...]:
return audit_bands(_estimation_keys())
# ---------------------------------------------------------------------------
# 1. The instrument itself must be correct, and must fail under mutation.
# ---------------------------------------------------------------------------
def test_serve_volume_is_derived_from_the_pinned_floor() -> None:
"""657 must be computed, never trusted as a literal.
If `WILSON_Z` ever moves, a hard-coded 657 becomes silently wrong in every
doc and test that repeats it. This asserts the derivation and the boundary.
"""
assert volume_for_theta(THETA_SERVE) == SERVE_VOLUME_AT_THETA_099 == 657
n = SERVE_VOLUME_AT_THETA_099
assert conservative_floor(n, n) >= THETA_SERVE
assert conservative_floor(n - 1, n - 1) < THETA_SERVE, (
"657 must be the SMALLEST perfect-record volume clearing theta"
)
def test_audit_detects_padding() -> None:
"""The mutation check. Pad a corpus and the instrument must catch it.
Both corpora below commit exactly 720 cases with a perfect record, so
`conservative_floor` returns the *same passing number* for each and the gate
as it stands cannot tell them apart. One exercised 720 decisions; the other
exercised 28. That gap is the whole point.
"""
honest = audit_band("honest", [f"case-{i}" for i in range(720)])
padded = audit_band("padded", [f"case-{i % 28}" for i in range(720)])
assert honest.committed == padded.committed == 720
assert honest.claimed == padded.claimed >= THETA_SERVE, (
"the existing gate must be shown to see these as identical"
)
assert honest.distinct == 720
assert honest.inflation == 1.0
assert honest.max_repeat == 1
assert honest.clears(THETA_SERVE)
assert padded.distinct == 28
assert padded.inflation > 25
assert padded.max_repeat > 25
assert not padded.clears(THETA_SERVE)
assert padded.honest < 0.81
def test_a_single_repeat_is_enough_to_move_the_honest_floor() -> None:
"""No dead zone: one duplicate in an otherwise-exact-threshold corpus drops it."""
exact = audit_band("exact", [f"c-{i}" for i in range(657)])
assert exact.clears(THETA_SERVE)
# Replace one distinct case with a duplicate: same committed, 656 distinct.
padded = audit_band("padded", [f"c-{i}" for i in range(656)] + ["c-0"])
assert padded.committed == 657
assert padded.distinct == 656
assert not padded.clears(THETA_SERVE)
def test_tighter_keys_can_only_report_more_inflation() -> None:
"""Key choice is safe in one direction only, and that is the direction used.
A coarser key (case text) merges fewer cases than a finer one (normalized
atom). So an audit over text is a lower bound on the audit over atoms, and a
finding built on it cannot be an exaggeration.
"""
coarse = ["Does a require b?", "Does a requires b?", "Does c require d?"]
fine = ["(a,requires,b)", "(a,requires,b)", "(c,requires,d)"]
assert audit_band("coarse", coarse).inflation <= audit_band("fine", fine).inflation
def test_audit_rejects_impossible_counts() -> None:
with pytest.raises(ValueError, match="cannot exceed"):
EvidenceAudit(band="b", committed=5, distinct=6, max_repeat=1)
with pytest.raises(ValueError, match="no distinct keys"):
EvidenceAudit(band="b", committed=5, distinct=0, max_repeat=0)
# ---------------------------------------------------------------------------
# 2. Every licensed capability must be audited — the anti-silence guard.
# ---------------------------------------------------------------------------
def test_every_licensed_capability_has_an_audit_source() -> None:
"""Derived from `CAPABILITY_LEDGERS`, so a new capability cannot slip past.
This was the forcing function for Phase C, and it worked: a ``None`` audit
source stops being an honest declaration the moment the capability's ledger
exists. All three producers now carry one, so the guard is holding the line
for the NEXT capability rather than for curriculum.
"""
assert set(AUDIT_SOURCES) == set(CAPABILITY_LEDGERS), (
"AUDIT_SOURCES and CAPABILITY_LEDGERS disagree — a licensed capability is "
"unaudited, or an audit source names a capability that is not licensed"
)
for capability, source in sorted(AUDIT_SOURCES.items()):
if source is not None:
continue
ledger_path = CAPABILITY_LEDGERS[capability].path
assert not ledger_path.exists(), (
f"{capability}: ledger {ledger_path.name} now exists but has no audit "
f"source. Register one in AUDIT_SOURCES — a sealed ledger whose "
f"distinct evidence is unmeasured is exactly the ADR-0264 R9 exposure."
)
@pytest.mark.parametrize("capability", sorted(c for c, s in AUDIT_SOURCES.items() if s))
def test_audited_capability_bands_are_non_degenerate(capability: str) -> None:
"""Whatever a producer emits, it must be auditable and non-empty."""
audits = audit_bands(AUDIT_SOURCES[capability]()) # type: ignore[misc]
assert audits, f"{capability}: producer yielded no bands"
for audit in audits:
assert audit.committed > 0
assert audit.distinct > 0
assert audit.inflation >= 1.0
# ---------------------------------------------------------------------------
# 3. The estimation producer — the clean standard the invariant is calibrated to.
# ---------------------------------------------------------------------------
def test_estimation_producer_has_no_inflation(
estimation_audits: tuple[EvidenceAudit, ...],
) -> None:
"""ADR-0175's producer commits distinct cases only, just above the threshold.
Recorded as a test because it is the existence proof that the invariant is
satisfiable and was in fact satisfied before ADR-0256's producer: 660
distinct cases against the 657 a perfect record needs.
"""
assert [a.band for a in estimation_audits] == [
"converse:parent_of",
"converse:sibling_of",
]
for audit in estimation_audits:
assert audit.committed == audit.distinct == 660, format_report(
estimation_audits, THETA_SERVE
)
assert audit.max_repeat == 1
assert audit.clears(THETA_SERVE)
assert below_floor(estimation_audits, THETA_SERVE) == ()
# ---------------------------------------------------------------------------
# 3b. The curriculum producer — clean, and clean by construction (Phase C).
# ---------------------------------------------------------------------------
def test_curriculum_producer_has_no_inflation() -> None:
"""The second producer that satisfies the invariant, and the first that
satisfies it STRUCTURALLY.
Its case identity is the query atom, so ``committed == distinct`` is not a
property the generator has to maintain — it is the same fact twice. Pinned here
beside the estimation standard because this file is where a reader looks to ask
"which producers are honest about volume?".
"""
audits = audit_bands(_curriculum_keys())
assert audits, "curriculum producer yielded no bands"
assert len(audits) == 11, f"expected 11 populated bands, found {len(audits)}"
for audit in audits:
assert audit.committed == audit.distinct, format_report(audits, THETA_SERVE)
assert audit.inflation == 1.0
assert audit.max_repeat == 1
assert {a.band for a in below_floor(audits, THETA_SERVE)} == {
a.band for a in audits if a.distinct < SERVE_VOLUME_AT_THETA_099
}, "a band below the floor must be below it for lack of VOLUME, never inflation"
# ---------------------------------------------------------------------------
# 4. The deduction producer — the measured exposure, pinned in both directions.
# ---------------------------------------------------------------------------
def test_deduction_distinct_evidence_matches_the_recorded_exposure(
deduction_audits: tuple[EvidenceAudit, ...],
) -> None:
"""Pins the exact inventory, so the exposure can neither grow nor drift.
Fails if a band's distinct count changes in EITHER direction. A drop is the
exposure worsening. A rise means someone improved a band — welcome, and the
inventory must then be updated deliberately rather than by a silently
loosening test.
"""
measured = {a.band: a.distinct for a in deduction_audits}
assert measured == DEDUCTION_DISTINCT_EVIDENCE, format_report(
deduction_audits, THETA_SERVE
)
for audit in deduction_audits:
assert audit.committed == 720, "CASES_PER_BAND changed — re-audit the ledger"
def test_deduction_exposure_membership_is_exactly_as_recorded(
deduction_audits: tuple[EvidenceAudit, ...],
) -> None:
"""Which bands fail is derived from the floor, not restated alongside it."""
failing = {a.band for a in below_floor(deduction_audits, THETA_SERVE)}
clean = {a.band for a in deduction_audits} - failing
assert clean == _EXPECTED_CLEAN, format_report(deduction_audits, THETA_SERVE)
assert len(failing) == 21, (
f"expected 21 bands below the distinct-evidence floor, found {len(failing)}"
)
def test_deduction_sealed_ledger_matches_the_producer_it_names(
deduction_audits: tuple[EvidenceAudit, ...],
) -> None:
"""The exposure is in the shipped artifact, not only in the generator.
Without this the finding could be dismissed as being about a generator that
the sealed ledger does not reflect. The ledger's committed counts are the
producer's committed counts, band for band.
"""
path = CAPABILITY_LEDGERS["deduction_serve"].path
ledger = json.loads(path.read_text(encoding="utf-8"))
classes = ledger["classes"]
assert ledger["provenance"] == "evals.deduction_serve.practice.runner.seal_ledger"
produced = {a.band: a.committed for a in deduction_audits}
sealed = {name: tally["correct"] + tally["wrong"] for name, tally in classes.items()}
assert sealed == produced, (
"sealed ledger committed counts diverge from the producer — the audit "
"below would then be measuring something the engine does not read"
)
assert all(tally["wrong"] == 0 for tally in classes.values()), "wrong=0 must hold"
def test_recorded_exposure_is_declared_in_a_decision_record() -> None:
"""A pinned exposure with no decision record behind it is just a stale test.
Ties this file to the ADR that rules on it, so the inventory above cannot
outlive the reasoning that justified leaving it in place.
"""
adr = REPO_ROOT / "docs" / "adr" / "ADR-0264-negative-curriculum-and-premise-scope.md"
assert adr.exists(), "ADR-0264 governs this invariant and must be present"
text = adr.read_text(encoding="utf-8")
assert "R9" in text, "ADR-0264 must state the R9 volume-honesty rule"
research = REPO_ROOT / "docs" / "research" / "distinct-evidence-audit-2026-07-25.md"
assert research.exists(), (
"the measured audit must stay written down — a 21-band exposure recorded "
"only in a test's data structure is not a finding anyone will read"
)