core/docs/plans/curriculum-license-loop-2026-07-25.md
Shay 55a3f79f18 docs(arc): curriculum-license-loop plan of record + tier division of work
Two prior arcs closed on "the binding constraint is ratified curriculum volume,
not machinery." Verified against code 2026-07-25: the machinery half is wrong in
a load-bearing way, and the correction is the reason this arc exists.

evals/curriculum_serve/practice/ does not exist. seal_ledger exists only for
deduction (evals/deduction_serve/practice/runner.py:96), yet
chat/curriculum_serve_license.py's own docstring names
evals.curriculum_serve.practice.runner.seal_ledger as "the only writer" of the
artifact it reads -- that writer was never built, and
chat/data/curriculum_serve_ledger.json does not exist. And the ceremony stops
short: RatificationReceipt.pending_stages = (arena_queue_entry, ledger_reseal).

So the pipeline is author -> ratify -> ??? -> ??? -> license -> serve. Authoring
curriculum today cannot earn a license at ANY volume. Content is necessary and
currently insufficient. The build is still modest, because oracle.py is already
an independent decision procedure usable as the gold tether and ADR-0263 already
extracted the sealers for exactly a third instance.

Two measured facts shape the content work. `refuted` has NEVER been produced --
the physics lane gold is entailed 14 / unknown 12 / declined 6, and no corpus row
can express it. And bands key on (domain, operator_family), so negative content
must live INSIDE operator_family "modal" with a row-level polarity marker; a
separate modal_negative family would create a new band at n=0 instead of adding
refuted volume to the target band -- the easiest available way to waste the whole
authoring effort.

DIVISION-OF-WORK.md records the tiering criterion and why it is not difficulty.
The evidence does not support a prestige split: in the same 48h window Sonnet 5
found the DEFAULT_SINK bug that wrote outside the repository and did the
six-worktree public_demo archaeology, while Opus 5 mis-diagnosed the CGA hot path
by multiplying a microbenchmark by a call count. Model tier was not the variable;
verification discipline was.

The split is therefore: would an error here be caught by a gate, or is it silent?
Two units are silent-failure BECAUSE THEY ARE THE GATE -- the negative-curriculum
epistemology (wrong => corpus encodes falsehoods and wrong=0 still passes, since
lane gold and the oracle both read the same rows) and the volume-honesty invariant
(wrong => conservative_floor cannot tell 657 independent facts from 16 asked 41
times, so the ledger clears theta=0.99 having earned nothing). Those get Opus.
Everything loud goes to the cheapest competent tier.

Also records the ordering correction: the epistemology ADR must precede the
generator, or the generator gets built twice.

[Verification]: docs-only; no code paths touched. Every referenced path confirmed
to exist and all five line citations confirmed accurate at HEAD (gold.py:1163,
curriculum_serve/runner.py:71, discovery_yield.py:67-70, entail.py:125,
curriculum_surface.py:184). Pre-push gate runs on push.
2026-07-25 15:09:09 -07:00

9.6 KiB
Raw Blame History

Curriculum License Loop — Plan of Record

Date: 2026-07-25 · Status: ACTIVE · Base: main @ 0a26787f (post ADR-governance pin, PR #114)

Successor to generalization-arc-2026-07-24.md, which closed its Tier F/O/S arc, and to the assessment-verification arc (PR #113). Division of work across tiers: docs/handoff/curriculum-license-loop-2026-07/DIVISION-OF-WORK.md (binding — read it before starting any unit).


1. Why this arc exists

Two arcs closed on the same stated conclusion: the binding constraint is ratified curriculum volume, not machinery. That conclusion is half right, and the wrong half is load-bearing. Verified 2026-07-25 by reading code:

  1. evals/curriculum_serve/practice/ does not exist. The deduction analogue (evals/deduction_serve/practice/{gold,runner}.py) is what folds run_practice over a corpus into per-band ClassTally. Curriculum has no producer.
  2. seal_ledger exists only for deduction (evals/deduction_serve/practice/runner.py:96). chat/curriculum_serve_license.py's own docstring names evals.curriculum_serve.practice.runner.seal_ledger as "the only writer" of the artifact it reads. That writer was never built, and chat/data/curriculum_serve_ledger.json does not exist.
  3. The ceremony stops short. teaching/ratification.py::RatificationReceipt carries pending_stages = ("arena_queue_entry", "ledger_reseal") — it grows the corpus and explicitly neither practices it nor reseals the ledger.

So the pipeline is author → ratify chain → ??? → ??? → license → serve, with two unbuilt segments. Authoring curriculum today cannot earn a license at any volume. Content is necessary and currently insufficient.

The build is nonetheless modest, because the expensive pieces already exist: evals/curriculum_serve/oracle.py is already an independent decision procedure usable as the gold tether, and ADR-0263 already extracted the sealers (core/ratified_ledger.py) for precisely a third instance.

2. Two measured facts that shape the content work

  • refuted has never been produced. The physics lane gold is entailed 14 / unknown 12 / declined 6 — zero refuted. The verdict exists in CurriculumDecision.verdict; no corpus row can express it.
  • Bands key on (domain, operator_family) (chat/curriculum_surface.py:184). Negative content must therefore live inside operator_family: "modal" with a row-level polarity marker. A separate modal_negative family would create a new band at n=0 instead of adding refuted volume to the target band. This is the easiest available way to waste the entire authoring effort.

3. Decisions taken (2026-07-25, Shay)

Decision Choice
Leading track Close the license loop (not articulation, not substrate)
First content target physics · modal — n=9, closest of eleven bands (24× short)
refuted representation Explicit negative edges, polarity inside the existing family
Reseal trigger Explicit core proposal-queue reseal verb, never automatic on ratify

Reseal is explicit because AGENTS.md forbids ratification automation, and because an auto-reseal per ratified row would churn the ledger's content_sha256 on every append.

4. Phases

Phase A — Negative-curriculum epistemology (design only; gates everything)

ADR deciding how an explicitly-taught negative coexists with the open-world reading. Binding constraints: absent edge ⇒ UNKNOWN (never "no"); explicit negative edge ⇒ REFUTED; polarity is a row-level field or intent value, never a new operator_family; evals/curriculum_serve/oracle.py must learn polarity independently of the serving path, since that independence is the whole evidentiary value.

Touches: teaching/domain_chains/physics_chains_v1.jsonl schema, teaching/curriculum_premises.py, teaching/ratification.py::validate_admissible, evals/curriculum_serve/oracle.py, lane contract anti-recall probes.

Done when: ADR Accepted; schema shape fixed; no code written.

Phase B — The volume-honesty invariant (the anti-gaming gate)

Failing tests written before any producer code. The generator must emit at most one committed case per distinct (relation, direction, polarity, question-shape) tuple and must never paraphrase-pad. S6 already proved conservative_floor cannot distinguish "657 independent facts" from "16 facts asked 41 times," so an unbounded generator would clear the Wilson floor without earning anything.

Done when: tests exist, fail for the right reason, and fail under mutation (pad the generator ⇒ red).

Phase C — The producer (implementation against Phase B)

evals/curriculum_serve/practice/{__init__,generator,runner}.py, mirroring evals/deduction_serve/practice/ topology exactly — producer in evals/, artifact next to its reader in chat/data/.

Reuse, do not rewrite: evals/curriculum_serve/oracle.py (gold tether), core/learning_arena/engine.py::run_practice, core/ratified_ledger.py::{seal_artifact, tally_dict, write_sealed_ledger}, core/reliability_gate::{Action, Ceilings, ClassTally, license_for}, chat/curriculum_surface.py (solver under test).

Done when: Phase B tests green; wrong=0 on the physics lane.

Phase D — Close the ceremony's pending_stages

core proposal-queue reseal verb; ratify_chain records the enqueue. Files: teaching/ratification.py, core/cli_proposal_queue.py.

Done when: the verb produces a SHA-sealed chat/data/curriculum_serve_ledger.json, and curriculum_serve_license() reads a real (still-unearned) ledger rather than an absent one.

Phase E — Honesty seams (parallel, no dependency on AD)

  • E1 — audit-ledger R7. Defer the single sink emission to the pipeline serve boundary (chat/runtime.py::finalize_turn_surface; spec at docs/specs/runtime_contracts.md:448-456). Repairs the stale surface and stale trace_hash together. Default sink is None, so no deployment risk. Independent of the hash_surface-on-TurnEvent ruling.
  • E2 — assert_corpus_sound name collision. Two functions, one name: evals/deduction_serve/practice/gold.py:1163 (no args, practice corpus) vs evals/curriculum_serve/runner.py:71 (domain, cases, lane contract). Must land before Phase C adds a third caller.
  • E3 — ADR status vocabulary normalization. 27 unparseable status lines plus draft/ratified/active/accepted. variants across 312 files; then widen tests/test_adr_status_governance.py to a closed vocabulary.

Phase F — Content (the actual constraint)

Author + ratify physics · modal volume: ≈219 distinct taught modal relations for the entailed bucket, plus matching refuted/unknown. Measure with teaching.ratification._count_chains and evals/vocab_trigger_instrument.py --compare admissions delta.

Relations must be true. Drafting candidates is delegable; ratification is Shay's.

Phase G — The flag (Shay only)

Only after a band clears θ=0.99 at n≥657 with a genuine outcome mix: propose flipping curriculum_serving_enabled. On earned evidence, never on proximity.

5. Deferred, decision-gated (a ruling, not effort)

  • Band-level capability index — 25 near-1.0 entries would inflate coverage_geomean against the index's own anti-gaming property. Needs a scoring decision before any schema change.
  • Discovery-yield stratification — blocked on new persisted per-source counters in the engine_state manifest (teaching/discovery_yield.py:67-70 reads one monotonic turn_count).
  • hash_surface on TurnEvent — self-verifying telemetry vs replay-only. Current contract states recomputation is unsupported and correct to be so.

6. Off this arc's critical path

  • Articulation depth (Phase 5 / core_logos). EntailmentTrace carries five opaque BDD node keys; generate/proof_chain/entail.py:125-190 decides via is_tautology. There are no intermediate steps, so nothing is dropped and the stated trigger describes an event that cannot occur. CORE's decision procedure is complete but not explanatory. Next deliverable is a feasibility study for proof-term extraction over the ROBDD — a derivation calculus with a real soundness surface, not a data-structure refactor. Highest intellectual value, least schedulable.
  • Substrate. CORE_BACKEND=rust bit-exact parity is now answerable locally (cargo 1.97.1 + registry cache present; core-rs/tests/test_crdt_hash_parity.rs exists; needs PYO3_PYTHON=/opt/homebrew/bin/python3.12). Then Rust typestate (UnverifiedClaimVersorClaim) — zero determinism cost, greenfield. The real hot path is cga_innergeometric_product, 33,986 calls/turn, ~73% of turn time. Not the diagonal shortcut — not bit-exact (954/4000 in f32). Refuted, do not revisit: .metal kernel, MLX fusion, bf16.
  • Math. Phase 4.2 case-first is falsified on a count — cases 0000/0001/0148/0082 affect 1 and 2 cases out of 500. Only remaining lever is the q:complex decomposition study (101 cases, one label). Low expected value.

7. Dependencies

  • A gates B (polarity shapes the generator's enumeration — building C before A means building it twice).
  • B gates C (tests first; the invariant is the specification).
  • E2 lands before C. E1/E3 fully parallel.
  • C + D gate F's measurement, and F gates G.
  • Phase 6 items independent and parallel throughout.

8. Non-goals

  • Flipping any flag without explicit ratification.
  • Adding band entries to the capability index before the scoring decision.
  • Paraphrase-padding practice volume to reach the Wilson floor.
  • Renumbering or overwriting Accepted ADRs.