Implements the 4-phase documentation reorganization master plan. - Consolidation: Merged brief/, handoff/, planning/, and decisions/ into briefs/, handoffs/, plans/, and adr/ respectively (101 ADRs relocated) - Root Cleanup: Relocated HANDOFF-gpt55-*.md and key top-level docs (runtime_contracts.md, etc.) to canonical folders. Added superseded alerts. - Indices & Navigation: Created docs/README.md navigation document, docs/sessions/README.md index, docs/adr/README.md index - Note: Also includes prior commit adding ADR-0200+ corpus hygiene governance (ADR-0225, dependency map, backfilled cross-references)
151 lines
6.5 KiB
Markdown
151 lines
6.5 KiB
Markdown
# ADR-0164.4 — Phase 2 Statement-Frame Reader
|
|
|
|
**Status:** Proposed
|
|
**Date:** 2026-05-26
|
|
**Author:** Shay
|
|
**Anchor:** [[thesis-decoding-not-generating]]
|
|
**Parent:** [ADR-0164 — Incremental Comprehension Reader](./ADR-0164-incremental-comprehension-reader.md)
|
|
**Builds on:** [ADR-0164.3 — Cross-Sentence Reading State](./ADR-0164.3-cross-sentence-state.md)
|
|
**Related downstream types:** [ADR-0115 — `MathProblemGraph`](./ADR-0115-math-problem-parser-and-graph.md)
|
|
|
|
---
|
|
|
|
## Context
|
|
|
|
Phase 1 (ADR-0164.3) shipped the `question_frame` reader and the
|
|
two-level `ProblemReadingState` / `SentenceReadingState` lifecycle. Phase
|
|
2 extends the reader to the three statement-side frames and adds the
|
|
`finalize()` projection from `ProblemReadingState` into
|
|
`MathProblemGraph`, so a whole problem can be read end-to-end without
|
|
the legacy regex parser.
|
|
|
|
## Decision
|
|
|
|
### Frames ratified
|
|
|
|
- **`initial_state_frame`** — `entity possession_verb [count] [unit]`,
|
|
emits a `PartialInitialPossession` → `InitialPossession` at
|
|
`finalize()`.
|
|
- **`operation_frame`** — `entity (accumulation|depletion|transfer|
|
|
capacity)_verb [count] [unit] [to entity₂]`, emits a `PartialOperation`
|
|
→ `Operation` at `finalize()`. `accumulation` → `add`, `depletion` →
|
|
`subtract`, `capacity` → `add`, `transfer` → `transfer`.
|
|
- **`descriptive_frame`** — opens on `copula_verb` (or subject-dropped
|
|
verb position), drains known tokens, emits no math state. Used for
|
|
descriptive prose ("Sandra is a baker", "There are some kids in
|
|
camp") that does not bind quantities to operations.
|
|
|
|
### `finalize()` projection
|
|
|
|
Operates on a closed `ProblemReadingState`:
|
|
|
|
1. Require `unknown_target_slot` — else `no_question_target`.
|
|
2. Build `entities` tuple from `entity_registry` — empty registry yields
|
|
`dangling_entity`.
|
|
3. `PartialInitialPossession` → `InitialPossession` (requires
|
|
`entity`, `quantity.value`, and resolved `unit`).
|
|
4. `PartialOperation` → `Operation` (requires `actor`, op-kind from
|
|
verb category, `operand.value`, resolved `unit`).
|
|
5. `QuestionTargetSlot` → `Unknown` with `unit` derived from the slot's
|
|
captured unit lemma or the unit-class default.
|
|
|
|
### Integration flag
|
|
|
|
`generate.math_candidate_graph.parse_and_solve(text, *,
|
|
comprehension_reader: bool = False)` gates the reader-first path. With
|
|
the flag `False` (default), behaviour is byte-identical to the existing
|
|
regex parser. With the flag `True`, the reader is attempted first; if
|
|
any sentence refuses (all-or-nothing) the regex path runs unchanged.
|
|
|
|
### Wrong = 0 discipline
|
|
|
|
The reader never returns a graph with a wrong answer in the Phase 2
|
|
GSM8K-train sample: any structural ambiguity (multi-quantity ops,
|
|
fractions, multi-subject sentences) yields a typed `ReaderRefusal` so
|
|
the regex parser handles the case. This preserves the project-wide
|
|
`wrong == 0` invariant.
|
|
|
|
### Lexicon additions ratified (`phase_2_reader_gsm8k_2026-05-26`)
|
|
|
|
- `currency_unit_noun` +2 (`dollar`, `cent`).
|
|
- `accumulation_verb` +2 (`adopt`, `invest`).
|
|
- `capacity_verb` +6 (`fill`, `lift`, `play`, `work`, `finish`,
|
|
`drive`).
|
|
- `proper_noun_entity_female` +5 (`allison`, `brooke`, `jan`,
|
|
`marion`, `sidney`).
|
|
- `proper_noun_entity_male` +14 (`bart`, `fernando`, `georgie`, `jake`,
|
|
`jed`, `jeremie`, `jose`, `orlando`, `rex`, `rudolph`, `steve`,
|
|
`troy`, `xavier`, `yun`).
|
|
- `time_unit_noun` +3 (`year`, `month`, `second`).
|
|
- `count_unit_noun` +14 (puppy, kitten, parakeet, coconut, macaroon,
|
|
brownie, scoop, section, foot, cable, eraser, crayon, paperclip,
|
|
card, …).
|
|
- `drain_token` substantial expansion to absorb prose connectives,
|
|
written numerals, place names, and non-math verbs that should not
|
|
drive frame selection.
|
|
|
|
### Possessive handling
|
|
|
|
`_classify()` now strips trailing `'s` and re-attempts lexicon lookup,
|
|
so `Rudolph's` resolves to `rudolph` (proper_noun_entity_male). Genitive
|
|
possessives drain (e.g., "Aaron and his brother") rather than triggering
|
|
the multi-subject refusal.
|
|
|
|
## Evidence
|
|
|
|
`evals/gsm8k_math/train_sample/v1/reader_phase2_delta.json` captures
|
|
per-case attribution on the 50-case sample:
|
|
|
|
```text
|
|
flag-OFF: correct=3 wrong=0 refused=47
|
|
flag-ON: correct=3 wrong=0 refused=47
|
|
reader_accepted (built a Graph): 3 / 50
|
|
```
|
|
|
|
### Observed bottlenecks
|
|
|
|
| count | reader refusal class | examples / interpretation |
|
|
| ----- | ------------------------------ | -------------------------------------------- |
|
|
| 18 | `incomplete_operation` at end | multi-quantity ops ("4 bags with 20 apples in each bag"); no-quantity op_frame |
|
|
| 11 | `unknown_word` | `hundred`, `presently`, compound `one-hour`; non-math verbs (`encountered`, `studied`, `holds`) |
|
|
| 6 | `unexpected_category` | fraction/percentage literals (Phase 2.1); multi-subject ("Aaron and Carson") |
|
|
| 6 | `unresolved_pronoun` | `them`, `their`, `his` with no compatible registry entry |
|
|
| 5 | `unattached_quantity` at end | quantity never bound to a unit noun |
|
|
| 1 | `no_question_target` at finalize | question sentence parsed but never set the slot |
|
|
|
|
### Acceptance gate
|
|
|
|
The brief asks for `correct ≥ 25 (preferred)` or
|
|
`mixed ∈ [4, 24] with documented bottlenecks`. The current count of
|
|
`correct = 3` falls below the gate floor. **The reader is structurally
|
|
correct (wrong = 0 holds, flag-OFF byte-identical, determinism holds),
|
|
but the lexicon and structural coverage are not yet sufficient to clear
|
|
the gate.** Closing the gap requires:
|
|
|
|
1. Phase 2.1: embedded-quantifier aggregates ("N X with M Y in each")
|
|
and multi-quantity operation handling.
|
|
2. Phase 2.2: fraction/percentage literal handling (currently refused
|
|
wholesale).
|
|
3. Phase 3: multi-subject sentences, descriptive-clause unpacking.
|
|
|
|
## Invariants
|
|
|
|
- `versor_condition(F) < 1e-6` — Phase 2 reader does not touch field
|
|
state; trivially preserved.
|
|
- `wrong == 0` — empirically verified on the GSM8K train sample under
|
|
both flag settings.
|
|
- Flag-OFF byte-identical — `parse_and_solve` short-circuits before any
|
|
reader call when the flag is `False`.
|
|
- Determinism — identical input yields identical `trace_hash` on
|
|
repeated runs (50/50 verified).
|
|
|
|
## Out of scope (refused cleanly in Phase 2)
|
|
|
|
- Embedded-quantifier aggregates → `embedded-quantifier aggregate;
|
|
deferred to Phase 2.1`.
|
|
- Fraction / percentage literals → `unexpected_category` with
|
|
Phase 2.1 deferred-scope detail.
|
|
- Conditional frames ("If X, then Y") → Phase 3+.
|
|
- Multi-quantity initial state ("Two puppies, two kittens, …") →
|
|
Phase 2.1.
|
|
- Multi-subject sentences ("Aaron and Carson saved $40") → Phase 2.1.
|