core/formation/mastery.py
Shay 64c5bc4619 feat(epistemic): truth-seeking schema audit — 3 leaks closed, 4 new lanes, 3 new invariants
Audit of the one-mutation-path invariant (ADR-0021 §3) found three leaks
where pack authority or session-state writes could substitute for coherence
judgment. All three landed fixes or partial closures in this push.

Leaks closed:
- Leak A: pack vocab defaulted to COHERENT — flipped to SPECULATIVE in
  language_packs/{compiler,schema}.py; docstring corrected to align with
  ADR-0021 (it was rationalizing the leak).
- Leak B: vault.recall was epistemic-blind — VaultStore.store() now stamps
  every entry with EpistemicStatus (default SPECULATIVE); recall(min_status=)
  filters to admissible-as-evidence tier. All 4 vault-write sites updated.
- Leak C (write-side): generate/proposition.py:198 stored articulated
  propositions unmarked — now stamps SPECULATIVE, breaking the
  fabrication-feedback loop in principle. Read-side audit of 5 call sites
  is the residual.

New architectural invariants (tests/test_architectural_invariants.py):
- INV-21: one-mutation-path allowlist (caught Leak C on first run)
- INV-22: pack lexicon default is SPECULATIVE (Leak A guard)
- INV-23: vault recall epistemic-aware (Leak B guard)

New eval lanes:
- teaching_injection_resistance — ships GREEN at 1.00/1.00/0 (the
  structural anti-injection claim is real and measurable)
- refusal_calibration — honest gap: 0% refusal, 0% fabrication
- contradiction_detection — honest gap: 50% flag via versor-delta heuristic,
  100% false-positive; motivates the proper coherence-checker
- articulation_of_status — honest gap: 0% speculative articulation, 60%
  false certainty; output-side leak surface

New benchmarks:
- benchmarks/footprint.py — total deployed runtime is 7.06 MiB
  (109,358x smaller than Llama 3.1 405B, runs offline, no GPU)
- benchmarks/learning_curve.py — monotonic + replay-deterministic curve
  per lane

Documentation:
- docs/truth_seeking_schema.md — foundational architectural commitment,
  five rules, mapped to human failure modes, leaks published openly
- evals/CLAIMS.md — five-tier public claims doc; Tier 4.5 publishes
  known gaps with named fixes; verification contract at top
- README.md — new pillar between algebraic substrate and language pillar

Includes in-flight formation pipeline scaffolding (formation/, tests/formation/,
docs/formation_pipeline_plan.md) and minor CLI/contracts/gitignore edits
that were already in the working tree at session start.

Verification: 798 passed, 2 skipped, 1 deselected (pre-existing pack-count
test drift unrelated to schema changes).
2026-05-17 07:27:41 -07:00

103 lines
3.4 KiB
Python

"""``MasteryReport`` self-sealing and emission helpers.
A ``MasteryReport`` is the cryptographic receipt at the end of Stage 7
(Ratify). It is the only artifact whose SHA authorizes Stage 8 (Promote).
The seal works by computing SHA-256 over the canonical JSON of the report's
dict form with ``report_sha256`` blanked to the empty string, then writing
the SHA into the field. ``verify_seal`` reproduces the process. See
``formation/hashing.py`` for the primitive.
"""
from __future__ import annotations
from datetime import datetime, timezone
from typing import Any
from formation.course import GateMeasurement, MasteryReport
from formation.hashing import self_seal, verify_seal
def _iso_utc_now() -> str:
"""Return current time as a stable ISO-8601 UTC string with no microseconds."""
return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace(
"+00:00", "Z"
)
def report_to_dict(report: MasteryReport) -> dict[str, Any]:
"""Project a ``MasteryReport`` to a canonical-JSON-safe dict."""
return {
"schema_version": report.schema_version,
"course_id": report.course_id,
"source_bundle_sha": report.source_bundle_sha,
"validated_set_sha": report.validated_set_sha,
"course_sha256": report.course_sha256,
"plan_sha256": report.plan_sha256,
"gates": [
{
"name": g.name,
"passed": g.passed,
"measurement": g.measurement,
"threshold": g.threshold,
}
for g in report.gates
],
"trace_hashes": list(report.trace_hashes),
"ratified": report.ratified,
"issued_at": report.issued_at,
"failure_reasons": list(report.failure_reasons),
"report_sha256": report.report_sha256,
}
def emit_report(
*,
course_id: str,
source_bundle_sha: str,
validated_set_sha: str,
course_sha256: str,
plan_sha256: str,
gates: tuple[GateMeasurement, ...],
trace_hashes: tuple[str, ...],
failure_reasons: tuple[str, ...] = (),
issued_at: str | None = None,
) -> MasteryReport:
"""Emit a fully-sealed ``MasteryReport``.
``ratified`` is derived: True iff every gate passed.
"""
ratified = all(g.passed for g in gates) and not failure_reasons
when = issued_at if issued_at is not None else _iso_utc_now()
draft = MasteryReport(
course_id=course_id,
source_bundle_sha=source_bundle_sha,
validated_set_sha=validated_set_sha,
course_sha256=course_sha256,
plan_sha256=plan_sha256,
gates=gates,
trace_hashes=trace_hashes,
ratified=ratified,
report_sha256="",
issued_at=when,
failure_reasons=failure_reasons,
)
sealed = self_seal(report_to_dict(draft), sha_field="report_sha256")
return MasteryReport(
course_id=course_id,
source_bundle_sha=source_bundle_sha,
validated_set_sha=validated_set_sha,
course_sha256=course_sha256,
plan_sha256=plan_sha256,
gates=gates,
trace_hashes=trace_hashes,
ratified=ratified,
report_sha256=sealed["report_sha256"],
issued_at=when,
failure_reasons=failure_reasons,
)
def verify_report(report: MasteryReport) -> bool:
"""Return True iff ``report.report_sha256`` matches its self-sealing SHA."""
return verify_seal(report_to_dict(report), sha_field="report_sha256")