Phase B of the curriculum-license-loop arc. Stacked on the ADR-0264 branch. The invariant: 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 an upper bound on its evidence; the defensible figure is its distinct-decision count. Phase B was scoped as a precaution for a curriculum producer that does not exist yet. Running the instrument against the producers that DO exist found it already violated: 21 of the 25 ratified deduction_serve bands do not clear theta_SERVE=0.99 on distinct evidence. Three inflate 28 distinct cases into 720 committed (honest floor 0.8084 vs claimed 0.9909). deduction_serving_enabled was ratified ON 2026-07-24 and is live. The estimation producer (ADR-0175) is clean -- 660 committed, 660 distinct, zero repeats, evidently chosen just above the 657 a perfect record needs. So this is a regression from a standard already established in the repo, not an architectural gap. `claimed` is identical for all 25 deduction bands because every band commits 720 with a perfect record: the gate sees 25 indistinguishable passes while honest floors span 0.8084..0.9909. NOT REPAIRED. The ledger is SHA-sealed, ratified, and gating a live flag, so re-sealing it is Shay's ratification, not a test's. wrong=0 still holds -- no band answered anything incorrectly. What is not established is reliability at the volume claimed. Measured, pinned in both directions, written down. Added: - core/reliability_gate/evidence.py -- pure measurement, imported by no serving path. volume_for_theta() DERIVES 657 from conservative_floor rather than restating it, so a WILSON_Z change cannot leave a stale literal behind. - tests/test_volume_honesty.py -- 13 tests. AUDIT_SOURCES is checked against CAPABILITY_LEDGERS, so a new licensed capability cannot ship unaudited; the curriculum entry is a declared None that fails the moment its ledger exists. That is Phase C's forcing function against repeating the pattern. - docs/research/distinct-evidence-audit-2026-07-25.md -- full audit + the open outcome-mix ruling for Shay. - ADR-0264 R9 amended with the measured exposure. Decision key is case TEXT deliberately: a tighter key (normalized atom) would collapse spelling variants and report MORE inflation, so text-identity under-reports and every number is a floor on the real gap. Outcome mix is deliberately NOT pinned. ClassTally has no verdict axis, the deduction producer already balances 240/240/240 by construction, and imposing a per-verdict-class floor would retroactively fail all 25 bands on a criterion no ADR has ratified (smallest per-band class count is 120). Recorded for a ruling with numbers instead. [Verification]: uv sync --locked on canonical CPython 3.12.13; in-worktree smoke 569 passed (556 baseline + 13), deductive 285 passed. Registered in the `smoke` curated suite -- not left to `full`, which gates nothing. Mutation- checked: doubling CASES_PER_BAND -> 2 failed; reporting committed as distinct -> 4 failed; gating on `claimed` instead of `honest` -> 3 failed; tree restores to 13 passed.
175 lines
7.1 KiB
Python
175 lines
7.1 KiB
Python
"""ADR-0264 R9 — distinct-evidence audit: the precondition :func:`conservative_floor` assumes.
|
|
|
|
:func:`core.reliability_gate.floor.conservative_floor` is a one-sided Wilson lower
|
|
bound on a success proportion. Wilson assumes **independent trials**. CORE's
|
|
pipeline is deterministic by construction — that is the whole thesis — so
|
|
replaying an identical input yields the identical outcome with certainty. Two
|
|
identical cases in a practice ledger are therefore perfectly correlated, not
|
|
independent, and contribute one trial's worth of evidence between them, not two.
|
|
|
|
So a ledger's ``committed`` count is an upper bound on its evidence, and the
|
|
honest figure is the count of *distinct decisions* it exercised. This module
|
|
computes both and reports the gap. It is deliberately a pure measurement with no
|
|
authority: it never edits a ledger, never gates anything, and nothing in the
|
|
serving path imports it. What to do about a gap is a ratification decision.
|
|
|
|
Why this exists as code rather than a note: S6 predicted the exposure in the
|
|
abstract (`docs/research/curriculum-volume-quantification-2026-07-24.md` §1 —
|
|
``conservative_floor`` cannot distinguish "657 independent facts" from "16 facts
|
|
asked 41 times"). It was then measured in the *live, ratified* deduction ledger,
|
|
where 21 of 25 bands do not clear θ_SERVE on distinct evidence. A prediction that
|
|
has come true needs an instrument, not a second warning.
|
|
|
|
**The key is supplied by the caller, and must be conservative.** A decision key
|
|
identifies what the pipeline actually decided. Case *text* is the safe default:
|
|
two cases with identical text are indisputably the same decision. A tighter key
|
|
(e.g. the normalized propositional atom, which collapses spelling variants of one
|
|
question) reports *more* inflation. Text-identity therefore under-reports, which
|
|
is the correct direction for a claim of this kind — the measured gap is a floor on
|
|
the real gap, never an exaggeration of it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections import Counter
|
|
from collections.abc import Hashable, Iterable
|
|
from dataclasses import dataclass
|
|
|
|
from core.reliability_gate.floor import conservative_floor
|
|
|
|
#: The committed volume a *perfect* record needs to clear θ=0.99 under the pinned
|
|
#: ``WILSON_Z``. Derived, not chosen: the bound for ``successes == committed``
|
|
#: reduces to ``n / (n + z²)``, so ``n / (n + 6.635776) ≥ 0.99`` ⟺ ``n ≥ 656.93``.
|
|
#: Recomputed by :func:`volume_for_theta` rather than trusted as a constant.
|
|
SERVE_VOLUME_AT_THETA_099: int = 657
|
|
|
|
|
|
def volume_for_theta(theta: float) -> int:
|
|
"""Smallest perfect-record volume whose conservative floor reaches *theta*.
|
|
|
|
Derives the figure from :func:`conservative_floor` itself instead of
|
|
restating it, so a change to ``WILSON_Z`` cannot leave a stale number behind
|
|
in a docstring or a test. Search, not algebra, because the bound is rounded
|
|
to 1e-9 and the comparison downstream is the rounded one.
|
|
"""
|
|
if not 0.0 < theta < 1.0:
|
|
raise ValueError(f"theta must lie in (0, 1); got {theta!r}")
|
|
n = 1
|
|
while conservative_floor(n, n) < theta:
|
|
n *= 2
|
|
if n > 1 << 40: # pragma: no cover - unreachable for theta < 1
|
|
raise ValueError(f"no finite volume reaches theta={theta!r}")
|
|
low, high = n // 2, n
|
|
while low < high:
|
|
mid = (low + high) // 2
|
|
if conservative_floor(mid, mid) >= theta:
|
|
high = mid
|
|
else:
|
|
low = mid + 1
|
|
return low
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class EvidenceAudit:
|
|
"""What one band's practice volume is worth as evidence.
|
|
|
|
``claimed`` is the floor the ledger's own ``committed`` count produces —
|
|
what the gate sees today. ``honest`` is the floor over distinct decisions —
|
|
what a bound assuming independent trials is entitled to claim.
|
|
"""
|
|
|
|
band: str
|
|
committed: int
|
|
distinct: int
|
|
max_repeat: int
|
|
|
|
def __post_init__(self) -> None:
|
|
if self.committed < 0 or self.distinct < 0 or self.max_repeat < 0:
|
|
raise ValueError("counts must be non-negative")
|
|
if self.distinct > self.committed:
|
|
raise ValueError(
|
|
f"{self.band}: distinct ({self.distinct}) cannot exceed "
|
|
f"committed ({self.committed})"
|
|
)
|
|
if self.committed and not self.distinct:
|
|
raise ValueError(f"{self.band}: committed cases with no distinct keys")
|
|
|
|
@property
|
|
def claimed(self) -> float:
|
|
"""Floor from ``committed`` — assumes every case was a fresh trial."""
|
|
return conservative_floor(self.committed, self.committed)
|
|
|
|
@property
|
|
def honest(self) -> float:
|
|
"""Floor from distinct decisions — the defensible figure."""
|
|
return conservative_floor(self.distinct, self.distinct)
|
|
|
|
@property
|
|
def inflation(self) -> float:
|
|
"""``committed / distinct``. 1.0 means every case was a distinct decision."""
|
|
return round(self.committed / self.distinct, 9) if self.distinct else 0.0
|
|
|
|
def clears(self, theta: float) -> bool:
|
|
"""Does the *honest* floor reach *theta*? The question the gate should ask."""
|
|
return round(self.honest, 9) >= round(theta, 9)
|
|
|
|
|
|
def audit_band(band: str, keys: Iterable[Hashable]) -> EvidenceAudit:
|
|
"""Audit one band from the decision keys of its committed cases.
|
|
|
|
*keys* is one entry per committed case — repeats are the point, so this
|
|
takes an iterable of keys rather than a set.
|
|
"""
|
|
counts = Counter(keys)
|
|
committed = sum(counts.values())
|
|
return EvidenceAudit(
|
|
band=band,
|
|
committed=committed,
|
|
distinct=len(counts),
|
|
max_repeat=max(counts.values()) if counts else 0,
|
|
)
|
|
|
|
|
|
def audit_bands(cases_by_band: dict[str, Iterable[Hashable]]) -> tuple[EvidenceAudit, ...]:
|
|
"""Audit every band, ordered by band name for replay-stable reporting."""
|
|
return tuple(audit_band(band, cases_by_band[band]) for band in sorted(cases_by_band))
|
|
|
|
|
|
def below_floor(
|
|
audits: Iterable[EvidenceAudit], theta: float
|
|
) -> tuple[EvidenceAudit, ...]:
|
|
"""The audits whose honest floor does not reach *theta*, worst gap first."""
|
|
failing = [a for a in audits if not a.clears(theta)]
|
|
return tuple(sorted(failing, key=lambda a: (a.honest, a.band)))
|
|
|
|
|
|
def format_report(audits: Iterable[EvidenceAudit], theta: float) -> str:
|
|
"""A fixed-width report — the text a failing pin should print.
|
|
|
|
Assertion messages are the whole value of an audit that fails months from
|
|
now, so the numbers are formatted here rather than at each call site.
|
|
"""
|
|
rows = sorted(audits, key=lambda a: a.band)
|
|
need = volume_for_theta(theta)
|
|
lines = [
|
|
f"theta={theta} perfect-record volume needed={need}",
|
|
f"{'band':30s} {'committed':>9s} {'distinct':>8s} {'x':>6s} "
|
|
f"{'claimed':>8s} {'honest':>7s} clears",
|
|
]
|
|
for a in rows:
|
|
lines.append(
|
|
f"{a.band:30s} {a.committed:9d} {a.distinct:8d} {a.inflation:6.1f} "
|
|
f"{a.claimed:8.4f} {a.honest:7.4f} {'yes' if a.clears(theta) else 'NO'}"
|
|
)
|
|
return "\n".join(lines)
|
|
|
|
|
|
__all__ = [
|
|
"SERVE_VOLUME_AT_THETA_099",
|
|
"EvidenceAudit",
|
|
"audit_band",
|
|
"audit_bands",
|
|
"below_floor",
|
|
"format_report",
|
|
"volume_for_theta",
|
|
]
|