fix(math): restore WAVE-A multiplicative aggregate completeness provenance

The ADR-0191 completeness guard (added after WAVE-A) requires aggregating
initials to expose every consumed source token via
`consumed_value_tokens`, so it can confirm no source quantity was
silently dropped.  The WAVE-A "each weighing" injector predates the guard
and left that field empty, so for every "<Subject> <verb> M <outer>, each
... N <unit>" reading the guard computed required={M, N} vs
consumed={M*N} and refused as "incomplete reading: source quantities
[M, N] not consumed".  This silently regressed the entire WAVE-A
capability — the canary `test_lilibeth_canary_solves_end_to_end` has been
red on main (it failed byte-identically on f79b647; the smoke gate does
not collect this dedicated test file, so it merged green originally).

Fix: populate `consumed_value_tokens=(count_a_token, count_b_token)` on
the composed initial — exactly the contract the day-enumeration and
embedded-quantifier aggregators already satisfy.

wrong==0 preserved: the two tokens genuinely ARE the multiplicands of the
emitted value; the guard remains refusal-only.  Serving frozen: this
shape does not occur in train_sample, so the fix is serving-neutral.

Evidence:
- tests/test_wave_a_multiplicative_aggregation_injector.py: 11 passed
  (was 1 failed) incl. test_wrong_zero_preserved (full train_sample eval,
  wrong==0).
- core test --suite packs: 141 passed (was 1 failed, 140 passed).
- core test --suite smoke: 67 passed.
- scripts/verify_lane_shas.py: lanes 8/8 match pinned SHAs — the
  train_sample_v1 serving SHA is byte-identical, proving zero serving
  count change.

PR checklist:
- Capability: restores WAVE-A multiplicative-aggregate reading regressed
  by ADR-0191.
- Invariant: wrong==0 (completeness guard stays refusal-only; tokens are
  true multiplicands).
- Lane: core test --suite packs / smoke + lane-SHA gate (8/8).
- No hidden normalization, stochastic fallback, approximate recall, or
  unreviewed mutation.
- Trust boundary: none widened — internal candidate provenance only.
This commit is contained in:
Shay 2026-05-31 16:36:44 -07:00
parent f79b647671
commit cd97d59f13

View file

@ -1441,6 +1441,16 @@ def _try_extract_each_weighing_anchor(
"input_tokens": f"{count_a_token}|{count_b_token}",
"entity_source": "same_sentence",
},
# ADR-0191 completeness provenance. This is an aggregating initial:
# its derived value (count_a × count_b) collapses TWO source tokens
# into one quantity. Without recording them, the completeness guard
# (generate/math_completeness.py) sees required={count_a, count_b}
# but consumed={composed_value} and refuses every WAVE-A reading as
# "incomplete" — a silent regression of the WAVE-A capability that
# predates the guard. Expose both consumed tokens so the guard can
# confirm no source quantity was dropped. wrong==0 is preserved:
# these tokens genuinely ARE the multiplicands of the emitted value.
consumed_value_tokens=(count_a_token, count_b_token),
)
anchor: Mapping[str, Any] = {