core/generate
Shay 7441b42bf5 feat(wave-a): first non-DCS injector — multiplicative_aggregation w/ value extraction
Addresses 5 of 47 train_sample "recognizer matched but produced no
injection" refusals (the largest single failure-mode bucket
identified in RAT-1's audit).

Modules
-------
- generate/recognizer_match.py:
  - _MULT_AGG_EACH_WEIGHING_RE — regex for "<Subject> <bake-verb>
    <M> <outer-noun>, each <weigh-verb>ing <N> <unit>" pattern
  - _try_extract_each_weighing_anchor — extracts M, N, subject,
    inner unit; emits pre-composed CandidateInitial(value=M*N) with
    composition_evidence so RAT-1's _composed_initial_admissible
    gate verifies INPUT tokens ground (preserves wrong=0)
  - _match_multiplicative_aggregation dispatches to the value
    extractor when spec carries extract_values=True; specs without
    that flag get the existing detection-only return path
    (byte-identical legacy behavior)

- generate/recognizer_anchor_inject.py:
  - inject_multiplicative_aggregation — new per-category injector;
    narrow by anchor.kind so ME-3/ME-4 additive/subtractive anchors
    (which share the same matcher entry point) continue to flow
    through composition_registry consult instead of WAVE-A's direct
    path
  - registered in _INJECTORS dict (2nd entry after DCS)

- core/cli.py:
  - seed-recognizer CLI gains --extract-values flag to opt the
    canonical_pattern into the value-extracting matcher path

Seeded artifacts
----------------
- proposals.jsonl: rat1-seed-4dc30608fb783bc7 — multiplicative_
  aggregation recognizer with anchor_kind=multiplicative_aggregate,
  extract_values=True, observed_units covering ounces/strawberries/
  questions/etc.

Live result on train_sample
---------------------------
- wrong == 0 preserved (3/47/0 baseline)
- Case 0050 hazard pin held
- public 150/150 preserved
- packs suite: 127 → 131 (+4 new WAVE-A tests, all green)
- teaching suite 93 unchanged
- runtime suite 20 unchanged

End-to-end synthetic solve (FIRST WAVE-A admission):
  "Lilibeth fills 6 baskets where each basket holds 50 strawberries.
   How many strawberries does Lilibeth have?"  → answer=300

Cases that moved (statement now admits; refusal shifted downstream):
- Case 0025 (Lilibeth): statement admits via WAVE-A; refusal moved
  to question parser ("If three of Lilibeth's friends pick the same
  amount, how many strawberries do Lilibeth and her friends pick in
  all?")
- Case 0047 (John bakes 12 macaroons): statement 1 admits; refusal
  moved to statement 2

Eval correct count unchanged because the QUESTION parser (and
multi-statement cross-sentence reasoning) is the next bottleneck.
RAT-1's audit identified that gap; WAVE-A closes the injector half.

The remaining 3 multiplicative_aggregation refusals (0006, 0013,
0045) have different shape patterns the WAVE-A regex does not yet
cover; they're follow-up matcher extensions in the same architecture.

Tests
-----
- tests/test_wave_a_multiplicative_aggregation_injector.py (10
  tests): each-weighing + each-basket-holds admission shapes,
  detection-only path preserved when extract_values absent,
  unobserved unit / pronoun / zero count refusals, end-to-end
  inject_from_match dispatch, the Lilibeth canary solve,
  wrong=0 preserved, case 0050 hazard pin

Stacks on PR #406 (RAT-1).
2026-05-27 20:50:04 -07:00
..
binding_graph feat(binding-graph): Phase 4 question-target binding (ADR-0135) (#179) 2026-05-23 11:24:49 -07:00
comprehension feat(consumption-wiring): CW-1 + CW-2 — Frame + Composition registry loaders (#398) 2026-05-27 16:17:03 -07:00
__init__.py chore(generate): delete unreachable agenerate (#90) 2026-05-20 19:59:28 -07:00
admissibility.py feat(adr-0026): Phase 3 — ranked admissibility with margin 2026-05-17 15:03:03 -07:00
articulation.py Graceful fallback in realize() when slot versors are missing 2026-05-13 21:41:52 -07:00
articulation_legality.py feat(realizer): C1.5 — articulation legality at the realizer boundary 2026-05-20 11:11:28 -07:00
attention.py Add ADR-0008 salience attention 2026-05-13 22:40:36 -07:00
bridge_trace.py Phase 1 — bridge trace instrumentation (observation-only) 2026-05-18 18:04:57 -07:00
dialogue.py Fix test suite errors across core physics and generation 2026-05-14 13:02:32 -07:00
discourse_planner.py feat(discourse): Phase 2 — reflective rendering pronominalizes focus subject 2026-05-21 10:16:12 -07:00
exhaustion.py fix(W-011/W-012): propagate recognition refusal + catch InnerLoopExhaustion (#258) 2026-05-24 20:46:46 -07:00
graph_constraint.py fix(adr-0046): make forward-graph-constraint branch mergeable 2026-05-18 05:57:46 -07:00
graph_planner.py perf(graph): PropositionGraph.topo_order — Kahn's O(N+E) instead of O(N×E) (#92) 2026-05-20 20:37:21 -07:00
grounding_accessors.py feat(grounding): structured GroundedFact accessors for discourse planner 2026-05-19 11:19:59 -07:00
intent.py fix(intent): route 'Actually X R Y' premises to CORRECTION (inference_closure) (#117) 2026-05-22 12:33:56 -07:00
intent_bridge.py Phase 2 — proposition-slot grounding for articulate_with_intent 2026-05-18 18:18:31 -07:00
intent_ratifier.py feat(recognition): ADR-0144 — EpistemicGraph carrier + pipeline integration (#227) 2026-05-24 13:39:01 -07:00
math_candidate_graph.py feat(RAT-1): close ratify→runtime gap + first live composition admission 2026-05-27 20:09:47 -07:00
math_candidate_parser.py feat(RAT-1): close ratify→runtime gap + first live composition admission 2026-05-27 20:09:47 -07:00
math_parser.py fix(quarantine): drain all 60 quarantined tests — QUARANTINE=∅ (#267) 2026-05-25 11:22:12 -07:00
math_problem_graph.py feat(parser): ADR-0123 comparison-phrasing substrate (substrate-only; lift deferred) 2026-05-23 01:56:28 -07:00
math_realizer.py feat(realizer): ADR-0123 comparison-phrasing surface (closes substrate) 2026-05-23 02:03:49 -07:00
math_roundtrip.py feat(ADR-0131.G.3.1): numerics extensions — fractions + multi-currency + multi-token cardinals + word-num-adjective 2026-05-23 15:16:46 -07:00
math_solver.py feat(parser): ADR-0123 comparison-phrasing substrate (substrate-only; lift deferred) 2026-05-23 01:56:28 -07:00
math_symbolic_equivalence.py feat(ADR-0131.1.B): harden symbolic equivalence lane with generated corpus + exact algebra (#169) 2026-05-23 10:47:57 -07:00
math_symbolic_normalizer.py feat(ADR-0131.1.B): harden symbolic equivalence lane with generated corpus + exact algebra (#169) 2026-05-23 10:47:57 -07:00
math_verifier.py feat(parser): ADR-0123 comparison-phrasing substrate (substrate-only; lift deferred) 2026-05-23 01:56:28 -07:00
math_versor_arithmetic.py feat(ADR-0141): multiply as CGA dilator versor (positive non-zero) (#216) 2026-05-24 09:09:53 -07:00
morphology.py fix(gaps): close G1+G2+G3 + identity vocab + pipeline safety-stub honour 2026-05-16 21:21:06 -07:00
ood_surface_generator.py fix(quarantine): drain all 60 quarantined tests — QUARANTINE=∅ (#267) 2026-05-25 11:22:12 -07:00
operators.py feat(compositionality): compose_relations operator lifts lane 68.8% → 100% 2026-05-16 22:44:06 -07:00
perturbation_suite.py feat: add ADR-0125 perturbation suite 2026-05-22 17:12:33 -07:00
proposition.py feat(adr-0022): Forward Semantic Control — Accepted 2026-05-17 12:10:20 -07:00
realizer.py [codex] Implement energy-modulated vault surface (#269) 2026-05-25 11:33:32 -07:00
realizer_guard.py feat(coherence): ADR-0075 — realizer slot-type guard (C1) 2026-05-19 22:35:09 -07:00
recognizer_anchor_inject.py feat(wave-a): first non-DCS injector — multiplicative_aggregation w/ value extraction 2026-05-27 20:50:04 -07:00
recognizer_match.py feat(wave-a): first non-DCS injector — multiplicative_aggregation w/ value extraction 2026-05-27 20:50:04 -07:00
recognizer_registry.py feat(ADR-0163.D): wire ratified RecognizerSpecs into math_candidate_graph admissibility surface (#302) 2026-05-26 13:11:47 -07:00
result.py feat(adr-0023): Forward Semantic Control proof evidence — Accepted 2026-05-17 12:55:19 -07:00
rotor_admissibility.py feat(adr-0025): Phase 4 — rotor / frame admissibility at the seam 2026-05-17 15:16:32 -07:00
salience.py Implement core physics and pack validation 2026-05-14 12:35:19 -07:00
semantic_templates.py feat: vault recall index, Rust versor parity, cognitive pack expansion 2026-05-15 15:34:39 -07:00
stream.py chore(generate): make stop-tokens caller-overridable via RuntimeConfig (#87) 2026-05-20 19:59:33 -07:00
surface.py feat(surface): ADR-0031 — score-decomposition surface (per-axis hedges) 2026-05-17 20:16:22 -07:00
templates.py feat(realizer): C1.5 — articulation legality at the realizer boundary 2026-05-20 11:11:28 -07:00