core/docs/decisions/ADR-0165-regex-scope-rule.md
Shay 94bf1be1bc docs: ratify ADR-0207 — GSM8K comprehension/composition substrate
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.
2026-06-03 19:42:47 -07:00

12 KiB
Raw Blame History

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-0114a — Anti-overfitting proof obligations, ADR-0150 — Autonomous inter-session contemplation, ADR-0152 — Learning-arc proof corridor, ADR-0161 — HITL async queue


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 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.

# 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.

# 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.

# 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.1S.4 and ADR-0163.D.2D.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.