Shay
|
11d7e0b607
|
feat(matcher-extension/ME-4): subtractive composition matcher
Extends _match_multiplicative_aggregation with a new branch keyed on
anchor_kind="subtractive_quantity_composition". Pattern:
<Subject> <init-verb> <N> <unit>(,| then| ;| and then| and)
<sub-verb> <M> <unit>
Same-unit only. Emits a pre-composed CandidateInitial(N - M, unit) +
composition_shape="bound(initial) − bound(removed)".
Verb whitelists:
initial: had/has/got/owns/owned/earned/saved/made/received/bought
removal: lost/spent/gave/donated/paid/removed/sold/used/consumed
Removal verbs accept an optional " away" suffix ("gave away 20 apples").
Refusal-preferring discipline:
- count_b >= count_a → refuse (non-negative remainder; wrong>0 hazard)
- Pronoun / determiner subject → refuse
- Cross-unit → refuse (no v1 conversion table)
- Unobserved unit → refuse
- Unknown initial/removal verb → refuse
Tests (17 new, all green):
- canonical subtractive ("Sam had 50 apples, gave 20" → 30)
- then/and connectives
- gave away variant
- negative + equal remainder refused (hazard pin)
- pronoun + determiner subject refused
- cross-unit refused
- unobserved unit refused
- unknown initial/removal verbs refused
- additive (ME-3) path unaffected
- multiplicative_aggregate detection unaffected
- anchor audit fields complete
- end-to-end via composition_registry: affirms admits, falsifies suppresses
Registered in core/cli.py "packs" suite.
core test --suite packs -q → 123 passed (106 + 17 new)
core eval gsm8k_math --split public → 150/150, wrong=0
Anti-regression invariants preserved across ME-1..ME-4 stack:
- wrong == 0 on gsm8k_math public 150/150
- Case 0050 hazard pin holds
- ADR-0166 — no new eval lanes
- ADR-0167 partition — no cognition imports
- All prior matcher paths unaffected (test pins)
- engine_state/* not committed
- All three SAFE_COMPOSITION_CATEGORIES (multiplicative / additive /
subtractive) now have matcher extensions wired
Stacks on PR #402 (base: feat/matcher-extension-multi-quantity).
|
2026-05-27 17:23:35 -07:00 |
|