Commit graph

5 commits

Author SHA1 Message Date
Shay
6f1ef49018 revert(reader-arc): hold frame-anchoring out of increment 1 — defer to rate-frame increment (#77 ruling)
Reverts the c3aed13b parser change (frame-anchored comparative regexes +
verb-free connector + _COMPARE_POLARITY_BLOCK + 'as much'); the reader stays
on the _comparison_anchor_verb() whitelist (fail-closed). Increment 1 ships
the compiler tier + the funnel finding only.

Three reasons on record: (1) frame-anchoring converts 0 of 500 official cases
— zero measured benefit today; (2) its consumer is rate-frame admission, a
later increment — the next increment (seeding-sentence injection) is a shared
layer that doesn't touch it; (3) the polarity blocklist is fail-OPEN — an
unenumerated depletion verb in a complete frame is a coherent-but-inverted
graph = a wrong on the run-once sealed arbiter (round-trip guards parse
consistency, not gold-correctness), a trade the fail-closed doctrine never
takes for zero gain.

Verified before revert-merge: with the whitelist reader, the 5 real compare
parses are non-divergent — test_real_compare_cases_solved_wrong_zero still
sees 5, solves 5, wrong 0 (corridor real-reach 0->5/500 preserved).

Frame-anchoring recorded as an OPEN DESIGN TASK owned by the rate-frame
increment: frame + POSITIVE polarity determination (neutral-polarity allowlist
or small polarity classifier), not assume-safe-unless-blocklisted. Detail in
docs/research/compare-increment-funnel-2026-07-18.md.
2026-07-18 20:03:38 -07:00
Shay
c3aed13bbe feat(reader-arc): frame-anchored compare recognizer (verb-free + polarity blocklist)
Increment 1 reader half. Re-anchor the two multiplicative-comparison frame
regexes on the closed-class frame ('<factor> as many/much <unit> as <REF>')
instead of the _comparison_anchor_verb() whitelist: the verb slot becomes a
verb-free bounded connector, 'as much' joins 'as many'. Admission is now
open-class for safe verbs (scored/wrote/caught/taught/…), gated by the frame.

One closed class is NOT frame-neutral — polarity-inverting/depletion verbs
(lose/spend/give/sell/win/donate/pay/eat/drop/lend): in a compare frame they
make the compared quantity a loss, so actor=factor×reference reads backwards
→ wrong>0. _COMPARE_POLARITY_BLOCK excludes exactly that set (the sanctioned
fallback; the frame is the gate for every other verb). Pins the wrong=0
guards in test_adr_0131_G2a + test_recognizer_comparative_inject.

Develop-on-tune / measure-once held. Footprint over 500 official cases: tune
byte-identical (0 divergences, wrong=0, PARSED=3); measure 1 divergence
(0441 'Zig wrote four times as many books as Flo') which advances
frame-refusal -> question-refusal (sanctioned delta) but does not solve — the
binding wall is the shared summation-question layer. X=15 measured delta=0.
Ruling per the funnel-conditioned escalation rule: mass is in shared layers,
so the next increment is shared-layer (summation-question reader), not a
practice escalation and not more compare frames. wrong=0 held on tune (261),
measure (239), smoke (176).
2026-07-18 19:35:23 -07:00
Shay
da663d1007 docs(reader-arc): pre-register escalation rule + refusal-histogram pin + reframe
Pre-registration before the shared-layer edit (PR ruling), all in the record:

1. Refusal-histogram baseline (tune, n=261): 'no injection' = 196/261 (75%) —
   a SHARED bottleneck across every family, not a compare defect; 48 statement,
   9 question, 3 PARSED (compare). Pinned; assert stable-or-explained after —
   only sanctioned delta = compare 'no injection' -> PARSED, disclosed.
2. Funnel-conditioned escalation rule (pre-committed): X=15 miss read via the
   funnel — compare-specific mass -> practice ruling; shared-layer mass ->
   shared-layer design increment (NOT practice). Load-bearing: practice cannot
   learn past a deterministic wall (better candidates still cross the same
   pipeline), so shared bottlenecks are design work regardless of X.
3. Reframe recorded: compare is the first slice of a larger reader project
   (reader parses ~1% of real GSM8K; 'no injection' 75% is a shared wall).
   Not scope creep — the arc seeing its true size.
2026-07-18 17:42:02 -07:00
Shay
7c28bb0ba4 docs(reader-arc): record 'reader was waiting on the compiler' — intentional guard
Code archaeology before treating 'no injection' as a defect: it is a DELIBERATE
narrowing, not broken code. recognizer_anchor_inject.py's discrete-count injector
refuses comparative surfaces with the explicit comment 'Refuse here until a real
compare_multiplicative operation can be emitted' (~L324) and 'does not create any
new admitting path' (~L460). The lockstep thesis of the arc in the code's own
history: the reader refused compare shapes to protect wrong=0 + ADR-0191
completeness because nothing downstream could compile them. The compiler tier
this increment shipped IS that operation -> the fix is LIFTING a now-obsolete
guard whose reason has shipped, not patching injection.
2026-07-18 17:31:08 -07:00
Shay
4a5d0f460d docs(reader-arc): compare increment per-layer attrition funnel (diagnostic)
Instrument-first (PR #76 ruling): before touching the parser, measure where the
61 compare-marked TUNE cases die. Funnel: 57/61 die pre-enumeration; of those,
**45 at the injection layer** ('recognizer matched but produced no injection'),
8 'no admissible candidate for statement', 3 'expected exactly one question
sentence'; 3 solve today.

Finding: the leverage is INJECTION (45/61), not the candidate regexes (which
fire on clean clauses but the real multi-clause sentences never reach them) nor
segmentation writ large. Injection is an EMITTER, so the sanctioned fix is
making it inject compare candidates the recognizer already matches — never
loosening the round-trip gate. Fix order by measured mass: injection (45) ->
statement-admissibility (8) -> question-sentence (3). Tune-only development;
single measure run at the end with refusal-by-reason + delta.
2026-07-18 17:25:26 -07:00