"""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 `` 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)