core/core
Shay 8d43eac45a feat(matcher-extension/ME-1): currency-per-unit composition admission
Lights up the dormant consumption path from PR #398. Extends
_match_rate_with_currency with a new branch keyed on
anchor_kind="currency_per_unit_composition" — when a statement
carries the "<Subject> bought <count> <noun> at $<amount> each" shape
with a same-sentence proper-noun subject, the matcher publishes:

  - composition_shape = "bound(count) × bound(unit_cost)"
  - composed_initial  = CandidateInitial(entity=Subject,
                                         quantity=Quantity(count*amount,
                                                           dollars))

The PR #398 consumption wire in inject_from_match consults
composition_registry on composition_shape: an affirms entry admits
the pre-composed CandidateInitial; falsifies suppresses; absence
refuses.

Subject binding under Option A (refuse when same-sentence subject
absent). Option B (placeholder) forbidden by the brief; Option C
(cross-sentence lookup) is ME-2.

Truth-test scorecard (6-row binding table from PR #399):

  #1 Synthetic Maria admits ........ PASS
  #2 Case 0050 stays refused ....... PASS
  #3 train_sample 3/47, no regress . PASS (3 correct preserved)
  #4 wrong == 0 preserved .......... PASS
  #5 public 150/150 unchanged ...... PASS
  #6 All PR #398 tests still pass .. PASS (38 tests + new 21 = 59)

Case 0019 stays refused (Option A) — admitting it requires
cross-sentence subject lookup (ME-2 brief).

Tests (21 new, all green):
- test_matcher_extension_currency_per_unit.py (15)
- test_matcher_extension_case_0050_hazard_pin.py ( 2)
- test_matcher_extension_end_to_end_admission.py ( 4)

Registered in core/cli.py "packs" suite.

Suite results:
  core test --suite runtime  -q → 20 passed
  core test --suite packs    -q → 51 passed (existing) + 21 new
  core test --suite teaching -q → 93 passed
  core eval gsm8k_math --split public → 150/150, wrong=0

Anti-regression invariants preserved:
- wrong == 0 on gsm8k_math public
- Case 0050 hazard pin holds
- ADR-0166 — no new eval lanes
- ADR-0167 partition — no cognition imports
- Existing currency_per_unit_rate path byte-identical (test pins)
- Refusal-preferring: subject-absent → no composition emission
- engine_state/* not committed

Stacks on PR #398 (base: feat/composition-frame-consumption-wiring).
2026-05-27 16:48:21 -07:00
..
capability feat(ADR-0120 math, ledger flip): mathematics_logic → expert tier (first-ever) (#195) 2026-05-23 18:55:34 -07:00
cognition feat(W-020b): DerivedRecognizer producer wiring (ADR-0154) (#278) 2026-05-25 18:44:12 -07:00
contemplation feat(contemplation): land ADR-0080 phase 1 (#119) 2026-05-22 13:10:03 -07:00
demos fix(quarantine): drain all 60 quarantined tests — QUARANTINE=∅ (#267) 2026-05-25 11:22:12 -07:00
physics feat(W-020a): TurnEvent.trace_hash back-stamp (ADR-0153) (#277) 2026-05-25 18:42:35 -07:00
protocol feat(protocol): ADR-0140 CORE Trace Protocol v0 (#259) 2026-05-25 06:08:51 -07:00
__init__.py
_safe_display.py feat(adr-0051): trust-boundary hardening pass 2026-05-18 07:09:55 -07:00
cli.py feat(matcher-extension/ME-1): currency-per-unit composition admission 2026-05-27 16:48:21 -07:00
config.py feat(ADR-0164.P1): reader/regex hybrid coexistence + Phase 1 measurement gate (#331) 2026-05-26 21:14:11 -07:00
epistemic_state.py feat(workbench-ui): design system v1 scaffold (ADR-0162 Branch 1) (#295) 2026-05-26 11:33:27 -07:00