CORE served the affirmative of propositions the user denied. Measured live on
main @ 536d6e55 with realizer_grounded_authority=True:
"evidence does not support truth" -> 'Evidence is verified: what supports truth.'
"evidence supports truth" -> 'Evidence is verified: what supports truth.'
Byte-identical.
Phase 4 (#136) pinned "render_semantic has no negated parameter" as a defect.
Sizing the exposure before acting on it -- the step §7 requires -- showed the
pin was correct and INCOMPLETE. The defect is two drops in series, and the
first is in the graph:
intent.negated parsed from the user's words, always has been
GraphNode NO FIELD FOR IT <-- first drop
ground_graph rebuilds nodes field-by-field; nothing to carry
depth enrichment rebuilds nodes field-by-field; nothing to carry
plan_articulation cannot carry what the node does not hold
realize_semantic never read step.negated
render_semantic no parameter for it <-- second drop
Five separate constructors, each silently defaulting to the affirmative.
Why every gate was green
------------------------
On the default config the ungrounded realizer emits "...", _is_useful_surface
rejects it, and the runtime echo wins the resolver -- and the echo contains the
user's own "does not". The truth path was correct BY ACCIDENT. ADR-0088 Phase B
grounds the graph first, which is exactly when the realizer's surface becomes
useful enough to win. So the defect sat behind a shipped flag, invisible to
every property-of-one-surface test, because nothing compared a denial to its
assertion.
Delivered
---------
- GraphNode.negated, threaded intent -> graph -> ground -> enrich -> step ->
surface. Serialized ONLY when True, so every pre-existing as_dict and every
trace_hash folded from one stays byte-identical -- which is why no lane pin
moves.
- Clause grammar delegated to its one owner. Four of the eight intent
"templates" were never frames; they were plain clauses. They now call
render_step. Writing a second negation implementation in semantic_templates
was the tempting fix and is rejected: Phase 2A spent a unit giving every
linguistic fact one owner, and that design rebuilds the disease one level up.
- Frames that keep a finite verb (VERIFICATION, PROCEDURE, COMPARISON) get an
explicit negated form. RECALL is a speech act with no proposition to deny, so
it falls back to the clause path rather than drop the denial (ADR-0261 §5.1).
Measured
--------
delegation on affirmatives 192/192 byte-identical
serving realizer, all corpora 85/347 -> 109/347 (+24 = the denials)
feature-bearing bucket 49/214 -> 73/214
CONTROL (nothing droppable) 33/33 -> 33/33 unchanged
multi-node (clause joining) 3/100 -> 3/100 unchanged, out of scope
lane pins 11/11 byte-identical, none edited
The control staying 33/33 and multi-node staying 3/100 is the evidence that
this moved the denials and nothing else.
The exhaustive control earned its keep immediately
--------------------------------------------------
It found FIVE more intents serving a denial as its own assertion --
TRANSITIVE_QUERY, FRAME_TRANSFER, NARRATIVE, EXAMPLE, DEDUCTION -- because an
intent with no frame fell back to the UNKNOWN *template* (which cannot say
"not") rather than the UNKNOWN *clause* (which can). The default is now the
capable path, so the next intent added inherits correctness. Found by the
control, not by inspection.
Mutation -- every link reverted individually
--------------------------------------------
baseline 19 pass
graph_from_intent drops intent.negated 8 FAIL
plan_articulation drops node.negated 6 FAIL
ground_graph drops it on rebuild 2 FAIL
realize_semantic stops passing step.negated 6 FAIL
unframed intents fall back to the template 1 FAIL
pipeline depth-enrichment drops it 1 FAIL
The last row was GREEN on the first run -- my fix there was unguarded. That is
what added the structural invariant: every GraphNode(...) built on the serving
path must NAME `negated` or be recorded in an allowlist with a reason. The
defect was five constructors; a per-site test must be written per site, and a
site added without one is invisible. Only recognition/connector.py is exempt
(an EpistemicNode has no polarity to carry).
Four Phase 4 pins are revised, not relaxed -- #136's M2 mutation ("render_semantic
GAINS a negated parameter -> FAIL") has now happened for real, and forced the
deliberate revision it was built to force.
Registered in `smoke` in the same PR that creates it, per the #136 finding that
an unregistered pin runs nowhere.
Still unexpressed, deliberately: quantifier, tense, aspect. NO PRODUCER sets
them anywhere on the serving path, so threading them would be machinery with no
caller. render_step already handles all three the moment a producer exists.
[Verification]: in-worktree on CPython 3.12.13 with `uv sync --locked` --
smoke 641 (was 621), deductive 503, lane pins 11/11 with no pin edited.
Phase 4 of the grammar-unification arc, resolved by option (b) of the plan.
The problem: 149 green fluency cases scored `realize_target`, and
`core/cognition/pipeline.py` never calls it -- it calls `realize_semantic`.
`english_fluency_ood` reported 117/117 + 39/39 for a function that does not
speak, for the whole life of the lane.
The plan framed this as "which realizer is better". Reading the source says it
is not a quality question. `render_semantic`'s signature is
`(intent, subject, predicate, obj, secondary, language, root)` -- no `negated`,
no `quantifier`, no `tense`, no `aspect` -- and `realize_semantic` never reads
them off the step. So the serving writer cannot express content the
ArticulationStep is carrying:
negated=False -> 'Knowledge is defined as opinion.'
negated=True -> 'Knowledge is defined as opinion.'
It serves the AFFIRMATIVE of a negated proposition. That is the ADR-0261 §5.1
family, not a fluency defect. Pinned here as a defect; NOT fixed, because
fixing it changes served output and belongs to Shay.
Measured -- identical contract, all seven scored corpora
--------------------------------------------------------
bucket n realize_target realize_semantic
feature-bearing, single node 214 207 49
no features, multi-node 100 100 3
no features, single node (CONTROL) 33 33 33
total 347 340 85
The control is what makes the rest mean anything. Every corpus hardcodes
IntentTag.UNKNOWN, so "the serving writer scores badly" could have been an
artifact of never giving it a real intent. On the 33 cases carrying nothing it
cannot express, the two are IDENTICAL -- so the gap on the other 314 is the
dropped features and the clause joining, not the intent.
Delivered
---------
- `grammatical_coverage/runner.py` reports `serving_accuracy` beside
`accuracy`; `english_fluency_ood` delegates to that run_lane and gains it
for free. The realizer is a parameter now instead of a hardcoded import.
- `tests/test_phase4_realizer_resolution.py` -- the control, the decomposition,
the negation defect pin, and the §6 evidence.
- The claim is restated at both places it was made: the lane docstring and
`grammar_roundtrip/contract.md`.
Zero served bytes change. No serving authorization needed.
§6 -- the plan's pre-commitment was wrong, and is corrected rather than
quietly edited
------------------------------------------------------------------------
§6 forks on read_rate: risen => Phase 5 diversity; near-zero => §1.8 graph-model
mismatch => ADR. It pre-committed to the second. Neither is what the
measurement says.
g_read_rate went to 1/293. The unblocked case was blocked by a one-line WRITER
defect (predicate-nominal object agreement, #135), not by §1.8. The other 292:
no_template_match 289 reader has no SUBJ-VERB-OBJ template at all
unknown_morphology 2 prepositional objects (reserved_word_in_np)
unsupported_negation 1 reader has no negated-categorical template
Every one is the reader declining a CONSTRUCTION, not a projection disagreeing
about a graph it parsed. Where a construction is in both inventories the round
trip closes exactly. So the barrier is the OVERLAP of the two construction
inventories, currently one construction wide -- Phase 5's item 1, tractable,
not an ADR-scale model decision.
§1.6 read "uniform no_template_match" as evidence FOR the type mismatch. It is
not: no_template_match is a coverage fact, and the corpus was 289/293 bare
transitives, a construction the reader never claimed to read. The measurement
was mostly reporting the corpus's composition.
And a finding in my own stack
------------------------------
`tests/test_realizer_quantifier_agreement.py` lived ONLY in the `cognition`
suite, which is not on the AGENTS.md pre-push gate. So every pin Phases 3 and 4
added to it -- including the invariant covering all twelve inflection branches
-- ran in NO gate. That is why smoke stayed at 621 across two PRs that added 13
tests between them, and it is the same silent-red shape the smoke list already
calls out for test_adr_index.py.
Registered into `deductive`, which now runs 504 instead of 406.
Mutation
--------
baseline 12 pass
serving metric computed with realize_target 4 FAIL
render_semantic GAINS a `negated` parameter 2 FAIL
realize_semantic delegated to realize_target 6 FAIL
Row 2 matters most: if someone FIXES the negation defect, the pin forces a
deliberate revision instead of passing silently.
Still open, still Shay's: option (a), promoting realize_target to the serving
path. It now has a price tag -- 340/347 over 85/347 and the ability to say
"not", against a move in every surface hash and whatever the Shadow Coherence
Gate ruling in core/cognition/surface_resolution.py was protecting.
[Verification]: in-worktree on CPython 3.12.13 with `uv sync --locked` --
smoke 621, deductive 504 (was 406; +12 new Phase 4 pins, +86 previously
ungated), lane pins 11/11 unchanged, no pin edited.
_inflect_predicate applied base_form — a SINGLE-VERB function — to whole
humanized predicate phrases, stripping the final word's last character
class, and its plural branch never consulted `copular`. Nine of the 26 seed
predicates came out wrong and every multi-word one did:
is defined as -> "is defined a" want "are defined as"
has the following ... -> "...step" want "have the following steps"
belongs to -> "belongs to" want "belong to"
causes -> "caus" want "cause"
Root causes, both single-point as §1.4 predicted:
1. morphology.agree_plural_phrase inflects the HEAD (the finite verb is the
first token of every humanized predicate) and carries the rest through.
base_form stays single-verb and is PINNED as still wrong on a phrase, so
nobody "fixes" the symptom in the wrong place.
2. The plural branch now agrees the phrase. The plural NEGATED branch had the
same defect ("do not is defined a") and is fixed with it: a plural copula
takes a bare "not", everything else takes do-support.
Two further defects found while writing the eval cases, both fixed here:
base_form("causes") -> "caus". The -es sibilant rule fired on a stem
ending in a single "s"; it must require a doubled "ss" ("passes"->"pass"),
because a single "s" is nearly always a stem ending in "e" that took a
plain -s ("causes"->"cause").
pluralize("proof") -> "prooves". f/fe -> ves is NOT productive in English
(proof->proofs, chief->chiefs, roof->roofs); it is a closed set. Now
derived as lexicon.VES_PLURAL_SINGULARS from the ves-rows of
IRREGULAR_SINGULARS, so the rule cannot claim a word the table does not
know. Phase 2B had put pluralize on the SERVING path, so this one was live
— and the surface-hashing pin from #133 confirms no served surface moved,
which is that guard's first real use.
New construction C14 quantified_copular, 13 cases: the combination that was
broken was the one never tested. Measured before: 152 corpus cases carry a
quantifier and ZERO combine it with a copular predicate.
MY FIRST DRAFT OF THOSE CASES COULD NOT FAIL. must_contain/word_order listed
quantifier, subject and object but NOT THE VERB, so "all molecules is
defined a compound" passed and reverting the fix left 47/47 green. Rewritten
with the agreed verb in both constraints plus reject_surfaces carrying the
ACTUAL pre-fix output, computed by running the reverted code rather than
guessed. Mutation now:
baseline 13/13 C14
revert phrase-head agreement 4/13
revert -es stem rule 12/13
revert closed ves set 11/13
The 4 survivors of the first mutation are the mass-noun controls, which is
correct — "all evidence is grounded in truth" must NOT pluralize.
Same lesson as the lane pins in #133: a pin that cannot fail guards nothing,
and the only way to know is to break the thing on purpose.
grammar_roundtrip's graph corpus is harvested from the committed case files,
so it grew 280 -> 293. Updated exactly rather than loosened to an inequality:
a corpus that grows or shrinks should require a deliberate edit.
[Verification]: in-worktree on CPython 3.12.13, uv sync --locked —
agreement 26/26 (from 17/26); english_fluency_ood 117/117 + 39/39 + dev
13/13 unchanged; grammatical_coverage v1 49/49; smoke 621 unchanged;
deductive 405; scripts/verify_lane_shas.py 11/11, no pin edited.
The pinned artifact carried verdict counts only. The runner's docstring
justified that: prose is "presentation, not decision", so the pinned bytes
"stay stable against wording-only changes; wording is covered by
tests/test_deduction_surface.py."
Measured, that justification was false. With render._display_noun sabotaged
so every clause reads "all SABOTAGE_dogs are SABOTAGE_animals":
11 lane SHA pins -> 11/11 byte-identical, blind
test_deduction_serve_lane + _license -> 20 passed, blind
tests/test_deduction_surface.py -> 41 passed, blind
(the named wording guard)
evals/grammar_roundtrip -> RED, the only witness
So CORE's user-visible output was unguarded by its own hash pins, which is
how the ratified v1b band served "all dog are mammal" for the entire arc
with wrong=0 intact.
build_report now emits surface_sha256 + per-case surfaces from the real
deduction_grounded_surface — the same call chat serving makes, so what is
hashed is what a user reads. Note build_combined_report re-projects five
named fields per split, so a field added to build_report alone never reaches
the pinned bytes; both had to change. The payload is not the report.
Surfaces are recorded, not just digested, so a moved pin shows the exact
sentence that changed in review instead of an opaque hash to go re-derive.
2,766 -> 37,280 bytes.
deduction_serve_v1 under sabotage: BEFORE byte-identical (blind)
AFTER 52370b73 vs c855d55c (RED)
Re-pinned surgically, one line, old hash recorded beside it, never --update.
Verdicts untouched: 166/166 correct, wrong=0. The hash moved because the
payload grew.
test_surface_hash_moves_when_the_renderer_is_sabotaged makes it permanent:
it corrupts the renderer, requires a digest to move, AND asserts the
aggregate counts are unchanged — proving the digest tracks PROSE rather than
smuggling in a decision change. A pin that cannot fail guards nothing.
Accepted cost: wording-only changes now move this pin. That is the intent —
a wording change IS a user-visible change and should require a deliberate
re-pin. The other 10 lanes are untouched; deduction_serve was fixed because
it is the one demonstrably serving prose to users.
[Verification]: in-worktree on CPython 3.12.13, uv sync --locked —
smoke 621 unchanged; deductive 405 (403 + 2 new);
scripts/verify_lane_shas.py 11/11 with the new pin, and 10/11 (RED on
deduction_serve_v1) under the sabotage it previously could not see.
The ratified, flag-ON v1b categorical band served "all dog are mammal" for
every noun: the A/E/I/O templates supply all/no/some + are, which demand a
plural, and the slots were filled with singular canonical entity ids. Four
of the 47 ratified corpus cases were affected, and wrong=0 never noticed
because every verdict was correct — only the prose was wrong.
Two fixes that compose into a closed round trip:
1. generate/morphology.py becomes the single owner of the number RULES
(Phase 2A gave the TABLES one owner). Both directions live there:
pluralize + singularize, over lexicon.IRREGULAR_PLURALS /
IRREGULAR_SINGULARS, with mass-noun and compound-head handling.
templates.pluralize and reader._singularize were two independent copies
of the regular suffix rules that disagreed about which irregulars they
knew; both now delegate.
2. render._display_noun re-inflects at render time and swaps _ for a space,
so compound ids read "guard dogs" rather than "guards dog" or
"guard_dog".
Result: reader gives wolves -> wolf, renderer gives wolf -> wolves. The
round trip closes.
0 malformed of 47 (from 4)
reader-vs-reader singularization 20/20 (from 8/20), 0 silently wrong
s_surface_match_rate 0.0 -> 0.625, now EQUAL to s_renderable_rate, so the
only remaining losses are surfaces the renderer cannot express at all
NEAR-MISS — widening a reader broke soundness, caught by the lane:
Routing the reader through the full 29-entry table first produced wrong=1 on
band v6-EX. ds-ex-0012 ("No fish are mammals. Therefore some fish are
mammals.") answered invalid where gold is refuted.
_singularize returning None makes the reader REFUSE, and the serving
composer tries the categorical band FIRST, falling through to more capable
bands. "fish" previously returned None (it matches no suffix rule), so v6-EX
got the case and decided it correctly. Resolving "fish" made v1b accept a
sentence it cannot decide.
Fixed by a principle, not a patch: a number-INVARIANT form is ambiguous in
number — "fish are mammals" is plural, "a fish is a mammal" is singular, and
the token cannot tell you which — so a reader that must not guess number
declines it. lexicon.INVARIANT_NUMBER is derived from the singularizer's own
key == value rows, so the rule cannot drift from the table.
=> Coverage and correctness are different axes. Fixing a corrupted VALUE is
safe; widening ACCEPTANCE changes which band answers, and in a
first-match composer that turns a right answer into a wrong one. Same
family as ADR-0261 5.1 refuse-don't-drop.
Also fixed, found by testing the inverse law: the two number tables were not
mutual inverses. The pluralizer lacked cactus->cacti, fungus->fungi,
die->dice and the invariants aircraft/means/offspring, so CORE could read
"cacti" but wrote "cactuses", and would have written "aircrafts", "meanses",
"offsprings". No round trip can close across a non-invertible table.
THE LANE SHA PINS ARE BLIND TO SERVED ENGLISH:
2B changed 4 served surfaces and the pins came back 11/11 byte-identical.
The deduction_serve_v1 hashed report holds only n/counts/by_gold/
correct_by_gold/all_cases_correct/mismatch_examples — no prose at all.
Confirmed by sabotage: with _display_noun returning "SABOTAGE_" + ..., so
every clause reads "all SABOTAGE_dogs are SABOTAGE_animals",
11 lane SHA pins -> 11/11 byte-identical, blind
test_deduction_serve_lane + _license -> 20 passed, blind
Phase 1 grammar_roundtrip -> 3 tests RED, caught it
This corrects #129: byte-identity of the pins is the arbiter for values and
verdicts, NOT for surface text, so the 2A/2B split is not a partition of
"changes users can see." Phase 2A's 11/11 conclusion still stands on its own
independent evidence (24/24 table-equality checks vs the pre-migration
literals), but the justification was thinner than stated.
Before Phase 1 no test in the tree would have noticed CORE's served prose
turning into word salad. That is exactly how "all dog are mammal" survived
on a ratified flag-ON band with wrong=0 intact.
Deliberately not fixed: mass-noun verb agreement ("all evidence ARE truth"
should be "is"). The copula is fixed text inside the templates, so agreeing
it changes the template shape rather than a slot, and no mass noun reaches a
categorical clause in any serve corpus. Recorded in render.py.
No lane pin edited — none moved.
[Verification]: in-worktree on CPython 3.12.13, uv sync --locked —
smoke 621 unchanged; deductive 403 passed (383 + 20 new/rewritten);
scripts/verify_lane_shas.py 11/11 (see blindness note above — gate on
grammar_roundtrip for surface work, not on these pins).
Collapses the duplicated closed English tables into generate/lexicon.py.
Measured on main @ 0948f7cd: the same facts were encoded up to five times
across the reading and writing paths, each copy written independently as a
successive deduction band landed.
The 2A/2B split is decided empirically per #129 — make the change, run the
11 pinned lanes, let byte-identity rule. Result: 11/11 byte-identical, so
this entire unit is 2A and nothing spilled into the authorization-gated 2B.
Collapsed to one object:
- connectives 3 identical copies (member, verb, cond_member)
- predicate display 2 identical 26-entry copies (semantic_templates,
templates)
- be-form inventory 5 copies, not the 2 §1.3 counted. The structural
test found realizer_guard._BE_AUX and
chat/runtime._BE_FORMS, which a COPULA-shaped grep
could never see.
Derived rather than duplicated, so they can no longer drift:
- STRUCTURAL = CONNECTIVES | {therefore}
- QUANTIFIER_TOKENS = QUANTIFIER_LEAD | QUANTIFIER_NON_LEAD
- NEGATION_BEARING_WITH_NOT = NEGATION_BEARING | {not}
- READER_IRREGULAR_SINGULARS = IRREGULAR_SINGULARS restricted to 8 keys
§1.3 re-measured while doing this, and it overstated the disease (plan
§1.9). Almost nothing contradicts:
- the "3 divergent plural tables" are 1 pluralizer + 2 singularizers,
i.e. inverse directions; comparing them as copies is a category error
- reader's 8 singulars are a STRICT SUBSET of member's 29 with the
difference in reader's favour empty, so its values are all correct and
only its coverage is short
- the "3 divergent quantifier sets" are 3 distinct facts; every/each lead
a clause but take singular nouns, so their absence from
PLURAL_QUANTIFIERS is correct
- english's negation set is a subset of member's, and the difference is
principled: v2-EN normalizes "<copula> not", v3-MEM refuses it
Exactly one genuine contradiction exists in the whole inventory:
discourse_planner maps is_defined_as -> "is" where the others map it to
"is defined as". Preserved as a register choice, pinned by test.
Found while reading, pinned as current behaviour for 2B to flip:
reader._singularize does NOT refuse uncovered plurals despite a comment
claiming it does — it falls through to a bare -s strip, so news -> new and
species -> specy, exactly the corruptions member.py's table comment says
its table exists to prevent.
Two 2A exit criteria were unmeasurable as written and are replaced:
- "Jaccard -> 1.00" cannot work. measure_grammar_seam.py scans source
literals, so unifying a fact removes it from those files and Jaccard
FELL, 0.083 -> 0.023 — the success direction reported by a metric
shaped to read like failure. Replaced with an object-identity count:
3 distinct objects behind 8 names, from 8-behind-8. Value comparison
cannot tell a shared object from two equal copies.
- "one table per fact" presumed §1.3's inventory was right. The report now
separates must-be-one-object (all UNIFIED) from related-but-distinct
(6 relations, all HOLD).
ADR-0258 §5 already decided morphology's destination is a ratified pack,
triggered by a grc/he member band. No such band exists, so the promotion is
correctly deferred and lexicon.py is a staging area, not a rival home — no
new ADR. Destination measured for whoever picks it up: packs/en/morphology
.jsonl has 9 records and zero irregular plurals, features.number has no
consumer, and _pack_morph_roots_for reads a top-level "root" key that 0 of
31 records across all four packs define, so it returns {} every call.
[Verification]: in-worktree on CPython 3.12.13, uv sync --locked —
smoke 621 unchanged; deductive 383 (364 + 19 new);
scripts/verify_lane_shas.py 11/11 byte-identical.
Third correction, same session, again from measurement rather than
argument.
I specified the Phase 2A/2B split as "a table is off-serving only when
every caller is proven eval-only," then computed the actual serving import
closure: 227 first-party modules from the six real serving entries, and
ALL 13 table-owning modules are in it — 13 of 13, including
generate/templates.py via pipeline.py -> realizer.py -> templates.py. So
the static test I had just written returns "everything is serving" and
discriminates nothing.
Import-reachable is not call-reachable. Importing a module executes its
table literals (pure data) but not its functions. The chain
realize_target -> render_step -> _inflect_predicate -> base_form is closed
and small enough to verify exhaustively, and realize_target has zero
non-eval non-test callers, so §1.2 and §1.4 stand as written.
But Python call-reachability is not statically decidable in general.
So the arbiter for this arc is EMPIRICAL: make the change, run the 11
pinned lanes, let byte-identity decide. That is stronger than a static
claim because it tests behaviour instead of predicting it, and it is what
the lane pins already encode as doctrine.
Consequence: 2A and 2B are now defined as a RESULT. A change is 2A if the
pins come back byte-identical and 2B if they move. Work the changes in
order, run the pins, let the split fall out — do not argue a change into
2A.
Two additions found while designing Phase 1's projection.
1. NEW §1.7 — band v1b serves malformed surfaces today, user-visible:
in : All dogs are mammals. All mammals are animals.
Therefore all dogs are animals.
out: Given: all dog are mammal; all mammal are animal.
That's valid — all dog are animal follows.
render.py::_CATEGORICAL_PHRASE uses plural syntax ("all {s} are {p}")
but interpolates the reader's SINGULARIZED entity ids, with no
re-pluralization step — because reader and renderer sit on opposite
sides of the §1.3 seam. Affects every plural noun, regular or
irregular; 4 of 47 ratified corpus cases that serve a categorical
clause (ds-v1-0023/0024/0026/0028). wrong=0 is NOT threatened — every
verdict is correct; this is purely surface.
Compounding cause: the reader's plural table has 8 entries where the
v3-MEM band's has 29, so wolves->wolve, knives->knive, leaves->leave,
lives->live, halves->halve, loaves->loave, thieves->thieve,
elves->elve. CORE's two readers disagree on 12 of 20 plurals. The
wrong singulars do not break soundness (uniform deterministic
bijection) but they are why cause 2 needs a SHARED table.
2. CORRECTED §4 — the earlier draft claimed "Phases 1-3 cannot change
serving behaviour." That was wrong, and it is the same shape as the
mistakes this arc exists to fix: I classified a table as off-serving
without asking which callers reach it. reader.py::_IRREGULAR_PLURALS
IS serving-reachable (comprehend -> to_syllogism -> v1b ->
deduction_grounded_surface).
New rule: a table is off-serving only when EVERY caller is proven
eval-only. Phase 2 splits on that test into 2A (off-serving,
byte-identical) and 2B (serving tables + the render fix,
authorization-gated). Phase 2A now ships a caller-provenance test so
this check lives in the tree, not in a reviewer's head.
Refs: ADR-0256 (band v1b), ADR-0258 (v3-MEM plural table)
CORE cannot read its own writing. Measured on main @ 9696443a:
- round-trip is 0/280 (0.0%) — all 280 writer-produced surfaces refuse
with no_template_match; all six readers refuse all writer output,
including CORE's own live served surfaces (24 refusals, 0 comprehensions)
- 35 word-tables on the reading path vs 9 on the writing path,
Jaccard 0.083; three divergent _IRREGULAR_PLURALS tables, two of them
both on the reading side
- 9 of 26 predicates produce wrong plural agreement
("all wolves is defined a mammal"); two single-point root causes
- the fluency instrument is decorative: "banana does the." passes all
five content predicates, and 0 of 280 eval cases exercise the
quantifier x copular combination that breaks
- the good realizer (render_step, 232 lines) is eval-only; 149 green
fluency cases score a function that never serves
Central design decision: the instrument IS the fix. Grammaticality cannot
be measured without a grammar, so round-trip forces one artifact to both
parse and generate. Positive AND negative corpora are both load-bearing —
round-trip proves mutual intelligibility, not English quality.
Phases 1-3 cannot change serving; Phase 4 is authorization-gated. Phase 5
is deliberately unestimated until Phase 1 reports. Section 6 makes the
next direction a measured fork rather than an argument, and pre-commits to
the reading that the graph-model mismatch (MeaningGraph vs
PropositionGraph are not type-compatible) is the likelier barrier.
Refs: ADR-0264, ADR-0071/0072 (seeded variation reused for diversity)
Every correction here is to something I wrote earlier in this arc. Original text
is preserved in place; nothing was rewritten to look right in hindsight.
ADR-0264 §4.2 — CORRECTED block. I sized the eleven band ceilings from per-TERM
exclusivity; `resolve_domain`'s predicate is per-PAIR, which is looser, so every
ceiling was understated and one verdict was wrong: systems_software_causal is
720, not 630, i.e. reachable rather than impossible. Seven of eleven bands
cannot reach 657, not eight. Downstream conclusions survive — physics·modal (480)
is still impossible and philosophy_theology·modal is still the target.
ADR-0264 R5 + DIVISION-OF-WORK ×2 + compile_premises docstring — the
"verdict-identical" claim is exact only where the full family was READABLE. Over
MAX_PREMISE_SENTENCES, full-family compilation refuses outright, so narrowing is
verdict-IMPROVING there. Read literally the unqualified phrasing implies a
17-chain family keeps declining, which is backwards — the opposite of the
unblock.
E2 rename staleness, 4 sites: ADR-0256 (Accepted) named
`gold.py::assert_corpus_sound`, which #119 deleted; the plan's E2 item and
DIVISION-OF-WORK's §2 row, §4 heading and "renaming after that is strictly more
work" reasoning were all still written as pending.
DIVISION-OF-WORK §0b — new status table: which PR each unit is, what stacks on
what, and the four things the units found that the plan did not predict.
Adds the arc-close brief from ARC-CLOSE-TEMPLATE.md. Its §3 (falsified
assumptions) is the section that cannot be recovered from the diff: nine
entries, five of them corrections to my own claims. Records that the
articulation trigger is not merely unmet but STRUCTURALLY unmeetable — the
previous arc left it unrecorded, which is what kept it re-triggerable — and
names four pieces of stale reasoning still in the tree, with files, since that
is the class of staleness nobody greps for.
[Verification]: in-worktree on canonical CPython 3.12.13 with `uv sync
--locked`: smoke 569, deductive 291 — both baseline, since the only non-doc
change is one docstring.
Closes the Opus share of the curriculum-license-loop arc. Three deliverables,
all docs -- no production code.
1. E1-R7-ASSERTION-SPEC.md -- the Opus half of Phase E1. The code move was
already specified by runtime_contracts.md ("defer the single sink emission
to the pipeline serve boundary"); what to ASSERT was not, and the default
sink is None, so nothing exercises the path. Eight invariants (I1-I8) plus
three mechanism rulings (M1-M3), each with the silent failure it prevents.
The three mechanism rulings are the value. M1: stage a turn_log INDEX, not
a captured TurnEvent -- a captured copy is the pre-override snapshot, i.e.
the defect with extra steps. M2: attach_telemetry_sink must NOT flush a
staged turn event, which is the OPPOSITE of what it correctly does for
_pending_reboot_payload; the reboot payload is final when buffered, a turn
event is mid-flight, and flushing on attach would silently restore R7. M3:
the runtime cannot detect whether a pipeline will run (the pipeline wraps
the runtime), so deferral must be explicit opt-in and the no-pipeline path
must stay byte-identical.
All ten source citations verified against HEAD.
2. Plan of record AMENDED with four falsified premises from Phases A/B, with
the original text preserved:
- physics·modal was the wrong first target -- its ceiling is 480 against a
657 threshold, and 8 of 11 bands cannot reach 657 at all. Vocabulary is
the constraint, not chain count. Retarget: philosophy_theology·modal.
- MAX_PREMISE_SENTENCES=16 caps a family at 16 chains, so ADR-0262 §5.1's
own remedy (~219 relations) collapses the band at row 17. No curriculum
band can earn SERVE until premise compilation is query-scoped. New
implementation phase precedes ALL content work.
- authoring a negative today serves a confident wrong "Yes", not UNKNOWN.
- 21 of 25 ratified deduction bands are short on distinct evidence.
3. DIVISION-OF-WORK updated for the handoff: §0 status table with branch names
and merge order, the revised order (E2 -> R5-R7 -> C -> D -> E1(code) ->
parity), the new R5-R7 unit specified to gate-level detail, and a standing
"do not fix" on the deduction ledger exposure.
One correction to my own earlier text: §4 told Phase C to mirror the
deduction producer "exactly". That would replicate the padding -- a flat
CASES_PER_BAND=720 cycling a 28-instance space. Phase C now points at the
`estimation` producer instead (660 distinct, zero repeats), and must
register in AUDIT_SOURCES.
[Verification]: uv sync --locked on canonical CPython 3.12.13; in-worktree
smoke 555 passed, deductive 285 passed (this branch is off main and carries
neither ADR-0264 nor the Phase B tests, so 555 is the correct baseline here,
not the 569 that holds on the stacked A+B branches).
Two prior arcs closed on "the binding constraint is ratified curriculum volume,
not machinery." Verified against code 2026-07-25: the machinery half is wrong in
a load-bearing way, and the correction is the reason this arc exists.
evals/curriculum_serve/practice/ does not exist. seal_ledger exists only for
deduction (evals/deduction_serve/practice/runner.py:96), yet
chat/curriculum_serve_license.py's own docstring names
evals.curriculum_serve.practice.runner.seal_ledger as "the only writer" of the
artifact it reads -- that writer was never built, and
chat/data/curriculum_serve_ledger.json does not exist. And the ceremony stops
short: RatificationReceipt.pending_stages = (arena_queue_entry, ledger_reseal).
So the pipeline is author -> ratify -> ??? -> ??? -> license -> serve. Authoring
curriculum today cannot earn a license at ANY volume. Content is necessary and
currently insufficient. The build is still modest, because oracle.py is already
an independent decision procedure usable as the gold tether and ADR-0263 already
extracted the sealers for exactly a third instance.
Two measured facts shape the content work. `refuted` has NEVER been produced --
the physics lane gold is entailed 14 / unknown 12 / declined 6, and no corpus row
can express it. And bands key on (domain, operator_family), so negative content
must live INSIDE operator_family "modal" with a row-level polarity marker; a
separate modal_negative family would create a new band at n=0 instead of adding
refuted volume to the target band -- the easiest available way to waste the whole
authoring effort.
DIVISION-OF-WORK.md records the tiering criterion and why it is not difficulty.
The evidence does not support a prestige split: in the same 48h window Sonnet 5
found the DEFAULT_SINK bug that wrote outside the repository and did the
six-worktree public_demo archaeology, while Opus 5 mis-diagnosed the CGA hot path
by multiplying a microbenchmark by a call count. Model tier was not the variable;
verification discipline was.
The split is therefore: would an error here be caught by a gate, or is it silent?
Two units are silent-failure BECAUSE THEY ARE THE GATE -- the negative-curriculum
epistemology (wrong => corpus encodes falsehoods and wrong=0 still passes, since
lane gold and the oracle both read the same rows) and the volume-honesty invariant
(wrong => conservative_floor cannot tell 657 independent facts from 16 asked 41
times, so the ledger clears theta=0.99 having earned nothing). Those get Opus.
Everything loud goes to the cheapest competent tier.
Also records the ordering correction: the epistemology ADR must precede the
generator, or the generator gets built twice.
[Verification]: docs-only; no code paths touched. Every referenced path confirmed
to exist and all five line citations confirmed accurate at HEAD (gold.py:1163,
curriculum_serve/runner.py:71, discovery_yield.py:67-70, entail.py:125,
curriculum_surface.py:184). Pre-push gate runs on push.
Plan of record for the generalization arc lands here
(docs/plans/generalization-arc-2026-07-24.md) with the risk-tiered
handoff pack (docs/handoff/generalization-2026-07/); Phase 0.1 executed.
Root-caused the three stale lane pins (docs/research/lane-drift-
investigation-2026-07-24.md):
- miner/curriculum: 5c69b741 (ADR-0244 §2.7) widened content digests
16→64 hex; intentional, pins were simply never updated. Re-pinned
surgically; SHAs triple-run deterministic.
- demo_composition: a REAL serving regression. #76's canonical-first
base precedence in resolve_surface, activated when #96 routed pipeline
turns through the resolver, served the pre-R6 canonical — the register
axis (ADR-0077 R6 substantive + ADR-0071 R4 decoration) was silently
stripped from every pipeline-served turn. T13's back-stamp then made
telemetry mirror the stripped bytes; register-tour claims went red and
the e2e tests pinning the axis (outside smoke) were failing on main.
Fix: response-first base precedence (served bytes = post-guard, post-R6,
post-R4) + new SurfaceResolution.hash_surface carrying the truth-path
canonical-precedence bytes through substrate overrides, folds, hedge,
logos-morph, and the speculative marker. compute_trace_hash folds
hash_surface, so the register axis varies the served surface ONLY and
trace_hash stays register-invariant (ADR-0069 inv C). _prior_surface
(correction binding) stays on the truth path. Dead FailureClass import
and _assessment_residual removed.
Also: generate_claims.py had raised on every run since the
deduction_serve_v1 pin landed without a _LANE_ADR entry — mapping added
(ADR-0256), CLAIMS.md regenerated, --check green.
[Verification]: register tour 6/6 claims (substantive-differs restored,
all_trace_hashes_identical held); 88 tests green in-worktree
(test_surface_resolution incl. 2 new fallback tests,
test_register_substantive_consumption incl. previously-red e2e tests,
test_grounded_open_hedge_arm, test_cognitive_turn_pipeline,
test_warmed_session_lane 10/10 T13 consistency); miner/curriculum lane
SHAs byte-identical across three runs; deduction_serve + deductive_logic
lane reports byte-identical to their unchanged pins; smoke suite via
pre-push gate.
Production-line brief pack for the three independent Phase 3 wiring lanes,
each grounded in fresh read-only research against the current worktree (not
assumed from the plan text):
- Lane A (discovery wiring): is_discovery_eligible + cross_band_discovery_gate
-> DiscoveryCandidate via the contemplation runner's existing sink; live
caller for propose_kappa_line_search so kappa_search_event fires. Flags a
real open question (what feeds surprise_norm for a contemplation finding)
rather than guessing.
- Lane B (sensorium corridor eval): first live consumer of the I-04 feed —
real Audio/Vision compilers -> cognitive_lifecycle -> readback -> GoldTether,
shaped like the adr_0242_v2_energy_compare fixed-replay template.
- Lane C (biography wiring): ADR-0240 harness PASS -> integrate_biography with
I-01 closure asserts and provenance recording. Flags a genuine
identity-substrate design question (mutation vs. proposal-only) for Shay
rather than picking silently.
Corrected dependency DAG: only Lane B actually depends on Phase 2's
cognitive_lifecycle module landing. Lanes A and C touch zero Phase-2 code —
every symbol they wire already exists on forgejo/main — so they can start
immediately, in parallel with Phase 2's own review, rather than waiting.
Also fixes a stale claim this research caught: the plan's substrate table
(Sec 2) named packs/en/readback_rules.py as already-landed §2.3 readback
rules. That file was deleted under audit ratchet W-006; the live substitute
is generate/realizer.py:energy_modulated_surface. Corrected in place.
Per standing production-line-pattern + no-self-dispatch doctrine: brief pack
only, dispatch is Shay's call.
[Verification]: docs-only change, no code touched; no test suite affected.
Implements ADR-0243 §2 honestly per the plan's deviations ledger, correcting
the §3 sketch's three pinned defects (SD-A/B/C):
- Ingress delegates superposition to sensorium_wave_feed, normalizes once at
the owned construction boundary (D-3).
- Relaxation is the imaginary-time semigroup psi <- normalize(exp(-(H-lam0)*dt)*psi)
(D-1) with a certified, never-assumed convergence certificate (D-2): exact
ground energy, achieved Rayleigh energy, eigen-residual, spectral gap, and a
psi_digest binding the certificate to the exact state it certifies.
- Two checkable problem domains: quadratic_well (convex target-decoding) and
propositional (Cl(4,1) blade lattice = assignment lattice of <=5 atoms;
diagonal penalty Hamiltonian; entailment via UNSAT(premises & !conclusion)
scored against independent truth-table gold).
- Egress composes unit-amplitude-density + certificate-binding + versor
closure (routes, does not admit, per the dual of SD-A) + ADR-0006 energy
classes + E0/E1 crystallization policy. Cold states emit a
CrystallizationProposal (epistemic_status pinned SPECULATIVE by the type;
D-5/I-03) — never a vault write.
- Quarantined off-serving (A-04): lazy barrel export, banned in the
transitive subprocess probe and the cohesion AST suite.
Adversarial verification (finder/verifier workflow; most verify agents lost
to a session limit, every surviving finding reproduced in-tree before acting)
surfaced and this closes two real defects beyond the plan text:
- egress_gate admitted any unit state paired with any converged certificate
from an unrelated run, so CrystallizationProposal could package a foreign
psi_digest next to an unrelated certificate_id as false provenance. Fixed
by binding the certificate to its state (psi_digest) and refusing mismatches
(certificate_state_mismatch).
- A state with a spectral gap below the requested tolerance could certify
with ZERO ground-space overlap (energy window alone can't resolve it).
Certification now also requires the excited weight (E-lam0)/gap <= tol
(refusal spectral_gap_below_tolerance), and the degeneracy cluster is
capped at the acceptance window so certificates report the honest
rate-limiting gap instead of absorbing a hairline split.
38 tests (31 original + 7 hardening: certificate-binding must-reject,
gap-refusal + true-ground pair, dense-branch (eigh) refusals, iterate-collapse,
Hamiltonian/egress shape must-rejects, E2 hold route, hardcoded canonical
entailment verdicts independent of the gold function's code shape).
[Verification]: lifecycle+pins+cohesion+transitive 58 passed; in-worktree
smoke 176 passed (131s); fast lane 11750 passed, 108 skipped (574s, exit 0).
Commits the ADR-0243 (Wave-Field Cognitive Lifecycle) proposal verbatim as
Proposed, and the arc-governing implementation plan derived from it plus
docs/analysis/core_cohesion_master_plan.md and the ADR-0241/0242 post-Accept
close audit findings.
The plan records that most of ADR-0243's organs already exist on main
(sensorium feed, WaveManifold, energy classes, GoldTether, surprise/discovery
plumbing, self-authorship, biography, packs/en readback) and that
tests/test_third_door_cohesion.py already pins I-01..I-05, A-02/A-04, and
core_ha absence from the cohesion master plan — so this arc is the §2.2
relaxation reasoner plus three wiring lanes, not a rebuild.
Also pins three defects in the ADR's §3 reference prototype so it can never
be ported verbatim: the egress gate's antisymmetric quadratic form is
identically zero (rejects every state, valid or not); the unitary
relaxation loop cannot dissipate toward a ground state (the honest
relaxer is the imaginary-time semigroup); and the prototype's block-matrix
"pseudoscalar proxy" is a different operator from the real Cl(4,1)
pseudoscalar action despite sharing I^2 = -Id.
[Verification]: uv run core test --suite smoke -q -> 176 passed (133.41s);
uv run python -m pytest tests/test_adr_0243_sketch_defect_pins.py tests/test_third_door_cohesion.py -q -> 19 passed (0.93s)
Complete remaining W5/post-pivot backlog without Docker CI: INV-21 allowlist
dedup, -n auto fast/full defaults, frozen f64 GP Python SOT suite, real
sensorium compiler → ψ → algebraic ρ feed, V2 fib/dyadic/log fixed-replay
evidence without production energy promotion, and project doctrine restored to
local-first + ubuntu-latest:host (no Docker CI for merge).
[Verification]: Smoke suite passed locally (145s, 176 passed); make test-fast
(-n auto) passed twice (11709 passed, 108 skipped each ~11–12 min).
The operational W0-W5 plan that drove the arc was never committed — it
lived only as a gitignored .claude/plan/ artifact in an orphaned
worktree. This commits the durable plan-to-outcome record: phase-by-phase
status against the original plan, the unplanned CI-collapse/local-first
pivot that consumed the post-ratification session, and the remaining
backlog.
Executes the explicit in-session 'Ratify' ruling on the D10 acceptance
packet (docs/audit/adr-0241-0242-acceptance-packet-2026-07-15.md §8 ruling
record added):
- ADR-0241 status: Proposed → Accepted (P7 demote-with-proof accepted as
honest per the #19 precedent; T1/T2 serve-boundary reconciliation
ratified; chiral sign-gate enforced on the accepted state via PR #41).
- ADR-0242 status: Proposed → Accepted (memo fidelity slice closed with no
new defects; V5 anyons remain claim-quarantined/not built; V2 production
promotion stays benchmark-gated).
- CRDT determinism ruling (PR #42) ratified: single-writer bit-exact now;
CRDT behind an explicit multi-writer gate.
- Checklist header, fidelity-ledger §12 status, and living summary §12
updated to the ratified state.
Post-Accept work remains tracked (W5 backlog + packet §7 carry items);
none are conditions of this Accept.
Copied from the Grok session worktree before arc cleanup prunes it.
Summary is the living status surface; the two plans are point-in-time
archives (CI-state headers say 'as of archive').
Maps the AssetOverflow audio-compiler proposal onto the existing
sensorium ProjectionHead boundary (ADR-0013) and the Delta-CRDT
sharded substrate (ADR-0180).
Core mapping decision: the audio chunk boundary IS the CRDT delta
boundary. In-chunk rotor composition (compile_events) is the explicit
serialization barrier ADR-0180 §1.5.2 requires for non-commutative
versor_apply; the resulting AudioCompilationUnit is the order-invariant
delta written at the only semilattice-eligible layer (vault/store).
The compiler's checksum chain supplies the content-addressed merge key
(canonical, ir, projection sha256) that ADR-0180 §1.5.3 demands, making
idempotence structural and the sequential==concurrent trace-hash proof
checkable.
Adds:
- docs/decisions/ADR-0181-audio-compiler-delta-crdt.md (decision + mapping)
- docs/plans/audio-compiler-spec.md (typed AudioIR, operator table,
manifest, numeric determinism, delta interface)
- docs/plans/audio-compiler-eval-plan.md (corpus, gates, A-1..A-6 CRDT
proof obligations, teacher-migration policy)
Docs only; no runtime/core mutation. PR-2..PR-6 substrate work sequenced
in the ADR, with PR-5 gated on ADR-0180 §1.5.4 (T-1..T-4) green on main.