Consolidating ratification of the GSM8K design of record. Ratify the built comprehension/derivation substrate, freeze the serving regex recognizer/ injector path to lexemes + refusal-only, pin Phase 5b execution to WIRING -> COMPOSITION -> LEXICON. - ADR-0207: new consolidating decision (Accepted, ratified 2026-06-03). Supersedes ADR-0163 §Phase B-E + ADR-0136 regex sentence-template prescriptions. Freeze + wrong=0 gates (22-case corpus + sealed 1,319). - ADR-0164/0165/0174/0178/0179: -> Accepted (ratified by ADR-0207, 2026-06-03). 0164 keeps its implementation clause (Phase 1+2 shipped; remainder per §5) so Accepted != fully built. - composition_validation/v1: 20 -> 22 cases (2nd R4/R5 positives, dataset-sourced golds), +contract invariants 6-7, +dataset-gold test. Baseline 4/18/0; 47 passed. - docs/analysis: extraction-richness audit (read-only) reconciling ADR-0179 to the tree (EX-1/2/4/5/6 landed; EX-3 deferred). Non-serving (evals/docs/tests only). train_sample 6/44/0 unchanged; no-ref <N> times hazard stays refused. GB3b/0136 untouched.
270 lines
12 KiB
Markdown
270 lines
12 KiB
Markdown
# ADR-0165 — Regex Scope Rule: Lexemes Only, Never Grammar
|
||
|
||
**Status:** Accepted (ratified by ADR-0207, 2026-06-03)
|
||
**Date:** 2026-05-26
|
||
**Author:** Shay
|
||
**Anchor:** [[thesis-decoding-not-generating]]
|
||
**Companions:** [ADR-0164 — Incremental Comprehension Reader](./ADR-0164-incremental-comprehension-reader.md), [ADR-0114a — Anti-overfitting proof obligations](./ADR-0114a-anti-overfitting-proof-obligations.md), [ADR-0150 — Autonomous inter-session contemplation](./ADR-0150-autonomous-inter-session-contemplation.md), [ADR-0152 — Learning-arc proof corridor](./ADR-0152-learning-arc-demo.md), [ADR-0161 — HITL async queue](./ADR-0161-hitl-async-queue.md)
|
||
|
||
---
|
||
|
||
## Context — where regex creeps in, and why the line matters
|
||
|
||
CORE's existing front-end parsers (`generate/math_candidate_parser.py`,
|
||
`generate/recognizer_match.py`) use regex for two structurally different
|
||
jobs that have been collapsed into one:
|
||
|
||
1. **Recognizing lexemes** — "this token chunk is a currency literal," "this
|
||
is a fraction `\d+/\d+`," "this is a numeric expression." These have
|
||
genuinely closed orthographic rules. Regex is the right primitive.
|
||
|
||
2. **Matching sentence structure** — "this whole sentence is the shape
|
||
`How much MASS_NOUN does ENTITY VERB ...`." These do not have a closed
|
||
rule, because natural language doesn't have one. Regex here is
|
||
enumeration of memorized shapes, dressed up as grammar.
|
||
|
||
Mixing the two has been the engine's most consistent source of overfitting.
|
||
[ADR-0164](./ADR-0164-incremental-comprehension-reader.md) replaces the
|
||
sentence-structure use with an incremental compositional reader. This ADR
|
||
locks the *boundary*: a structural invariant that any future code must
|
||
respect, independent of which front-end implementation is current.
|
||
|
||
The rule is in the same spirit as the existing structural invariants —
|
||
`versor_condition(F) < 1e-6`, "no normalization outside the gate", "no
|
||
approximate vault recall", "no hidden stochastic fallback." It is a typed
|
||
boundary, not a guideline.
|
||
|
||
---
|
||
|
||
## Rule
|
||
|
||
> **Regex is permitted only at the lexeme level.** Regex must operate on the
|
||
> orthographic shape of one structured token or contiguous token-class run
|
||
> whose meaning has a genuinely closed rule. Regex must not match across
|
||
> word combination, syntactic role, or sentence structure.
|
||
|
||
**Test for any regex literal in the runtime path:**
|
||
|
||
If the regex describes "what this piece of orthographic material looks
|
||
like," it is a *lexeme primitive* and is permitted.
|
||
|
||
If the regex describes "how these words combine to mean X," it is a
|
||
*grammar template* and is forbidden.
|
||
|
||
---
|
||
|
||
## Legitimate uses (lexeme primitives)
|
||
|
||
These are the canonical examples. The list is extensible through the
|
||
teaching corridor (§Population, below).
|
||
|
||
| Primitive | Example regex | Extracts | Category emitted |
|
||
|---|---|---|---|
|
||
| `currency_literal` | `\$(\d+(?:\.\d+)?)` | numeric value | QUANTITY, unit_class=currency |
|
||
| `numeric_literal` | `\d+(?:\.\d+)?` | numeric value | QUANTITY (unit pending) |
|
||
| `fraction_literal` | `(\d+)\s*/\s*(\d+)` | numerator, denominator | QUANTITY, kind=fraction |
|
||
| `percentage_literal` | `(\d+(?:\.\d+)?)\s*%` | numeric value | QUANTITY, unit_class=ratio |
|
||
| `time_amount_literal` | `(\d+)[- ]?(hour\|minute\|day\|week\|month\|year)s?` | value, unit | QUANTITY, unit_class=time |
|
||
| `mass_noun_token` | `(?:money\|profit\|interest\|...)` | the lexeme | UNIT_CATEGORY_TOKEN |
|
||
| `decimal_currency` | `\$\d+\.\d{2}` | value | QUANTITY, unit_class=currency |
|
||
| `ordinal_token` | `(?:first\|second\|third\|...)` | rank | ORDINAL |
|
||
|
||
Each primitive has:
|
||
|
||
- a **name** (closed registry key),
|
||
- a **pattern** (a single, focused regex over orthographic shape),
|
||
- an **emission** (the typed category + extracted values it produces),
|
||
- a **provenance** (which ADR or teaching ratification introduced it).
|
||
|
||
Primitives never reach across roles. `currency_literal` recognizes
|
||
`$18.00`; it does not recognize `$18.00 an hour` (that composition is the
|
||
reader's job, not the primitive's).
|
||
|
||
---
|
||
|
||
## Forbidden uses (grammar templates)
|
||
|
||
These are the patterns ADR-0164 deprecates and this rule forbids
|
||
recurring. Each example below is a *grammar template* and would be rejected
|
||
in code review under this ADR.
|
||
|
||
```python
|
||
# FORBIDDEN — regex matching question shape:
|
||
_Q_MASS_NOUN_RE = re.compile(
|
||
r"^How\s+much\s+"
|
||
rf"(?P<unit>{_MASS_NOUN_PATTERN})"
|
||
r"\s+(?:will|did|does|do|would)\s+"
|
||
rf"(?P<entity>{_Q_ENTITY_OR_PRONOUN})\s+"
|
||
rf"(?:have\s+earned\s+|be\s+able\s+to\s+)?{_PATTERN_A_VERBS}"
|
||
r"(?:\s+.*?)?\??\s*$"
|
||
)
|
||
```
|
||
|
||
This is a sentence-structure template. It matches across question stem
|
||
("How much"), unit ("money"), auxiliary ("will"), entity ("Tina"), and
|
||
verb ("earn"). It claims the conjunction of these elements forms a closed
|
||
shape. It doesn't.
|
||
|
||
```python
|
||
# FORBIDDEN — regex matching statement structure:
|
||
_INITIAL_HAS_RE = re.compile(
|
||
rf"^(?P<entity>{_ENTITY})\s+has\s+(?P<value>\d+)\s+(?P<unit>\w+)\.?\s*$"
|
||
)
|
||
```
|
||
|
||
Same problem: matches across subject, verb, value, unit, and clause
|
||
shape. Replace with reader composition rules over the categories
|
||
`proper_noun_entity`, `possession_verb`, `numeric_literal`, `count_unit_noun`.
|
||
|
||
```python
|
||
# PERMITTED — regex matching one orthographic shape:
|
||
_CURRENCY_LITERAL_RE = re.compile(r"\$(\d+(?:\.\d+)?)")
|
||
```
|
||
|
||
This recognizes the surface form of one token (with the `$` prefix). It
|
||
has a closed rule (currency notation). It is the correct use of regex.
|
||
|
||
---
|
||
|
||
## Code-review test (apply to every new regex)
|
||
|
||
When reviewing or writing a regex, answer three questions:
|
||
|
||
1. **What does the regex match?** If the answer names a *piece of
|
||
orthographic material* (a number, a currency amount, a unit-noun set,
|
||
a date), it's a lexeme primitive. If it names *a way words combine*
|
||
(a question shape, an assertion shape, a clause pattern), it's a
|
||
grammar template.
|
||
|
||
2. **Could a competent linguist describe the matched class as a closed
|
||
set of orthographic rules?** If yes, the regex is appropriate. If the
|
||
class is "things people sometimes say to mean X," the regex is
|
||
enumerating memorized shapes and is forbidden.
|
||
|
||
3. **What happens when a novel phrasing of the same underlying meaning
|
||
appears?** A lexeme primitive's domain doesn't depend on the rest of
|
||
the sentence, so novel phrasings around it don't break it. A grammar
|
||
template refuses on every novel phrasing. If a refusal on novel
|
||
phrasing is the expected behavior of the regex, it's a grammar
|
||
template.
|
||
|
||
A regex that fails any of these three is a grammar template and must be
|
||
restructured (typically: extract the closed-set vocabulary as a primitive,
|
||
move the structural part into reader composition rules).
|
||
|
||
---
|
||
|
||
## Population — how the primitive set grows
|
||
|
||
The closed registry of lexeme primitives is not static. It grows through
|
||
the same contemplation → proposal → review corridor that already grows the
|
||
language packs and (under ADR-0164) the operational lexicon. This means:
|
||
|
||
1. **The reader refuses on an unrecognized token shape** — for example,
|
||
it encounters `"$1.5M"` and no current primitive matches it.
|
||
2. The refusal is logged with its token shape and position
|
||
(`evals/discovery/discovery_candidates.jsonl` analog).
|
||
3. The contemplation runner (ADR-0150/0155) identifies the shape as a
|
||
candidate new primitive and emits a proposal carrying:
|
||
- the proposed primitive's pattern,
|
||
- its emission category and extracted fields,
|
||
- replay-equivalence evidence (acceptance does not lift `wrong` above
|
||
0 on the active corpus),
|
||
- the originating refused tokens.
|
||
4. The proposal lands in the HITL queue (ADR-0161). The operator reviews
|
||
the pattern and emission rule. On acceptance, the primitive enters the
|
||
closed registry with its provenance.
|
||
5. The reader picks up the new primitive on next run. No code edit. No
|
||
parser rewrite. The engine has been *taught* a new lexical recognizer.
|
||
|
||
This matches the user's original framing: regex is a **mental tool** the
|
||
engine wields. The toolset is bounded and reviewed, but not hard-wired.
|
||
Adding a tool follows the same ratification discipline as adding a lemma
|
||
or a category.
|
||
|
||
Two consequences of this design:
|
||
|
||
- **Operators do not write production regex.** They review proposed
|
||
regex against typed evidence. This eliminates the failure mode where
|
||
a regex sneaks in to "just unblock GSM8K case 0027."
|
||
- **The regex set has a measurable closure curve.** Each ratification
|
||
round either does or doesn't reduce the refused-token count.
|
||
Diminishing returns become visible — the regex set is on the same
|
||
measurement substrate as the lexicon and the recognizer corpus.
|
||
|
||
The bootstrap primitive set lands as part of the ADR-0164 Phase 1 PR. It
|
||
covers the closed orthographic forms already known to be needed from the
|
||
existing parser (currency, numeric, fraction, percentage, time-amount,
|
||
ordinal). Everything beyond bootstrap enters via the corridor.
|
||
|
||
---
|
||
|
||
## Consequences
|
||
|
||
### Positive
|
||
|
||
1. **Overfit-by-design becomes structurally impossible at the regex
|
||
layer.** A grammar-template regex cannot land in code review without
|
||
violating this ADR explicitly.
|
||
2. **Closed-set vocabulary already collected in the existing parser is
|
||
preserved.** Mass-noun lists, possession-verb lists, name lists — all
|
||
become lexeme primitives or lexicon entries.
|
||
3. **One regex toolkit, one lexicon, one composition layer.** Three
|
||
layered concerns with separate population pathways and separate
|
||
review criteria. Maintenance scales linearly, not multiplicatively.
|
||
4. **The teaching corridor's purpose generalizes.** Today the corridor
|
||
teaches words, domains, and (per the deprecated path) regex
|
||
recognizers. Under this rule it teaches words, categories, and
|
||
lexeme primitives — three orthogonal kinds of evidence, each with a
|
||
clean review predicate.
|
||
|
||
### Negative / tradeoffs
|
||
|
||
1. **Refactoring cost is real.** Removing existing sentence-template
|
||
regexes from `math_candidate_parser.py` and `recognizer_match.py` is
|
||
a substantial edit, even with vocabulary preserved. The transition
|
||
plan in ADR-0164 (coexistence → incremental removal) absorbs this.
|
||
2. **Lexeme primitives are an attractive surface for new overfitting.**
|
||
A primitive author could try to smuggle structure ("a number followed
|
||
by a currency word followed by 'an hour'") into a single regex. The
|
||
review criteria above are explicit about this; the corridor enforces
|
||
it.
|
||
3. **The reader has to do more work.** Composition that used to live
|
||
inside a regex now lives in update rules. This is the point —
|
||
composition is the engine's job, not the regex's — but it shifts
|
||
complexity from one place to another.
|
||
|
||
---
|
||
|
||
## Boundaries — what this ADR does **not** say
|
||
|
||
1. **It does not forbid regex.** Regex remains a primary tool for lexeme
|
||
recognition. The current `evals/`, `scripts/`, and CLI parsers
|
||
already use regex appropriately for log parsing, file-path matching,
|
||
etc. None of that is affected.
|
||
2. **It does not specify the reader.** The reader's design is
|
||
ADR-0164's scope. This ADR only constrains where regex may live
|
||
in whatever front-end is current.
|
||
3. **It does not retroactively reject older code wholesale.** ADRs
|
||
ADR-0136.S.1–S.4 and ADR-0163.D.2–D.4 introduced grammar templates
|
||
under previous policy. They are deprecated by ADR-0164 with an
|
||
explicit transition plan. New work follows this rule from acceptance
|
||
of this ADR forward.
|
||
|
||
---
|
||
|
||
## Cross-references
|
||
|
||
- **Sibling ADR**: ADR-0164 — the comprehension reader that occupies the
|
||
space this rule clears.
|
||
- **Existing structural invariants** (same spirit, different domain):
|
||
- `versor_condition(F) < 1e-6` (CLAUDE.md §Field Invariant)
|
||
- "Allowed normalization sites" (CLAUDE.md §Normalization Rules)
|
||
- "Exact CGA recall" (CLAUDE.md §Core Primitives)
|
||
- ADR-0114a Anti-overfitting proof obligations
|
||
- **Population corridor**: ADR-0150 (contemplation), ADR-0152
|
||
(learning-arc proof), ADR-0155 (CI contemplation runner), ADR-0161
|
||
(HITL async queue).
|
||
- **Anchor**: `[[thesis-decoding-not-generating]]` — regex is a
|
||
decoder's tool for recognizing fixed orthographic shapes. It is not a
|
||
generator's tool for hallucinating sentence grammars.
|