core/teaching
Shay c6a9bb0096
feat(ADR-0168/F1): FrameClaim ratification handler (Tier 1.5) (#389)
Implements the FrameClaim ratification handler per ADR-0168 doctrine
and the ADR-0168.1 MathFrameClaimProposal adapter.  Mirrors the
ADR-0167 W2-D LexicalClaim template (apply_lexical_claim) but lifts
the safe surface from drain-class lexical entries to allowlisted
frame-opening categories — the next sub-type up the wrong=0 hazard
ladder.

teaching/math_frame_proposal.py
  + MathFrameClaimProposal dataclass (ADR-0168.1 §"Data shape")
  + MathReaderRefusalEvidencePointer with source pinned to "math_audit"
  + build_evidence_pointer() — only sanctioned constructor; rejects None
    missing_operator
  + build_frame_claim_proposal() — enforces:
      • surface_form non-empty after normalization
      • frame_category in the ADR-0168 allowlist
      • polarity in {affirms, falsifies}
      • ≥1 evidence pointer with source="math_audit"
      • source="corpus" rejected as schema-illegal (ADR-0168.1
        §"Evidence floor")
  + compute_claim_signature() / compute_proposal_id() / canonical_bytes()
    — deterministic identity per ADR-0168 §"Replay obligations" #1

teaching/math_frame_ratification.py
  + SAFE_FRAME_CATEGORIES = {increment_frame, decrement_frame,
    transfer_frame, remainder_frame} — no other categories
  + Error hierarchy: RatificationError, WrongClaimSubType,
    WrongZeroViolationCandidate, AlreadyRatified, EvidenceTampering,
    UnknownCategory, InvalidPolarity, EvidenceLaundering
  + FrameRatificationReceipt dataclass with before/after SHA + evidence_hash
  + apply_frame_claim(claim, frame_category, polarity, reviewer, pack_root,
    evidence_source="math_audit"):
      • rejects evidence_source != "math_audit" (ADR-0168.1 §"Evidence floor")
      • rejects polarity outside {affirms, falsifies}
      • rejects claim.sub_type != "frame"
      • rejects evidence_hash tampering (recomputes from audit_row)
      • rejects frame_category outside SAFE_FRAME_CATEGORIES
      • writes language_packs/data/en_core_math_v1/frames/{category}.jsonl
      • idempotent: same (surface, category, polarity, evidence_hash)
        raises AlreadyRatified
      • duplicate evidence appends evidence_hash to existing row
        (ADR-0168.1 §"Idempotency" path #1)
      • polarity=falsifies records non-opener; never appends to compiled
        lexicon or manifest

language_packs/data/en_core_math_v1/frames/.gitkeep
  Directory scaffold for the reviewed frame source files.

workbench/readers.py
  _HANDLER_DISPATCH gains "frame_reclassification" → "FrameClaim".
  GET /math-proposals/{id} detail and POST /math-proposals/{id}/ratify
  now return suggested_cli pointing at apply_frame_claim().

core/cli.py
  teaching test-suite tuple gains tests/test_math_frame_ratification.py.

tests/test_math_frame_ratification.py — 14 tests:
   1. SAFE_FRAME_CATEGORIES is exactly the ADR-0168 allowlist
   2. apply writes a frame entry for a safe category
   3. receipt records before/after sha + evidence_hash
   4. idempotent same-evidence → AlreadyRatified
   5. rejects non-frame sub_type → WrongClaimSubType
   6. rejects categories outside SAFE_FRAME_CATEGORIES → WrongZeroViolationCandidate
   7. rejects invalid polarity → InvalidPolarity
   8. rejects evidence_hash tampering → EvidenceTampering
   9. rejects source="corpus" → EvidenceLaundering (ADR-0168.1 §"Evidence floor")
  10. case 0050 hazard pin — after ratification, case 0050 still refuses
  11. polarity=falsifies branch records non-opener; affirms+falsifies coexist
  12. duplicate evidence appends evidence_hash, does not create a second row
  13. manifest.json checksum unchanged by frame ratification
  14. alphabetical sort by surface_form preserved across writes

Suite verification
  core test --suite teaching -q → 47 passed (was 33; +14 new)
  core test --suite runtime  -q → 20 passed
  tests/test_math_lexical_ratification.py → 15 passed (untouched, regression-clean)
  tests/test_adr_0172_w4_workbench_e2e.py → 7 passed (existing dispatch tests still hold)

Doctrine invariants preserved
  - wrong=0: case 0050 still refuses after ratification
  - replay equivalence: claim_signature and proposal_id are deterministic
    (sha256 of canonical identity, clock-time-independent)
  - refusal-first: no runtime mutation; handler is the only mutation
    boundary and writes only the reviewed frames/ source tree
  - ADR-0167 partition: math-audit evidence stays math-domain; corpus
    evidence is rejected loudly

Brief-correction note: the brief named the scaffold path
"packs/en_core_math_v1/frames/.gitkeep" but the existing math pack lives
at language_packs/data/en_core_math_v1/ (no top-level packs/en_core_math_v1
exists).  Scaffold placed at language_packs/data/en_core_math_v1/frames/
to mirror the existing lexicon/ source-tree convention; apply_frame_claim
defaults pack_root to that location.
2026-05-27 14:10:43 -07:00
..
admissibility_exemplars feat(ADR-0163.B.2): four new exemplar corpora — discrete_count_statement, multiplicative_aggregation, currency_amount, plus temporal_aggregation v2 widening (#306) 2026-05-26 14:36:59 -07:00
cognition_chains chore(ratify): accept four Phase C round-2 recognizers (round 2) (#309) 2026-05-26 16:03:01 -07:00
cross_pack_chains feat(adr-0067): cross-pack teaching chains — Plan Phase 4 closed 2026-05-18 17:22:43 -07:00
domain_chains Add chain-first capability ledger and domain seeds (#97) 2026-05-20 21:33:24 -07:00
math_corpora feat(ADR-0131.2.B): B2 teaching-corpus enrichment — load-bearing gate (#177) 2026-05-23 11:29:48 -07:00
math_proposals feat(ADR-0172/W3): core eval math-contemplation CLI lane (#384) 2026-05-27 12:58:31 -07:00
proposals chore(ratify): accept four Phase C round-2 recognizers (round 2) (#309) 2026-05-26 16:03:01 -07:00
relations_chains content(en_core_relations_v1): +14 kinship/social lemmas + +14 chains, cognition eval byte-identical, ratify-idempotent (#211) 2026-05-23 22:47:53 -07:00
relations_chains_v2 feat(packs): en_core_relations_v2 — pronouns + role-fillers (Phase 2.4) 2026-05-18 16:42:02 -07:00
__init__.py chore(teaching): MetricSet dataclass (ADR-0142 debt #3) (#231) 2026-05-24 15:15:02 -07:00
audit.py feat(adr-0057): operator supersession history view — closes the supersede loop 2026-05-18 10:40:38 -07:00
contemplation.py fix(ADR-0167): route contemplation and proposal replay by candidate domain (#363) 2026-05-27 09:43:16 -07:00
correction.py
cross_pack_supersede.py feat(phase5+bench): cross-pack supersede + articulation benchmark suite 2026-05-18 17:44:59 -07:00
discovery.py feat(ADR-0167/W2-C): domain discriminator + cross-domain audit (#351) 2026-05-27 06:44:29 -07:00
discovery_sink.py feat(adr-0055): Phase B — DiscoveryCandidate emission from turn loop 2026-05-18 08:26:04 -07:00
epistemic.py feat(adr-0021): epistemic_status surface wired across teaching + trace 2026-05-16 20:20:35 -07:00
exemplar_ingest.py feat(ADR-0163.C.2): extend exemplar ingest + synthesis + matchers for round-2 categories (#307) 2026-05-26 15:08:41 -07:00
from_curriculum.py feat(teaching): ADR-0104 — curriculum-sourced teaching proposals (#107) 2026-05-22 10:05:14 -07:00
from_miner.py feat(teaching): implement ADR-0095 — Miner-Sourced Teaching Proposals 2026-05-21 18:18:51 -07:00
gaps.py feat(teaching): discovery gaps aggregator + auto-promotion queue (Phase 1.1+1.2) 2026-05-18 16:04:39 -07:00
math_claim_signature.py feat(ADR-0167/W2-B): lexical claim signature + dedup (#353) 2026-05-27 06:56:36 -07:00
math_contemplation.py feat(ADR-0172/tightening): three follow-ups — self-contained JSONL, widened dispatch, shape_category gap (#386) 2026-05-27 13:43:16 -07:00
math_contemplation_proposal.py feat(ADR-0172/tightening): three follow-ups — self-contained JSONL, widened dispatch, shape_category gap (#386) 2026-05-27 13:43:16 -07:00
math_evidence.py feat(ADR-0167/W1-A): MathReaderRefusalEvidence schema + canonical-bytes (#350) 2026-05-27 06:30:21 -07:00
math_frame_proposal.py feat(ADR-0168/F1): FrameClaim ratification handler (Tier 1.5) (#389) 2026-05-27 14:10:43 -07:00
math_frame_ratification.py feat(ADR-0168/F1): FrameClaim ratification handler (Tier 1.5) (#389) 2026-05-27 14:10:43 -07:00
math_inference_proposal.py feat(ADR-0172/W5): MathReaderInferenceProposal schema (Tier 2) (#388) 2026-05-27 14:01:50 -07:00
math_lexical_ratification.py feat(ADR-0167/W2-D): lexical ratification handler (#354) 2026-05-27 06:57:37 -07:00
math_reasoning_trace.py feat(teaching/W0): ReasoningTrace substrate for ADR-0172 Tier 1 (#379) 2026-05-27 12:21:59 -07:00
metric_set.py chore(teaching): MetricSet dataclass (ADR-0142 debt #3) (#231) 2026-05-24 15:15:02 -07:00
migrate_proposals_source_field.py feat(teaching): implement ADR-0094 — Proposal Source Provenance 2026-05-21 18:11:09 -07:00
oov_gaps.py feat(teaching): OOV signal flywheel — sink, aggregator, auto-promotion (Phase 2.3) 2026-05-18 16:42:26 -07:00
oov_promotion.py feat(teaching): OOV signal flywheel — sink, aggregator, auto-promotion (Phase 2.3) 2026-05-18 16:42:26 -07:00
oov_sink.py feat(teaching): OOV signal flywheel — sink, aggregator, auto-promotion (Phase 2.3) 2026-05-18 16:42:26 -07:00
promotion.py feat(teaching): discovery gaps aggregator + auto-promotion queue (Phase 1.1+1.2) 2026-05-18 16:04:39 -07:00
proposals.py fix(ADR-0167): route contemplation and proposal replay by candidate domain (#363) 2026-05-27 09:43:16 -07:00
provenance.py feat(adr-0055): Phase A — teaching corpus audit, supersession, typed provenance 2026-05-18 08:15:23 -07:00
queue.py feat(ADR-0161.2): HITL queue backpressure — pending-count cap + queue_full reports (#311) 2026-05-26 16:16:08 -07:00
recognizer_synthesis.py feat(ADR-0163.C.2): extend exemplar ingest + synthesis + matchers for round-2 categories (#307) 2026-05-26 15:08:41 -07:00
relation_parse.py feat(phase3): transitive_walk + path_recall operator bundle (ADR-0018) 2026-05-16 15:04:43 -07:00
replay.py feat(ADR-0163.C): contemplation ingests admissibility exemplars and emits DerivedRecognizer proposals through the HITL corridor (#301) 2026-05-26 12:26:56 -07:00
review.py fix(gaps): close G1+G2+G3 + identity vocab + pipeline safety-stub honour 2026-05-16 21:21:06 -07:00
source.py feat(ADR-0163.C): contemplation ingests admissibility exemplars and emits DerivedRecognizer proposals through the HITL corridor (#301) 2026-05-26 12:26:56 -07:00
store.py feat(teaching): implement ADR-0094 — Proposal Source Provenance 2026-05-21 18:11:09 -07:00
supersede.py feat(adr-0057): operator supersede CLI — retire active chain by appended replacement 2026-05-18 10:35:49 -07:00