core/chat/curriculum_serve_license.py
Shay 0a17c49693 refactor(learning): extract the ratified-ledger bridge from its three instances (ADR-0263)
Phase 3.3 of the generalization arc. Estimation (ADR-0175), deduction
serving (ADR-0256) and curriculum serving (ADR-0262) had each written the
same seal -> ratify -> SHA-verify -> serve-gate machinery. core/ratified_ledger.py
now owns it and states the four rules once: only sealed practice writes;
tamper-evidence is structural (a load that cannot reproduce content_sha256
REFUSES); ceilings are not negotiable at the call site; absent evidence is
never a license.

Each capability keeps a thin adapter that names its artifact and preserves
its public API. One real difference is now declared rather than implied:
missing_ok distinguishes a ledger a capability SHIPS with (absence = broken
deployment, refuse) from one whose practice volume is still being built
(absence = nothing earned yet, serve disclosed) — curriculum serving is the
second kind today.

Safety property is byte-identity, asserted not assumed: re-sealing the
committed 25-band deduction ledger through the bridge reproduces it
byte-for-byte, so no artifact and no lane pin moves.

Effect: a new subject arena now needs a gold corpus and a band key, not a
re-implementation of ratification — which is what §3 meant by sequencing
the bridge ahead of the second subject.

[Verification]: tests/test_ratified_ledger_bridge.py 8 passed; core test
--suite deductive 252 passed; estimation/license test set 355 passed;
committed deduction ledger byte-identical after reseal.
2026-07-24 14:45:16 -07:00

68 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Serving-side SERVE license for curriculum-grounded answers (ADR-0262).
Reads the **ratified, committed** curriculum-serve ledger
(``chat/data/curriculum_serve_ledger.json``) and exposes, per *(subject ×
relation family)* band, whether the FULL serving pipeline (curriculum
compiler → argument reader → ROBDD engine) has earned ``Action.SERVE`` under
the safe default ceilings (θ_SERVE=0.99). The engine READS this artifact; it
never writes it — the sealed-practice output of
``evals.curriculum_serve.practice.runner.seal_ledger`` is the only writer, and
its ``content_sha256`` is verified on load so a hand-edited ledger is rejected
rather than silently trusted.
The third instance of the seal → ratify → SHA-verify → serve-gate pattern, and
the one that made the shared bridge worth extracting: this module is now an
ADAPTER over ``core.ratified_ledger`` (ADR-0263). It names the artifact, keeps
the memoization, and declares the one thing that genuinely differs — this
ledger is legitimately ABSENT, because no curriculum band has earned anything
yet (ADR-0262 §5.1: the binding constraint is ratified curriculum volume). An
absent ledger reads as an empty table, so every answer is served DISCLOSED.
"""
from __future__ import annotations
from functools import lru_cache
from pathlib import Path
from core.ratified_ledger import (
RatifiedLedgerError as RatifiedCurriculumLedgerError,
load_sealed_ledger,
serve_license,
)
from core.reliability_gate import Ceilings, ClassTally, LicenseDecision
_LEDGER_PATH = Path(__file__).resolve().parent / "data" / "curriculum_serve_ledger.json"
@lru_cache(maxsize=1)
def load_ratified_ledger() -> dict[str, ClassTally]:
"""Load + verify the ratified curriculum-serve ledger → per-band tallies.
An ABSENT ledger is not an error here: no curriculum band has earned
anything yet, and the honest reading of "no file" is "no committed
evidence", which the gate turns into a disclosed answer rather than a
withheld one.
"""
return load_sealed_ledger(_LEDGER_PATH, missing_ok=True)
def curriculum_serve_license(
band: str,
*,
ledger: dict[str, ClassTally] | None = None,
ceilings: Ceilings | None = None,
) -> LicenseDecision | None:
"""The ``Action.SERVE`` license for a curriculum band, or ``None``.
``None`` means the band has no committed evidence → never licensed; the
caller serves a disclosed (hedged) surface, the safe default.
"""
ledger = ledger if ledger is not None else load_ratified_ledger()
return serve_license(band, ledger, ceilings=ceilings)
__all__ = [
"RatifiedCurriculumLedgerError",
"curriculum_serve_license",
"load_ratified_ledger",
]