core/formation/course.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

159 lines
4.4 KiB
Python

"""Frozen dataclasses for every Formation Pipeline artifact.
These are pure data carriers — no behavior, no IO. Each carries a
``schema_version`` so future migrations can detect mismatch at load time.
Serialization is via canonical JSON (``formation.hashing.canonical_json``).
SHA-256 of the canonical form is the content address.
Trust regions, left to right:
OreBundle (UNTRUSTED)
ValidatedTripleSet (REVIEWED — passed the Forge)
CourseYAML (REVIEWED — composed from validated triples)
FormationPlan (REVIEWED — compiled from CourseYAML)
MasteryReport (RATIFIED — self-sealed; only this authorizes promote)
"""
from __future__ import annotations
from dataclasses import dataclass, field
from formation.candidate import (
ConceptCandidate,
CounterCandidate,
OrderingHint,
RelationCandidate,
)
SCHEMA_VERSION: str = "1.0.0"
@dataclass(frozen=True, slots=True)
class SubjectSpec:
"""The one human-authored artifact in the chain.
Generated by ``core formation new <subject_id>`` as a YAML stub; edited
by the user; loaded into this dataclass for everything downstream.
"""
subject_id: str
title: str
target_depth: str # e.g. "introductory", "working", "expert"
requires_courses: tuple[str, ...] = ()
anti_requisites: tuple[str, ...] = ()
identity_axis_constraints: tuple[str, ...] = ()
schema_version: str = SCHEMA_VERSION
@dataclass(frozen=True, slots=True)
class OreEntry:
"""A single mined source: URL, bytes-SHA, retrieval metadata."""
source_sha: str
url: str
adapter: str
retrieved_at: str # ISO-8601 UTC
byte_length: int
citation: str = ""
@dataclass(frozen=True, slots=True)
class OreBundle:
"""The output of Stage 1 (Mining). Untrusted material."""
subject_id: str
entries: tuple[OreEntry, ...]
schema_version: str = SCHEMA_VERSION
@dataclass(frozen=True, slots=True)
class ValidatedTripleSet:
"""The output of Stage 3 (Forge). First artifact the rest of CORE can lawfully see.
Every entry here has passed every Forge rule and carries
``EpistemicStatus.SPECULATIVE`` once handed to the teaching layer.
"""
subject_id: str
concepts: tuple[ConceptCandidate, ...]
relations: tuple[RelationCandidate, ...]
counters: tuple[CounterCandidate, ...]
ordering_hints: tuple[OrderingHint, ...]
quarantined: tuple[RelationCandidate, ...] = ()
schema_version: str = SCHEMA_VERSION
@dataclass(frozen=True, slots=True)
class CourseYAML:
"""The output of Stage 4 (Compose). Deterministic, byte-stable."""
course_id: str
yaml_bytes: bytes
course_sha256: str
source_bundle_sha: str
validated_set_sha: str
template_id: str
template_version: str
schema_version: str = SCHEMA_VERSION
@dataclass(frozen=True, slots=True)
class PlanStep:
"""One step of a FormationPlan.
``step_type`` is one of:
"seed_concept", "introduce_relation", "walk_step",
"adversarial_probe", "replay_assertion".
``payload`` is a JSON-serializable dict; floats are forbidden.
"""
step_type: str
payload: dict[str, object]
@dataclass(frozen=True, slots=True)
class FormationPlan:
"""The output of Stage 5 (Compile). Deterministic given the same CourseYAML."""
course_id: str
course_sha256: str
steps: tuple[PlanStep, ...]
plan_sha256: str
schema_version: str = SCHEMA_VERSION
@dataclass(frozen=True, slots=True)
class GateMeasurement:
"""One gate's outcome at ratification time.
Numeric values are stringified to keep canonical JSON deterministic.
"""
name: str
passed: bool
measurement: str # stringified numeric or descriptor
threshold: str = ""
@dataclass(frozen=True, slots=True)
class MasteryReport:
"""The output of Stage 7 (Ratify). Self-sealed cryptographic receipt.
``report_sha256`` is the SHA over the JSON body with ``report_sha256``
blanked. See ``formation.hashing.self_seal`` / ``verify_seal``.
"""
course_id: str
source_bundle_sha: str
validated_set_sha: str
course_sha256: str
plan_sha256: str
gates: tuple[GateMeasurement, ...]
trace_hashes: tuple[str, ...]
ratified: bool
report_sha256: str = ""
schema_version: str = SCHEMA_VERSION
issued_at: str = "" # ISO-8601 UTC, set at emission
# Failure reasons accumulate when ``ratified`` is False; empty otherwise.
failure_reasons: tuple[str, ...] = field(default_factory=tuple)