G-9's charge: "law-enforced-by-review is weaker than law-enforced-by-test." Its
stated method — verification pass first, then mechanical PRs — is what made this
worth doing, because the three prohibitions turned out to be in three different
states and only one of them was the state the register assumed.
(a) EXACT RECALL — the real gap, and worse than recorded. "Would a cosine
ranker actually fail a test?" answers NO across nearly the whole surface. The
only import ban in the repository covers exactly one file
(core/physics/wave_manifold.py, via test_third_door_cohesion.py — itself in no
curated suite). Meanwhile generate/realize/recall.py, which IS the recall path,
states the prohibition in its module docstring — "an exact, deterministic
equality scan (no cosine / HNSW / ANN)" — and nothing enforced it. Law asserted
where it executes, enforced nowhere: H-8's failure mode applied to a
prohibition rather than a record.
Now scanned across vault/, generate/realize/, generate/meaning_graph/, field/,
recognition/ for banned ANN libraries AND for hand-rolled cosine* definitions.
The second half matters: an import ban only stops the convenient version, and
ten lines of numpy is the realistic way a well-meaning contributor violates
this. A third pin ties the docstring claim to the scan, so the sentence and its
enforcement cannot drift apart.
(b) GOVERNANCE BYPASS — now exact. INV-07 proves governance works WHEN CALLED;
nothing proved it could not be skipped. Mechanism: no function in
chat/runtime.py may construct a TurnVerdicts without invoking
safety_check.check, and every such call must pass self.safety_pack — because a
bypass need not skip the call, it can substitute the pack. Measured at close:
two verdict-constructing functions, both governed.
(c) SAFETY-PACK NON-SWAPPABILITY — already well pinned; the gap was REACH, not
coverage. tests/test_safety_pack.py pins unratified-pack-refused-in-production,
missing-companion-report-refused, seal-failure-refused, path-traversal-rejected,
missing-pack-fails-closed — and ran in NO curated suite, so a fail-closed safety
contract was verified only after merge. Promoted onto the gate; the new pin
guards that placement rather than duplicating the substance.
FOUR SABOTAGES, EACH OBSERVED RED, each caught by its own pin: a banned library
imported on a recall path, a hand-rolled cosine ranker, a serving path
assembling verdicts without governing, the safety pack demoted off the gate.
Both new files registered in TEST_SUITES["smoke"] on creation (#136). Source
scans only — no runtime behavior, no flag, no serving path touched.
Registers: G-9 CLOSED with the per-item findings; PR-6 marked LANDED.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wcw2pnMBwyvmNyQg4uPEt4
N-9 is the finding, and it PREVENTS work rather than re-scoping it.
WHAT THE PLAN GOT WRONG. N-3 concluded the 23-vs-13 smoke delta was unintended
drift, on two in-repo comments asserting parity, and called that "the strongest
evidence available that the drift was never intended". H-12 repeated it; R-14
built three options on it recommending "raise CI, +46s measured"; PR-4
specified a bidirectional parity pin as deliverable one.
A third artifact answers all of it, and none of them read it.
tests/test_cli_test_suites.py::test_cli_smoke_suite_covers_ci_smoke_gate has
pinned smoke.yml SUBSET-OF TEST_SUITES["smoke"] since before this assessment —
which is why every measurement finds CI-only == 0; a pin, not luck — beneath a
comment headed "DELIBERATELY ONE-DIRECTIONAL — do not 'complete' this by also
asserting local_paths <= ci_paths". Its history is 50fa287d (2026-07-25):
"revert(tests): drop the local-to-CI smoke parity assertion — CI is not a
gate." An earlier agent read the same comment, drew the same inference, made
the assertion symmetric, and reverted it hours later: "That was wrong, and
AGENTS.md says so in a line I had already read."
AGENTS.md:280 — GitHub is "a mirror only; its Actions are billing-locked and
produce dead signals — never chase them." §277 — the workflows are "secondary
observability only." So the local suite is the SOURCE and is deliberately
broader; the delta is the design.
- PR-4 pin 1: WITHDRAWN. It exists, in the direction that protects something.
- R-14: premise corrected in the packet. Option A spends 46s on a workflow
that does not gate; option B would delete real protection for a fiction;
option C's live half is a two-line comment fix, done here.
- N-3's exposure claim was too GENEROUS to CI: for a push that skipped the
local gate there is no automatic check at all. Larger than stated, and not
closable by editing smoke.yml.
WHAT LANDED. Measured: 749 of 877 test files are in no curated suite. The
plan's mechanism ("assign every orphan, or 749 exclusion reasons") is hollow at
that scale — glob topic-suites ("adr": tests/test_adr_*.py absorbs 172) satisfy
the assertion while changing nothing about what executes, which is precisely the
Third-Door objection the plan levels at G-7's own first formulation. All four
demonstrated incidents (#113, #136, negation-survives-articulation,
speculative-subject-lifecycle) were caused by a NEWLY LANDED orphan; none by a
legacy one.
So: a ratchet. tests/test_suite_membership.py + tests/full_only_baseline.txt.
New orphans fail. The baseline is enforced in BOTH directions — a promoted or
deleted file must leave it, so the list can only shrink — and its count is
pinned so bulk movement is a reviewed decision, in the discipline
test_volume_honesty.py uses.
Also: the gate-guarding pin now runs on the gate. test_cli_test_suites.py lived
in `fast`; the pre-push gate runs smoke + deductive. The pin guarding the gate
did not run on the gate.
Three sabotages, each OBSERVED RED: a new unregistered test file, a stale
baseline entry, the parity pin demoted out of smoke.
Note on the delta: now 12 (local 27, CI 15) because this session added three
pins locally. Under the corrected reading that is the design, not widening
drift — the invariant is CI-only == 0, and that is pinned. The registers now
say so; "ten files" was a measurement, never a target.
Process note: `git checkout --` during sabotage cleanup destroyed uncommitted
edits to core/cli_test.py, which were redone. Backups, not checkout, on files
with unstaged work.
Registers: G-7 CLOSED, H-12 amended, R-14 dissolved in the packet, PR-4
re-specified, N-9 added to plan §0.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wcw2pnMBwyvmNyQg4uPEt4
Wave 2's PR-9, whose authority is "mechanical PR" and which is gated on no
ruling. Widened by the 2026-07-28 triage from the accrual guard alone to all
three broad `except` blocks on the turn spine.
Each guard is DELIBERATE and stays: accrual is additive and must never crash a
turn; a pack/catalog failure must not take down logos authority; a probe
failure must not touch the served surface. Narrowing them to ImportError/
OSError — as an external assessment proposed — would convert a malformed
decision object into a turn-spine crash, trading silent failure for
served-surface failure. What was wrong is not the tolerance, it is that each
wrote a value INDISTINGUISHABLE FROM ITS HEALTHY CASE:
- a raising read->realize->determine chain left the same None accrual a quiet
turn leaves;
- a logos decision that raised looked exactly like a turn where logos was
never consulted (both: logos_decision_kind == "");
- a crashed geometric probe recorded the same empty neighborhood as a probe
that ran and found nothing — in the block whose entire job is producing the
data that prices the anti-unification roadmap.
Silence, in the one layer whose constitution is "failures are typed, never
silent" (INV-34).
chat/runtime.py _accrual_swallows / _last_accrual_error, read via
accrual_swallow_telemetry(). _last_turn_accrual is
still None on failure, so _maybe_surface_determination
returns byte-identically — ADDITIVE BY CONSTRUCTION,
and pinned as such.
cognition/result.py logos_error on CognitiveTurnResult.
cognition/pipeline.py logos_error recorded; probe_error,
neighbor_scan_errors, graph_anti_unify_error on the
OOV telemetry.
tests/test_accrual_swallow_telemetry.py — 7 pins. The two behavioral ones were
OBSERVED RED against a build carrying the fields with the recording stripped,
so they discriminate rather than merely pass. Two test bugs of mine were fixed
along the way (wrong logos module path; CognitiveTurnResult has required
fields) — the tests were wrong, not the code.
Registered in BOTH TEST_SUITES["smoke"] and smoke.yml on creation, per #136.
Local/CI delta verified unchanged at exactly ten (local 25, CI 15, CI-only 0),
so this settles nothing R-14 has to rule.
Cleanup as found: three dead imports removed from chat/runtime.py
(_COGNITION_PACK_ID, _TEACHING_CORPUS_ID, engine_identity_for_config), each
confirmed to have no re-export dependence first — workbench/readers.py imports
engine_identity_for_config straight from core.engine_identity. ruff 4 -> 1 on
these paths; the survivor is a pre-existing structural E402.
Registers: H-11 CLOSED; PR-9 marked LANDED in the plan.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wcw2pnMBwyvmNyQg4uPEt4
71542e61 fixed only half of H-13 and asserted a premise that is false. This
replaces it, and records why, because the failure mode is the one this arc
exists to catch.
WHAT WAS WRONG. The refcount rested on "seeding and eviction walk the same
source list, so the counts balance." They do not. The call site's arms are
MUTUALLY EXCLUSIVE (pipeline.py §10b): a proposal is seeded when SPECULATIVE or
released when COHERENT, never both. So a release never balances a claim the
same proposal made, and a COHERENT proposal ALWAYS releases claims it never
held. Refcounting therefore repaired only the sub-case where both proposals had
been taught speculatively. The ordinary case — an unreviewed `wisdom`, then a
separate correction about `practical wisdom` that passes review on its own turn
— still stripped the marker. Measured against the landed refcount:
`sibling marked? False`.
The first attempt's tests passed because their helpers split tokens themselves,
mirroring a call pattern production no longer used — tests written to the fix
instead of to the defect. That is the same "asserted past the evidence" failure
diagnosed in two external assessments earlier today, committed here one commit
later, and catchable by reading fifteen lines at the call site.
WHAT IS CORRECT. _speculative_subjects maps token -> SET OF CLAIMING SUBJECTS.
A token is evicted exactly when the subject that actually claimed it is
reviewed; discarding an absent claimant is a no-op, so a neighbour's marker
survives. Token derivation moved out of the call site into
_speculative_index_tokens, because ownership is what the call site cannot see —
doing the split out there made every token its own claimant, which was the bug.
Tests rewritten to call the cache exactly as §10b does. The lead pin
(test_coherent_proposal_does_not_unmark_an_unrelated_subject) was confirmed to
FAIL against the refcount design before this landed, so it discriminates rather
than merely passing. 13 pins green; the 8 pre-existing lifecycle pins unchanged.
SUITE MEMBERSHIP, resolved rather than deferred. The file pinning this behavior
sat in NO curated suite, reachable only through `full` — which is why the
regression was invisible (G-7's mechanism, on the pin that would have caught
it). Registered now in BOTH TEST_SUITES["smoke"] and smoke.yml, per the #136
precedent that an unregistered pin runs nowhere. Verified the local/CI delta is
unchanged at exactly ten files (local 24, CI 14, CI-only 0), so this is
compatible with all three R-14 options and settles none of them; PR-4 still
owns the standing ten.
Cleanup as found: three unambiguously dead imports removed from pipeline.py
(hashlib, RatificationOutcome, RatifiedIntent). ruff 4 -> 1; the survivor is a
pre-existing structural E402, left alone.
Ratification note unchanged: this changes served surfaces — markers appear on
turns where they previously vanished. Direction is toward disclosure and it
restores ADR-0021 §Articulation's stated intent rather than extending it.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wcw2pnMBwyvmNyQg4uPEt4
The speculative-marker cache seeds a subject AND each >=4-char token split from
it, so two independent proposals can claim the same token ("wisdom" from both
`wisdom` and `practical wisdom`). `_forget_speculative_subject` popped the token
outright on COHERENT promotion — regardless of which proposal had seeded it — so
promoting one proposal stripped the marker from another that was still
unreviewed. Unreviewed material was then served WITHOUT the "(speculative, not
yet reviewed)" prefix: the expensive failure direction, on the surface whose
whole job is telling reviewed knowledge from unreviewed.
_speculative_subjects becomes OrderedDict[str, int] — the value is a reference
count. Seeding increments and refreshes LRU position; promotion decrements and
evicts at zero. Seeding and eviction walk the same source list so counts
balance; where they disagree the count stays positive and the subject keeps its
marker, which is the honest direction to fail. An unmatched release floors at
removal and never goes negative, so it cannot borrow against a later proposal's
claim. The LRU cap survives unchanged as a size valve.
Four new pins in tests/test_speculative_subject_lifecycle.py, ALL FOUR OBSERVED
RED BEFORE GREEN — sibling token evicted, marker lost at the served surface,
repeated teaching cleared by one promotion, and count underflow. The eight
pre-existing lifecycle pins pass unchanged.
Also H-8e — expand_relation_closure's docstring claimed "Cycle: if path would
revisit a node, skip", describing a check the code does not perform. The code
was right: termination is structural (monotone growth over a finite triple set),
and a path-revisit skip would REFUSE SOUND transitive derivations, since a
witness path that revisits a node still proves a true fact. The docstring now
says that, and records that `path` is the witnessing step rather than full
ancestry — extending it would move operator_invocation and therefore trace_hash,
so it is deliberately not done here.
Registers updated: H-13 marked FIXED with the ratification note (this changes
served surfaces toward disclosure, restoring ADR-0021 §Articulation's stated
intent rather than extending it); H-8e marked CORRECTED.
Found while fixing it, recorded not acted on: tests/test_speculative_subject_
lifecycle.py — the file pinning this exact behavior — is in NO curated suite,
reachable only through `full`. G-7's mechanism, caught on the pin that would
have caught the defect. Assignment left to PR-4; adding it to TEST_SUITES
["smoke"] alone would widen N-3's ten-file delta and prejudge R-14.
Pre-existing ruff findings in pipeline.py (3 unused imports, 1 E402) confirmed
present before this change and left alone — module-top, not adjacent to the edit.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wcw2pnMBwyvmNyQg4uPEt4
Two external first-principles assessments of CORE were verified against code
line-by-line at 8f0ccfe3. What survived is entered; what failed is recorded in
the audit's negative space with the refuting file named, per the register's own
discipline.
Entered:
H-13 — the speculative-marker cache over-evicts shared tokens: promoting one
proposal to COHERENT pops tokens regardless of owner (pipeline.py:736-739,
:1045-1055), so a sibling proposal's still-SPECULATIVE material is served
without its marker. Honesty regression, served direction. Remedy: refcounted
cache, failing test first. (The source assessment described this seam with
the direction inverted — under-eviction; the code over-evicts. The check
that caught the inversion is what confirmed the bug.)
H-14 — _run_turn is 759 lines (pipeline.py:189-947) under a thin-wrapper
docstring, with finalize_turn_trace_hash x2 / finalize_turn_surface x1
back-stamps as the measured symptom. H-4's sibling: refactor ADR, PR-10's
byte-identical-trace bar, and the learn stage named stateful.
H-8e — inductive_closure.py's docstring claims a path-based cycle skip the
code does not perform (:106 vs :189-193) — and the code is the right side:
the monotone fixed point needs no path check, and adding one would refuse
sound derivations. path records only (a,b,c) for longer chains (:198), so
trace provenance is incomplete. Docstring fix is mechanical; extending path
changes operator_invocation bytes -> trace_hash, held to the trace-change bar.
PR-9 widened — the logos-authority bare except (pipeline.py:555) and the
three OOV-probe swallows (:605-657) join the count-the-swallow scope; same
remedy shape (record repr(e), keep the backstop), explicitly not the
narrow-catch alternative.
R-4 packet addition — first collapse candidate: composed_surface +
transitive_surface + transitive_max_depth -> chain_depth:int, justified by
ADR-0083's own docstring ladder; ruled in-lineage, not ad-hoc.
R-12a note — lived_life.json staleness recorded as a question; the proposed
PID-attestation fix rejected (refuses every reboot resume; PID reuse).
Cleared, with the refuting file named: EpistemicState compression
(vault/store.py, policy.py's ADR-0206 partition), the EpistemicState x
NormativeClearance product type (erases refusal evidence — H-3 rebuilt as a
type), PID attestation, path-based cycle skipping, the depth-enrichment cache
(pack_resolver.py:19 already lru_caches the cost), and the unified reasoning
engine as-refactor (trace_hash change + capability widening + discards the
ROBDD engine one merge after ADR-0265 ratified denial).
Register ranges updated to G-1..G-21 / H-1..H-14. Docs only; no runtime
behavior, no flag, no test changed.
[Verification]: uv run pytest tests/test_adr_index.py
tests/test_adr_status_governance.py tests/test_adr_0252_s5_blindness.py -q —
327 passed at this tree.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wcw2pnMBwyvmNyQg4uPEt4
The branch was re-created with SSH signatures before landing, which changed my
commit SHAs. Four citations of the pre-registration commit — the verdict's
header and closing note, G-1, and the plan's Track A section — pointed at
dfc394d2, which is not in main's history. They now point at 299c92be, which is.
Same tree, same message, same ordering, signature added. The claim the verdict
rests on is unchanged and checkable at 299c92be: that commit contains the
thresholds and no results. Recorded as a note in the verdict document rather
than swapped silently, because a document citing a commit absent from its own
repository's history is precisely the failure mode its §1 catalogues — and this
one would have been self-inflicted.
Docs only.
[Verification]: uv run pytest tests/test_adr_index.py
tests/test_adr_status_governance.py tests/test_adr_0252_s5_blindness.py -q —
327 passed.
Track A of docs/assessment/50-execution-plan.md §6, executed under its own
protocol. Criterion pre-registered at dfc394d2 (that commit carries the
thresholds as importable constants and NO results); this commit carries the run.
VERDICT: NO-GO. Full credit by ADR-0252 §5.4's own terms.
docs/research/sme-experiment-verdict-797ebad5.md
evals/structure_mapping/adr0252_s5/results/report-797ebad5.json
deterministic_digest b3d9d27592e213104c51bcace7415fd819d722a1b06f7d0a5ca65bd5a234e4ec
53 cases, 1378 pairs, 0.0% non-convergence — no exception contributed to any
number. RS-A (structure-only) separates perfectly, AUC 1.0000, margin +0.0867,
and fails structure-sensitivity. RS-B (attribute-bearing) fails all three.
The mechanism, measured rather than argued: the similarity quotient that would
deliver attribute-invariance is the same quotient that annihilates structural
contrast. An add-vs-subtract minimal pair — one entity, identical numbers, one
relation kind changed — aligns at residual exactly 0.0, its two configurations
being related by a PROPER rotation about e1. Sweeping the attribute weight
(committed as diagnostic_sweep), structure-sensitivity fails at every setting,
and every regime where the SME property survives is a regime where attributes
contribute nothing: AUC 1.00 -> 0.97 -> 0.83 -> 0.69 as they begin to matter.
Scope stated narrowly: this refutes H1 for embeddings that encode role-structure
as point positions aligned by conformal Procrustes under similarity. The
argument is about the quotient, so it generalises across that class; it does not
refute every Cl(4,1) representation, and it does not touch the symbolic
structure-mapping lane already in evals/structure_mapping/.
Two findings that were on nobody's list:
N-8 — the experiment was NOT unrun. rnd/sme-experiment-v2 @ 96e5f468 is titled
"Verdict: GO" and rnd/structure-mapping-experiment @ fc9d0c14 carries an earlier
one. Neither survives inspection: attempt 1 leaked the S1-S4 label into the
embedding; attempt 2 was blind and then took its separability from
`except ValueError: res = 1000.0` — a solver exception counted as a distance —
on a corpus 46/51 of which is outside holdout_dev/v1 with nothing marked, with
duplicate graphs, colliding ids, and an extractor that was never committed. The
register, the plan and the ADR all read the same absence and inherited the same
error for nine days. A branch tip is not a record.
G-21 — the math reader returns a selected graph for 5 of 500 holdout_dev/v1
cases (1.0%), all one skeleton; 24/150 on the public lane. That is why §5.1's
four-structure corpus is not extractable, and it is a sharper measurement of the
comprehension frontier than G-3's construction count.
Registers updated: G-1 carries the verdict, H-10 confirmed and discharged, G-21
added, plan §0 gains N-8, Track A closed, synthesis frontier 2 rewritten.
Pins: tests/test_adr_0252_s5_blindness.py, each observed red before green
(label leak and duplicate-graph sabotage both caught).
Off-serving — evals/structure_mapping/adr0252_s5/ is imported by no serving
path, emits no answers, and changes no flag.
[Verification]: 797ebad5 + this branch — `uv run core test --suite smoke -q`
641 passed in 199.76s; `uv run ruff check` clean; report regenerated after lint
with an unchanged digest.
Track A, per 50-execution-plan.md §6: "state the GO/NO-GO criterion in writing
BEFORE running (the ADR's §5 conformance bar, not a criterion chosen after
seeing results)." This commit carries the criterion and the code and NO results.
Why the protocol is load-bearing here rather than ceremonial: the §5 experiment
is not unrun. It has been run twice and returned GO twice, on unmerged branches,
and neither run's rule was binding.
- rnd/structure-mapping-experiment @ fc9d0c14 — disowned by its own successor:
the S1-S4 label entered the embedding, so Procrustes ran on identical
matrices per structure.
- rnd/sme-experiment-v2 @ 96e5f468 — blind, and then measured separability
with `except ValueError: res = 1000.0`. Its GO test cross_mean > 2*same_mean
is satisfied by that sentinel alone. A solver exception is not a distance.
Instrument characterised before use, on dummy clouds: conformal_procrustes has
two branches. The (5,K) Kabsch+Umeyama path never raises and is invariant to
rotation, translation AND uniform scale (identical 1.8e-16, rotated 7.8e-16,
translated 3.9e-15, scaled x2.5 1.4e-14) while separating non-similar
deformation (5.9e-1) and unrelated clouds (1.1e0). The mixed versor/point
sequence path performs field conjugacy and raises. Attempt 2 used the second;
this uses the first, and treats a raise as non-convergence — excluded, reported
as a rate, never counted as separation.
Corpus fact that forced the design, measured at 797ebad5: the serving reader
returns a selected graph for 5 of the 500 holdout_dev/v1 cases (1.0%), all with
the same skeleton. §5.1's four-structure corpus is not extractable from
holdout_dev/v1 today, so §5.1's own escape hatch is used and MARKED — 5 real
cases, 48 synthetic from four declared templates. A verdict from this corpus
speaks about the geometry, not about coverage; §5.5's compression estimate is
not answerable at 1.0% coverage and is not attempted.
Off-serving. Imported by no serving path; no answers emitted.
PR-1's amendments were derived at ed06dd64. main has since moved (#140, #138),
so every amended claim was re-measured against code at 797ebad5 before landing:
- TEST_SUITES["full"] == ("tests/",) (N-1) holds
- 5 tests/test_l10_*.py, none marked quarantine or slow (N-2) holds
- smoke suite 23 files vs smoke.yml 13, same ten-file delta,
and zero CI-only files (local is strictly the superset) (N-3) holds
- RuntimeConfig: 32 booleans, 28 off, the same 4 on (N-7) holds
- CONTINUOUS_LIFE_CONFIG_FLAGS still omits accrual (N-6) holds
- ADR-0264 §4.1 self-supersession banner in place (N-5) holds
- 18 resolve_promotable_* organs in generate/derivation/ (H-8b) holds
One correction to the amendment itself. H-8d said CONTINUOUS_LIFE_CONFIG_FLAGS
"contains neither claim's subject." It contains one of them: consolidate_
determinations IS forced. The false clause in both docstrings is the one naming
accrue_realized_knowledge as co-enabled, and a third comment on persist_session_
state makes the same shape of claim and is true. The entry now says that, and
says it was caught on re-verification — the same standard §0 holds itself to.
Docs only. No runtime behavior, no flag, no test changed.
scripts/hooks/pre-push describes its own step 1 as "the smoke suite — exact
CI-gate parity" while running 23 files against the CI gate's 13. That is the
second in-repo assertion of the parity H-12 falsifies, and it is inside the
tooling that enforces the protocol.
The corrections derived in 50-execution-plan.md §0, applied where the wrong
claims live. Every amendment is marked [AMENDED N-x] inline so the register
carries its own correction history rather than quietly reading correct.
Gap register — four entries amended:
- G-5 the soak RAN and passed (5000 beats, reboot at 2500, all four gates,
aed273b1). Retitled: what is owed is the committed artifact, the pinned
deterministic_digest, and a cadence — not the run. Both prior claims
withdrawn with their causes: "no suite contains any l10 test" was a
scan artifact (TEST_SUITES["full"] is a directory), and the pins
execute twice a day (post-merge + nightly cron).
- G-7 respecified. The proposed meta-check was already satisfied and would
have shipped green proving nothing — a hollow gate in the entry
proposing to abolish hollow gates. Now two pins: gate parity, and
curated-suite membership EXCLUDING full.
- G-8 28 default-off flags of 32 RuntimeConfig booleans, not seventeen.
- G-10 the 16-premise cap was removed by ADR-0264 R5 on 2026-07-26; the ADR
carries a self-supersession banner directly under the heading Phase 4
quoted. No engineering prerequisite remains — R-8 alone gates it.
- G-19 note: the 21/25 exposure is already pinned in test_volume_honesty.py,
so the work is applying the demotions, not discovering them.
Hindrance audit:
- H-12 added — the local smoke suite (23) and smoke.yml (13) have diverged by
ten files. Counter-evidence stated first: AGENTS.md makes the local run
the merge gate and it is the superset, so nothing is unguarded. What is
real is one comment claiming an equality that does not hold, and the
push that skipped the local gate.
- H-8 gains instance (d), inside the code: two flag docstrings assert a
production profile CONTINUOUS_LIFE_CONFIG_FLAGS does not have.
- H-1 gains the already-pinned note.
Also: correction note on the 2026-07-25 verification doc (a corrective
document that introduced the error at H-8c), and a staleness banner on
MIND-PHYSICS-BLUEPRINT.md pointing at the taxonomy that dissolved it.
The two ratified-ADR amendments (ADR-0146, ADR-0252) are NOT here — they are
drafted in full in 50-rulings.md R-12 and land on that ruling, because editing
a ratified ADR is Shay's authority even when the edit changes no decision.
Docs only. No runtime behavior, no flag, no test changed.
scripts/hooks/pre-push — the automation of the AGENTS.md local-first protocol
— opens by describing its own step 1 as "the smoke suite — exact CI-gate
parity". It runs 23 files; the CI gate runs 13. That is the second in-repo
assertion of a parity that does not hold, the first being core/cli_test.py's
audio block, and it is the strongest evidence available that the drift was
never intended rather than a deliberate narrowing.
Phase 6 of the holistic assessment: what follows from it, and what it needs
ruled before anything else can be sequenced.
`50-execution-plan.md` — five waves (scrub/rule → delete → simplify/enforce →
accelerate evidence loops → automate last) plus five frontier tracks, covering
every G-1…G-20 and H-1…H-12 entry, with four hard dependency gates and nine
risks stated before they are incurred.
`50-rulings.md` — R-1…R-14. One decision per section: the evidence verified at
ed06dd64, the options enumerated, a recommendation with its reasoning, and the
exact diff that follows from each choice, so ruling costs one word. Nothing in
it recommends reversing a ratified decision; R-12 amends two ADRs' records
without touching either decision.
§0 of the plan carries SEVEN corrections to the assessment, all found by
reading code, workflows and ADR supersession banners — none by re-reading
documents. Four change planned work:
- N-3 (new) the local smoke suite (23 files) and smoke.yml (13) have diverged
by 10 files. Severity is LOWER than this plan's first draft stated: AGENTS.md
makes the in-worktree run the merge gate and CI secondary observability, and
the local gate is the superset — so nothing is unguarded. What is real is one
in-code comment claiming an equality that does not hold, and the push that
skipped the local gate, for which CI is the only automatic check.
- N-4 the L10 soak HAS been run — 5000 beats, reboot at 2500, all four gates
pass (contract.md, landed aed273b1). G-5's "never produced an artifact" is
wrong. The debt is the ceremony: no committed report, no pinned
deterministic_digest (the contract's own unmet closing instruction), no
cadence. Prose with no pinned digest is testimony, not evidence.
- N-5 G-10's blocker does not exist. ADR-0264 §4.1 carries a self-supersession
banner: R5 removed the 16-premise cap on 2026-07-26, and four bands would
earn SERVE the moment a ledger is sealed. PR-13 is WITHDRAWN and the whole
throughput frontier reduces to one ruling (R-8).
- N-7 the flag count is 28 of 32 RuntimeConfig booleans, not seventeen.
Plus N-1 (the orphan scan artifact: TEST_SUITES["full"] is a directory),
N-2 (the L10 pins run twice a day, post-merge and nightly), and N-6 (H-8 has a
fourth instance inside the code — two flag docstrings assert a production
profile the production profile does not have, which moves R-3 decisively
toward "incomplete flag set").
Docs only. No runtime behavior, no flag, no test changed.
40-assessment.md — the verdict in one paragraph (skeleton real, discipline
exceptional, the two deepest commitments unproven in opposite directions);
the cognitive cycle stage-by-stage with the honest sentence for each; what
is excellent, stated as findings; the macro picture (built-and-dark,
capability outruns proof, the record decays faster than the code); THE
FIVE FRONTIERS (the reading, the verdict, the chooser, the proof of life,
the throughput — everything else on the registers is hygiene, enforcement,
or ceremony); the recommended attack order in five waves sequenced by the
mastery algorithm (scrub/rule -> delete -> simplify/enforce -> accelerate
evidence loops -> automate last, with the warning that an always-on
process consolidating an empty set is "garbage at high speed" and CORE
came within one flag of it); the charter's four questions answered
directly; and the maintenance contract that keeps this directory from
becoming the next dead instrument.
README.md — the directory index and reading order.
The assessment is complete: 21 documents, four phases, three
self-corrections, every claim SHA-stamped at 8927c563.
30-gap-register.md — CORE's first LIVE gap register since docs/gaps.md
closed its 26th entry (supersession proposed for ruling). 20 entries in
four tiers, each with evidence, deciding authority, and leverage rank:
- Tier A (frontier-blocking): G-1 the unrun ADR-0252 §5 experiment
(leverage 1 — authorized, scaffolded, verdict-less; the paradigm governs
ALL future comprehension); G-2 the #138 fabrications (pre-labeled
measured-and-pinned, held for ADR + ratification); G-3 reader 19 vs
writer 1739; G-4 CR-2 no-chooser (the AGI-grade conceptual absence);
G-5 L10 proof debt (no artifact, no suite, no cadence); G-6 the
half-gated lived learning loop.
- Tier B (enforcement debt): G-7 orphaned-pin meta-check (the highest-
leverage single mechanical change); G-8 flag-default register; G-9 three
doctrine laws without verified failing pins; G-10 curriculum scoping +
absent ledger; G-11 identity authorization bar unstated.
- Tier C (one-line rulings): CR-3 efferent, CR-4 temporal stance, CR-1
attention ADR, the daemon's owning ADR.
- Tier D (latent/carried): aspect-arm defect class (generate/templates.py
:79, unreachable today), sensorium entry criterion, curriculum-formation
bypass (unverified carry), Wilson evidence debt, refusal materialisation.
- Plus what is NOT in the register and why (deferred-with-ruling is the
scripture model; benchmarks excluded by the completeness criterion).
31-hindrance-audit.md — 11 entries ranked by leverage, each with fitness
verdict, evidence, proposed better home, deciding authority; decides
nothing. Headliners: H-1 Wilson/replay counting basis (wrong-solution in
the counting, not the gating — 21/25 bands short; the re-count may demote
licenses and that is the mechanism working); H-2 decoration as testimony
(DriveGradientMap, InhibitionMask — deletion per mastery step 2); H-3 the
typed refusal discarded at the public boundary; H-4 extend the resolver's
declared-precedence pattern upstream; H-8 three record/code contradictions
(each one paragraph to fix); H-9 dead instruments standing as if live.
Plus five examined-and-CLEARED candidates (the 18 organs' continued
service is governance working; pure-Python-by-default is measured-correct;
flag-gated conservatism is not hindrance — unregistered darkness is).
Eight component cards in 20-component-cards/: the four zero-subsystem zones
(comprehend-organ, determine-phase, realize-phase, sensorium-falsification)
plus always-on-process, derivation-organs, surface-selection,
attention-allocation. Plus 05-phase3-findings.md and correction banners on
the M6 and M4 layer cards.
CORRECTIONS (C-1..C-5):
- THREE more map live-serving labels demoted to live-internal:
comprehend-organ (a MATH SETUP ROUTER, not chat comprehension — imported
by neither serving entrypoint), determine-phase and realize-phase (both
behind accrue_realized_knowledge=False / idle flags; NO default-config
serving turn touches any of the three).
- Phase 2's M6 card overstated ephemerality: Shape B+ persistence exists
(persist_session_state, daemon-forced, "restored bit-exactly").
- Phase 2's M4 card understated the resolver: surface_resolution.py IS a
declared-precedence resolver for the pipeline seam; only the upstream
composer arms remain ordered branches. Third Door refines to "extend the
existing pattern upstream."
- 34-vs-18 RESOLVED: 18 resolve_promotable_* organs existed AT the ADR-0252
ratification commit; "34" counted modules (~32-33). No consolidation has
occurred; the governing ADR's headline number has no stated basis.
- The 2026-07-25 verification doc's claim that accrual "is enabled by the
production L10 process" is contradicted: CONTINUOUS_LIFE_CONFIG_FLAGS is
exactly {persist_session_state, consolidate_determinations,
strict_identity_continuity}.
NEW FINDINGS (F-6..F-10):
- F-6 THE CONTINUOUS LIFE MAY CONSOLIDATE AN EMPTY SET: the daemon forces
the consolidator ON but not the accruer, and realize_comprehension — the
only turn-path writer of realized facts — sits behind the accrual flag.
The two halves of the lived learning loop are gated by different flags
and only one is forced. Undocumented either way.
- F-7 ADR-0008's Allocation Physics LANDED, mutated, ungoverned: curvature
kernel -> salience adapter -> attention threshold plan -> candidate
intersection, with budget feedback making attention SELF-NARROWING
across a walk. InhibitionMask is decoration. top_k=16/threshold=0.3 have
no recorded derivation. CR-1 closes with a one-page ADR.
- F-8 two load-bearing naming traps (comprehend-organ; realize vs realizer).
- F-9 REALIZE is sound; its ceiling is the reader that feeds it (the #138
fabrication locus — measured/pinned/held, recorded not re-discovered).
- F-10 _accrue_in_turn swallows exceptions into a no-op with no telemetry.
Phase 4 seed list consolidated: 8 hindrance candidates, 10 gap candidates,
each with its deciding authority. Method note recorded: three phases of
corrections, and nothing in the chain was caught by re-reading documents.
Fills the taxonomy with evidence. Every liveness label re-verified at
8927c563 rather than inherited from the 2026-06-09 system map. Three
inherited claims did not survive, and every one of them came from a
document while every falsification came from reading code.
CORRECTIONS:
- Phase 0 Finding 0-C was WRONG. The L11 always-on process IS BUILT:
chat/always_on.py::run_continuous, chat/always_on_daemon.py::run_daemon
(single-instance lock, SIGINT/SIGTERM stop, load-time identity guard),
CLI `core always-on`. Landed 2026-06-14 — five days AFTER the system-map
snapshot that declared no forever entrypoint exists. The real finding is
sharper: built, with a complete falsifiable soak harness, never run to a
recorded artifact, and enforced by NO SUITE AT ALL.
- CR-1 attention/allocation is not a missing layer but a live undocumented
one: generate/stream.py:255-263 runs SalienceOperator -> AttentionOperator
and gates every generation step; use_salience defaults True. It owns the
~73%-of-turn hot path and has no ADR, no card, no layer in any ratified
articulation. (generate/salience.py COMPOSES core.physics.salience — not
a duplicate; that false lead is recorded, not propagated.)
- CR-2's components exist: DriveGradientMap and ExertionMeter are both
constructed in chat/runtime.py. DriveGradientMap is NEVER READ — textbook
decoration by the sabotage test. ExertionMeter runs but feeds telemetry
only; fatigue gates no decision. The claim survives and sharpens: CORE has
drive objects and no chooser.
STAGE-COVERAGE AUDIT: 7 of 9 covered; non-text ingest uncovered (59
sensorium modules reach no serving path); the cycle's runner claimed-only.
CROSS-CUTTING: F-1 built-and-off is the dominant pattern (17 flags default
False, only deduction_serving ratified ON) with no register of the set or
what would flip it. F-2 enforcement lags capability — orphaned pins are
undetectable because suite tuples are hand-curated. F-3 formation's
six-boundary trust standard is not applied at M2, the surface facing
untrusted user text. F-4 ADR/code contradictions are load-bearing (the
daemon has no ADR while ADR-0146 rejected the daemon shape; ADR-0252's
"34 surface organs" does not reproduce — 18 found). F-5 what is excellent,
stated plainly: the typed learning boundary, selection-not-rewrite, the
non-hardening invariant, fail-closed lane shapes.
No layer is wrong-solution. Two candidates deferred to Phase 4 with
evidence: Wilson/replay independence in licensing, DriveGradientMap.
Fixes the decomposition Phases 2-3 fill and Phase 4 audits against, per
Pillar I: criteria before judgment. Five decisions recorded explicitly:
- D1 The five unreconciled articulations answer five DIFFERENT questions
(what for / what happens today / by what mechanism / judged how / built
where) and become axes of one taxonomy rather than competitors. Functional
axis = the AGENTS.md north star; structural axis = 7 macro layers (M0
Substrate, M1 Knowledge & Memory, M2 Afferent, M3 Comprehension &
Reasoning, M4 Expression & Serving, M5 Learning & Growth, M6 Continuity &
Process) + 2 cross-cuts (MG Governance, MV Verification), grouping all 33
system-map zones with straddles recorded honestly. Mind-physics blueprint
dispositioned element-by-element (identity/compositional/renderer =
superseded by stronger implementations; Allocation Physics and
DriveGradientMap = orphans -> Candidate Register).
- D2 System-map schema EXTENDED, not replaced: 7-value liveness kept;
four missing dimensions added as orthogonal fields — evidence (with
would-fail-if-absent sabotage bit), capacity (designed/measured/ceilings),
design-vs-build split, fitness (6-value: fit/strained/misplaced/
wrong-solution/superseded-in-place/undetermined). Liveness ⊥ fitness:
the 34 organs are live-serving + superseded-in-place, a state no merged
enum could express.
- D3 Completeness criteria fixed: coverage = evidence-bearing ownership of
a functional stage; deferred-with-ruling ≠ missing; pins must run.
- D4 Candidate Register: CR-1 attention/allocation (the ~73%-of-turn-time
hot path has no owner), CR-2 agenda/drive (mechanisms without a chooser;
L10 risks landing as a heartbeat with nothing to want), CR-3 efferent
action (needs an explicit deferred-vs-out-of-telos ruling), CR-4 temporal
self-location (determinism vs lived time, undesigned). Considered-and-not-
registered recorded (sociality, affect, embodiment, self-governance-as-
layer) so the boundary is visibly examined.
- D5 Assessment output is COMMITTED (reviewable, versioned, visible);
system map stays local as a regeneratable navigation index. Staleness
handled by verified_at SHA stamps on every card.
Phase 2 work order: nine layer cards, priority M6 > M3 > M4 > M5; re-verify
every map liveness label; run the stage-coverage audit with evidence; the
four zero-subsystem zones scoped honestly and queued first for Phase 3.
Opens the holistic macro→micro assessment of CORE's cognitive-cycle design
and implementation fulfillment. Read-only; no runtime behavior changes.
Method is governed by docs/conceptualizing_engineering_mastery.md (committed
here because the assessment cites it as its method): Semantic Rigor,
Mechanical Sympathy, Third Door; delete before optimizing; automate last.
Phase 0 findings:
- 0-A CORE carries FIVE unreconciled macro articulations of its own cognitive
cycle (AGENTS.md north star; AGENTS.md live path; the 2026-05-12 draft
three-physics-layer blueprint; ratified ADR-0252's five paradigm stages; the
system map's 10-band L0-L11 layering). The blueprint's allocation/attention
layer (Salience/Attention/Inhibition) exists in no other articulation.
- 0-B .system-map/ is the best existing macro→micro artifact and is 48 days
stale, gitignored/local-only, and carries four zero-subsystem zones — three
of which sit on the serving path.
- 0-C ADR-0252 §5 — the experiment gating the governing paradigm's build — has
never returned a verdict (two unmerged rnd/ worktrees). The 34 surface organs
the ADR diagnoses as the error keep serving. L10 blocks all 7 OPEN W-* items;
field + T1 vault are discarded on exit, so "one continuous life" is today
many short lives sharing a checkpoint.
- 0-D No live gap register: docs/gaps.md is 26/26 closed, the liveness ratchet
is L10-blocked and stale, docs/analysis/ is a chronological archive.
- 0-E 333 ADRs, flat numbering, status not reliably machine-extractable;
INDEX-by-domain is 21 files behind; the Blueprint reserved 0254-0261 for
intents never materialised while those numbers were minted for other work.
- 0-F Measured: CGA is ~73% of turn time via cga_inner/geometric_product
(~34k calls/turn), NOT versor_condition (0.22%). Rust backend off by default,
parity question open and blocked. MLX in no runtime path.
- 0-G The 2026-07-25 verification precedent falsified ~1/3 of an external
blueprint's items by reading code — the bar for every downstream phase.
Phase 1 receives the system map's 17-field proto schema and 7-value liveness
vocabulary, plus the four dimensions it lacks (evidence pointer, capacity,
design-vs-built, fitness judgment) and five decisions to make explicitly.
PR #138's fabrication findings are recorded as measured-and-pinned, held for
ADR + ratification — never re-discovered, never fixed here.
Phase 5 item 1 asked for the overlap to be sized "by measuring the reader's
construction set against the writer's rather than by growing corpora blindly".
New lane `evals/construction_inventory` does that: it sweeps the writer's whole
parameter space (every RhetoricalMove x IntentTag x predicate x quantifier x
tense x aspect, both public entry points, 32292 cells), quotients it by the
reader's OWN function-word skeleton, and comprehends each construction under
three vocabularies.
writer constructions 1739
reader constructions 19 (mint-site AST-guarded)
overlap, faithful 6
accepts but MIS-READS 22
refuses 1711
vocabulary-dependent 0
Faithfulness, not acceptance, is the criterion — and that reverses two claims
in the plan's §6 RESULT, using a metric that was already on the page:
* g_read_rate is 1/293 but **g_args_rate is 0.0**. The one surface that "reads",
`all molecules are defined as compounds`, is comprehended as
`subset(molecule, defined_as_compound)` — the reader chunked the writer's verb
phrase into a class name. It accepted; it did not comprehend.
* "one construction wide" was wrong both ways: zero on that corpus, six over the
writer's actual output space. A corpus cannot report an inventory's size.
Three findings re-order Phase 5 item 1:
1. The reader FABRICATES on 22 constructions — neither reads nor refuses.
`every dog is a mammal` -> member(every_dog, mammal);
`furthermore, all dogs are mammals` -> asserted(furthermore).
Both are ordinary user English, not writer artefacts. Root cause: _RESERVED
lacks the function words the writer emits, and _parse_propositional accepts
any single token as a fact.
2. It reaches SERVED output. deduction_surface recites
`Given: furthermore; p implies q; p.` — a premise the user never stated — and
chat/runtime.py realizes declarative turns into the held self, so a
fabricated atom is vault-writable. Widening the inventory first would widen
the fabrication surface with it.
3. ADR-0265's defect class survives inside ADR-0265's designated owner of clause
grammar: the four aspect arms of _inflect_predicate bind `negated` to a
wildcard and never read it, so `dog has been defined as mammal` serves both
the assertion and the denial (10530/16146 points). Unreachable today — no
producer sets aspect — so a loaded gun, not a casualty. It survived because
ADR-0265's invariant is structural (is `negated` threaded?) and cannot see an
arm that receives the flag and ignores it. A behavioural sweep can.
The two fixes are written already, as the mutations that turn the defect pins
red. They are NOT applied here: they change what CORE comprehends from user
input, which is a serving change on the truth path — authorization-gated, ADR
first, on the ADR-0261 §5.1 refuse-don't-drop precedent.
Guards, so the tables cannot rot: reader constructions are pinned to an AST
count of the reader's 10 mint sites; the declared tense/aspect axes are pinned
to _inflect_predicate's match arms; the committed corpus is pinned to the
fillers in use. 14 pins, 13 mutations observed RED.
[Verification]: in-worktree, CPython 3.12.13, uv sync --locked.
deductive 517 (was 503, +14 — count moved, registration confirmed)
smoke 641 (unchanged; the file is registered in `deductive`)
lane SHAs 11/11 match, no pin edited
pyright 0 errors on all new files
mutations 13/13 red, including both fabrication fixes
Serving-path authorization for the negation fix in this PR. The ADR is
Accepted rather than Proposed because the defect it removes was LIVE behind a
shipped flag (realizer_grounded_authority), not latent: CORE served the
affirmative of propositions users denied.
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)
Ratified by Joshua Shay 2026-07-26. All nine rules are implemented and merged to
main @ 803703fc: R5-R7 (#120), R9 (#117), R1-R4/R8 (#125). The status line names
the enforcement pins so the record points at what holds it up.
Also discharges a staleness the ratification would otherwise have blessed. §4.1's
heading — "No curriculum band can earn a SERVE license under the current
architecture" — is NO LONGER TRUE of the running system, and it was falsified by
this ADR's own R5: the finding rested on "the premise cap holds a family to <=16
chains", and query-scoped compilation removed that cap. Post-R5, four bands would
earn SERVE the moment a ledger is sealed. Leaving that heading unqualified in an
Accepted ADR is precisely the ADR-0256 shape — a governance record asserting
something false about live code.
The §4.1 CONCLUSION survives, for a different and stronger reason, and the note
says so: reliability is commitment precision and a correct UNKNOWN is a
commitment, so a band clears theta_SERVE on non-commitments alone
(conservative_floor(660,660)=0.990046). Licensable evidence is 99.0-99.98%
non-entailed; max entailed volume in any band is 9. So §4.1's "≥97.6%
non-entailed" arithmetic was directionally right and its CAUSE was wrong — it is
not the premise cap that makes a curriculum license dishonest, it is the absence
of a mix rule. The binding constraint is now the outcome-mix ruling (§5, still
open), and nothing is licensed while it is unmade: the ledger is absent and
`core proposal-queue reseal` refuses to grant a license without
--allow-new-licenses.
[Verification]: in-worktree on canonical CPython 3.12.13 with `uv sync --locked`:
smoke 621 (unchanged), and 335 passed across test_adr_status_governance.py /
test_adr_index.py / test_volume_honesty.py. Status parses as "Accepted …" under
the governance regex and the banned `ratify-on-merge` predicate is absent. No
flag moved; no code changed.
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.
Plan §6A, report-only per DIVISION-OF-WORK §4. Both halves ran. The cargo half
is real evidence; the LANE half is vacuous, and saying so is most of the point.
cargo test (PYO3_PYTHON=/opt/homebrew/bin/python3.12, --offline): 43 passed,
0 failed across 7 suites including test_crdt_hash_parity.rs. The plan's read
was right — cargo 1.97.1 and the registry cache are present locally and the
cloud session was blocked only by sandbox network policy.
Lane parity: 11/11 pinned SHAs match under both backends. That number means
nothing. Sabotaging EVERY core_rs callable to raise and re-running under
CORE_BACKEND=rust still gives `lanes: 11/11 match pinned SHAs`, exit 0. Three
sufficient reasons:
- The hot path bypasses the dispatch. algebra.cga.cga_inner is NOT
algebra.backend.cga_inner; 69 call sites import the hot functions from
algebra.cga/algebra.cl41 directly vs 24 through algebra.backend. The ~34k
cga_inner->geometric_product calls/turn that plan §6C calls ~73% of turn
time never reach the dispatch.
- The dtype gates reject the runtime workload. versor_condition IS imported
from algebra.backend by pipeline.py:24, and still falls through: the Rust
arm requires f32 and the wave-field workload is f64.
- Every dispatch arm ends in `except (..., Exception): pass`, so a broken,
garbage-returning, or absent kernel falls back to Python SILENTLY. That is
what makes the first two unfalsifiable by lane hashes.
Instrumented under CORE_BACKEND=rust: zero Rust calls in the whole
deductive_logic lane (pure ROBDD, no CGA), and exactly ONE
(versor_apply_with_closure_f64) in a full pipeline turn. CORE_BACKEND=rust is
today a one-call switch.
So §6B ("if parity holds, consider Rust default") rests on a measurement that
cannot fail, and §6C is the real blocker and is upstream of the backend. NOT
acted on — §6.4 says a parity/determinism finding is escalated, not fixed.
Recorded three follow-ups in dependency order: make the dispatch fail loudly,
add a parity test that fails when the Rust path is not TAKEN, only then route
the hot path.
The one thing fixed here is a plain defect blocking the measurement.
`core rust build` — the activation path print_rust_status() itself recommends —
raised `TypeError: _run() got an unexpected keyword argument 'env'` on every
invocation. core/cli.py::_run is injected into cli_rust.cmd_rust_build, which
passes env=rust_build_env() to carry PYO3_USE_ABI3_FORWARD_COMPATIBILITY, and
_run lacked the keyword the CommandRunner Protocol declares. One keyword, plus
tests/test_cli_runner_contract.py deriving the expected keywords FROM the
Protocol so the two cannot drift apart again. Verified end-to-end: `core rust
build` now builds and installs.
[Verification]: in-worktree on canonical CPython 3.12.13 with `uv sync
--locked`: smoke 575 (569 + 6), deductive 291 (unchanged). New tests fail
under mutation (revert the env keyword -> 3 red). Registered in `fast` AND
`smoke`. Installing core_rs does not activate it (_ALLOW_RUST requires
CORE_BACKEND), verified: extension present + no env var -> "rust backend:
inactive", so no default behaviour moves.
Audit-ledger R7, implementing docs/handoff/curriculum-license-loop-2026-07/
E1-R7-ASSERTION-SPEC.md. `ChatRuntime.chat` seals a TurnEvent before the
surface authority is known; `CognitiveTurnPipeline` back-stamps the resolved
surface and canonical trace_hash onto `turn_log[-1]` after `chat` returns. So
the in-memory log ended up correct and the DURABLE stream carried the
pre-override record — the thing that persists was the wrong one.
Mechanism, per the spec's M1-M3:
- M1 — stage an INDEX into `turn_log`, never the TurnEvent. The flush re-reads
the log, so every back-stamp is picked up by construction and the staged
record cannot go stale. Capturing the event object would be the original
defect with extra steps.
- M2 — `attach_telemetry_sink` does NOT flush a staged turn event, the
opposite of what it correctly does for `_pending_reboot_payload`. The reboot
payload is final when buffered; a staged turn event is mid-flight. Flushing
on attach would silently restore the defect.
- M3 — deferral is opt-in. The pipeline wraps the runtime rather than the
reverse, so the runtime cannot detect whether a pipeline will run. A runtime
used directly (eval and demo paths) emits inline, byte-identically and at
the same moment as before.
The `finally` at the serve boundary is load-bearing (I5): a pipeline that
raises after `chat` returns must still flush, or an error path silently
swallows a telemetry record — worse than the staleness being fixed.
TWO CORRECTIONS TO MY OWN SPEC, reported rather than quietly absorbed:
1. I2 bullet 3 and I3 assert on an emitted `trace_hash`. There is no such
field — `chat/telemetry.py` never serializes `TurnEvent.trace_hash`, so the
sink never carried a trace_hash, stale or otherwise. R7 repairs the SURFACE
only. Pinned by `test_trace_hash_is_not_in_the_wire_format_at_all` so the
claim cannot be re-asserted; the replay-not-recomputation ruling is kept on
the object that does carry the hash.
2. The surface divergence is unreachable under the DEFAULT config:
`finalize_turn_surface` is a no-op on all 36 turns probed, because the
runtime's own surface already wins the resolver. It fires under
`realizer_grounded_authority` — 24 divergences over 84 turns. A test on the
default config would have passed while proving nothing, exactly as the spec
warned, so the fixture pins that flag and asserts the pre-fix divergence
exists before asserting it is gone.
[Verification]: in-worktree on canonical CPython 3.12.13 with `uv sync
--locked`: smoke 591 (569 + 22), deductive 291 (unchanged). All seven existing
sink test files pass UNCHANGED (80 tests). warmed_session_consistency
telemetry_consistency_rate = 1.0. Mutation-checked all three mechanisms:
staging the event instead of the index -> 3 I2 tests red; flushing on attach ->
the M2 test red; dropping the `finally` -> the I5 test red. Registered in
`smoke` and `cognition`.
Builds the producer `chat/curriculum_serve_license.py` already named as the
only writer of the ledger it reads — `evals.curriculum_serve.practice.runner
.seal_ledger` — which did not exist. Until now, authoring curriculum could
not earn a license at any volume.
A band's case space is ENUMERATED, not authored: every exam question that
routes to that subject (resolve_domain) whose relation is in that family, one
committed case per distinct query atom. So `committed == distinct` is not a
property the generator maintains, it is the same fact twice — the structural
form of ADR-0264 R9, and why this producer cannot develop the deduction
producer's exposure (CASES_PER_BAND=720 filled from spaces as small as 28).
CASES_PER_BAND=660 follows `evals/determination_estimation` per
DIVISION-OF-WORK §4: a ceiling on committed volume, not a quota.
11 bands, wrong=0, inflation 1.0 everywhere.
THE LEDGER IS DELIBERATELY NOT COMMITTED. The plan's Phase-1 exit criterion
asked for "a real (still-unearned) ledger"; that state is unreachable.
Reliability is commitment precision and a correct UNKNOWN is a commitment, so
conservative_floor(660,660)=0.990046 clears theta_SERVE on non-commitments
alone. Sealing today licenses FOUR bands on evidence that is 99.0%-99.98%
correct non-commitment — which ADR-0262 §5.1 rules unacceptable and which
ClassTally structurally cannot see (no verdict axis). Writing the artifact is
therefore a ratification and belongs to Phase D's explicit human-run verb.
The open outcome-mix ruling is now blocking, not academic.
Two corrections to my own earlier records, both measured:
- ADR-0264 §4.2 sized bands from per-TERM exclusivity; the router's predicate
is per-PAIR, which is looser. Every ceiling was understated, and
systems_software_causal is 720 not 630 — flipping it from "cannot reach
657" to "can". 4 of 11 bands can reach the floor, not 3. Now pinned as
measured values in BAND_ATOM_SPACE.
- `then` and `therefore` are taught philosophy_theology lemmas AND control
words of the argument reader (`therefore` is the conclusion marker). 164
routable atoms refuse compiled_premises_unreadable — coverage misses, never
wrongs — in the band Phase F retargets to. The vocabulary boundary is not
screened against the reader's grammar; a pack teaching and/or/not/if would
open a much larger hole the same way. Recorded, not fixed (§6.5), pinned as
a two-lemma bound.
Registers curriculum_serve in AUDIT_SOURCES, retiring the declared `None`
that was Phase C's forcing function, and adds the producer to `deductive`.
[Verification]: in-worktree on canonical CPython 3.12.13 with `uv sync
--locked`: smoke 571 (569 + 1 test + 1 parametrization), deductive 310
(291 + 19). Mutation-checked: injecting the deduction padding pattern into
band_cases turns 5 tests red including the R9 audit and the seal guard.
curriculum_serve lane unchanged at n=32 correct=32 wrong=0 anti_recall=5;
all 11 lane SHA pins match; no ledger written, so no serving change.
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).
Phase B of the curriculum-license-loop arc. Stacked on the ADR-0264 branch.
The invariant: conservative_floor is a one-sided Wilson lower bound and Wilson
assumes INDEPENDENT trials. CORE's pipeline is deterministic, so replaying an
identical case is not a second trial -- it is the same trial with a guaranteed
outcome. A ledger's `committed` count is an upper bound on its evidence; the
defensible figure is its distinct-decision count.
Phase B was scoped as a precaution for a curriculum producer that does not
exist yet. Running the instrument against the producers that DO exist found it
already violated:
21 of the 25 ratified deduction_serve bands do not clear theta_SERVE=0.99 on
distinct evidence. Three inflate 28 distinct cases into 720 committed
(honest floor 0.8084 vs claimed 0.9909). deduction_serving_enabled was
ratified ON 2026-07-24 and is live.
The estimation producer (ADR-0175) is clean -- 660 committed, 660 distinct,
zero repeats, evidently chosen just above the 657 a perfect record needs. So
this is a regression from a standard already established in the repo, not an
architectural gap. `claimed` is identical for all 25 deduction bands because
every band commits 720 with a perfect record: the gate sees 25
indistinguishable passes while honest floors span 0.8084..0.9909.
NOT REPAIRED. The ledger is SHA-sealed, ratified, and gating a live flag, so
re-sealing it is Shay's ratification, not a test's. wrong=0 still holds -- no
band answered anything incorrectly. What is not established is reliability at
the volume claimed. Measured, pinned in both directions, written down.
Added:
- core/reliability_gate/evidence.py -- pure measurement, imported by no serving
path. volume_for_theta() DERIVES 657 from conservative_floor rather than
restating it, so a WILSON_Z change cannot leave a stale literal behind.
- tests/test_volume_honesty.py -- 13 tests. AUDIT_SOURCES is checked against
CAPABILITY_LEDGERS, so a new licensed capability cannot ship unaudited; the
curriculum entry is a declared None that fails the moment its ledger exists.
That is Phase C's forcing function against repeating the pattern.
- docs/research/distinct-evidence-audit-2026-07-25.md -- full audit + the open
outcome-mix ruling for Shay.
- ADR-0264 R9 amended with the measured exposure.
Decision key is case TEXT deliberately: a tighter key (normalized atom) would
collapse spelling variants and report MORE inflation, so text-identity
under-reports and every number is a floor on the real gap.
Outcome mix is deliberately NOT pinned. ClassTally has no verdict axis, the
deduction producer already balances 240/240/240 by construction, and imposing
a per-verdict-class floor would retroactively fail all 25 bands on a criterion
no ADR has ratified (smallest per-band class count is 120). Recorded for a
ruling with numbers instead.
[Verification]: uv sync --locked on canonical CPython 3.12.13; in-worktree
smoke 569 passed (556 baseline + 13), deductive 285 passed. Registered in the
`smoke` curated suite -- not left to `full`, which gates nothing. Mutation-
checked: doubling CASES_PER_BAND -> 2 failed; reporting committed as distinct
-> 4 failed; gating on `claimed` instead of `honest` -> 3 failed; tree restores
to 13 passed.
Phase A of the curriculum-license-loop arc. Design only; no production code,
no flag, no default changed.
Rules R1-R9: polarity is a row-level field (absent => affirmative), negatives
compile to the sentential-not form and MUST reuse the affirmative connective
(atom identity), contradiction is rejected at ratification, premise
compilation becomes query-scoped, an empty scope is UNKNOWN, premise_count
keeps reporting family size, the oracle learns polarity independently, and a
band's honest ceiling must be reported before anyone authors for it.
Three findings, each measured in-tree and each reversing something:
1. `polarity` is read by nothing. A row authored to refute a question today
serves a confident wrong "Yes" -- and the independent oracle ignores the
field for the same reason, so gold agrees and wrong=0 stays green. This is
the silent-failure class Phase A existed to prevent, now demonstrated.
2. The 16-premise honesty cap holds a family to <=16 chains; at 17 the band
declines everything, including the taught positive that works today. So
ADR-0262 §5.1's own remedy (author ~219 relations) destroys the capability
at row 17, tripping the fix §6 deferred as a future contingency. Jointly:
a band has <=16 entailed cases against a 657-committed threshold, so no
curriculum band can earn SERVE until scoping lands. The blocker is
engineering, not content -- inverting the conclusion two arcs closed on.
3. Honest volume is bounded by taught vocabulary, not corpus size. 8 of 11
bands cannot reach 657 at all, including the plan's chosen first target
physics·modal (ceiling 480, counting every possible question). Retargets
Phase F to philosophy_theology·modal (ceiling 44,104, same 8-chain start).
R5 is the only rule that could change an existing answer, so it is the only
one carrying evidence: 8,520 routable questions, 0 verdict mismatches for both
candidate scopes. Verdict-identity holds for any scope that is a superset of
the query-atom rows, since each premise mints one independent atom. That is
stronger than ADR-0262 §6's soundness argument, and it is why this narrowing
is not the ADR-0261 §5.1 premise-dropping failure.
ADR-0262 §5.1/§5.2/§6 carry forward-pointers; original text preserved.
[Verification]: uv sync --locked on canonical CPython 3.12.13; in-worktree
`core test --suite smoke -q` 556 passed (555 baseline + 1: the derived
ratify-on-merge pin picked up ADR-0264 and discharged it), `--suite
deductive -q` 285 passed. Four probes reproducible from
docs/research/curriculum-premise-scope-2026-07-25.md; the corpus-mutating one
restores the file and asserts byte-identity.
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.
Nine ADRs (0254, 0256-0263) were merged into main and left stamped Proposed.
Two carried an explicit ratify-on-merge predicate their own merge had already
discharged, and ADR-0256 governs deduction_serving_enabled, which was ratified
True on 2026-07-24 and is serving live traffic. So the governance record
asserted "not yet decided" about a decision already in force.
That is the asymmetry the assessment arc (#113) found one file over in
workbench/api.py: the honest path degrades, the stale record lies. An unwritten
ADR is a visible gap; a Proposed one that is actually in force is a false
statement.
Each stamp records the ACTUAL ratifying act -- "Accepted, ratified by Joshua
Shay via <merge> (<sha>, <date>)" -- derived from the commit that added the file
and verified an ancestor of main, not assumed. Merge authority is Shay's alone
(AGENTS.md: no merge automation), so the merge IS the ratifying act.
No ADR content changed. No flag changed. ADR-0262's stamp says so explicitly:
accepting it does NOT enable curriculum_serving_enabled, which stays False
pending ratified volume -- eleven bands re-measured today, still 24x-73x short.
tests/test_adr_status_governance.py pins two independent invariants in the
smoke (pre-push) suite:
1. A default-ON flag is not governed by a Proposed ADR. The flag -> ADR mapping
is DERIVED by walking core/config.py for `<name>: bool = True` and reading
ADR refs from the preceding comment block -- not a hand-written table, which
would be the same second-copy-of-a-closed-set defect ADR-0256's arc fixed.
2. A ratify-on-merge predicate cannot coexist with Proposed. Self-discharging:
the file being on main IS the merge having happened.
Plus a vacuity guard, because a derivation that parses zero flags would make
every other assertion pass on an empty set.
Registered two orphans found in passing: test_adr_index.py (5) and
test_ratification_ceremony.py (14) landed in #113 in NO curated suite, so 19
tests -- including the one mechanism that can move curriculum volume -- ran
only under `full`, which gates nothing. Fifth instance of this shape.
Deliberately NOT fixed, recorded in the research doc: the 312-file corpus has
27 unparseable status lines and draft/ratified/active variants. A closed-vocab
assertion would fail on ~35 pre-existing files and get muted, and a muted gate
reads as coverage.
[Verification]: smoke 555 passed in 137.73s (236 baseline + 314 + 5, +1.2s);
governance pin 314 passed in 1.18s standalone and MUTATION-CHECKED -- reverting
ADR-0256 to Proposed fails both invariants independently (2 failed/312 passed);
orphans 19 passed; ruff clean. Canonical Python 3.12.13, uv sync --locked.
The full 99-register run is green: 801 passed, 0 failed, up from 99 failures on
clean main. bf17f42's "DO NOT MERGE until green" is hereby satisfied; the fix in
bf17f42 + bec76d4 is verified.
Records the whole thing, including what was NOT broken: the load-bearing
ADR-0072 claim (test_register_matrix_trace_hash_invariant) passed throughout, on
main and after. trace_hash folds hash_surface, so a real truth-path leak would
have moved it, and it never did. The invariant was intact the entire time — it
just was not observable, because hash_surface was pipeline-local, which is why
the test drifted onto `surface` when Phase 0 changed what that field means.
Also records the wrong turn: the first patch aimed at
evals/cognition/runner.py::CaseResult, while the test consumes
evals/metrics.py::CaseResult via run_cognition_eval. Thirteen files here define
a class called CaseResult. Follow the import, not the name.
[Verification]: register matrix 801 passed / 0 failed (17m50s), including the
trace_hash invariant across all 99 registers; capability index + eval harness 23
passed. evals/metrics.py::CaseResult gained a DEFAULTED field and its only other
consumers (calibration/tune.py, calibration/replay.py) never construct it.
NON-CANONICAL: Python 3.12.11.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FduW6Krm3PPQv3P5iwBYtx
Reverts the bidirectional half of the smoke parity pin added earlier today,
and records why at the assertion site so it is not "completed" again.
I read the suite list's comment ("so the local-first pre-push gate equals the
CI gate") as promising equality, made the assertion symmetric, and reported
tests/test_pack_draft_serve_boundary.py as drift because it sits in the local
gate and not in .github/workflows/smoke.yml.
That was wrong, and AGENTS.md says so in a line I had already read: GitHub
Actions are billing-locked and produce dead signals, never chase them. The
Forgejo host (e2-micro) cannot run workflows either. CI here is run MANUALLY
in-worktree — usually faster anyway on UMA hardware with real RAM — which is
what scripts/ci/local-ci.sh now front-ends. smoke.yml is secondary
observability, not a gate.
So the local suite is the SOURCE and is free to be broader. Asserting the
reverse converts a file nobody executes into a maintenance obligation, and one
agents cannot discharge at that — pushing workflow changes needs an OAuth scope
the push credential lacks. The three "owed" lines were never owed.
The surviving direction (CI subset-of local) still protects something real: if
smoke.yml ever names a path the local gate lacks, the local gate is narrower
than a published claim about it.
Arc-close brief updated to match: the "three files owed to smoke.yml" open item
is replaced by a recorded non-finding, so the next reader does not re-derive it.
Its shipped-work table now lists what actually landed in its place — the local
CI runner, the lane-roster fix, and the proposal-sink test-isolation fix.
[Verification]: 21 passed across test_cli_test_suites, test_lane_sha_verifier,
test_adr_index; ruff clean on the changed test.
NON-CANONICAL: Python 3.12.11, not the pinned 3.12.13 (unavailable for
linux-x86_64). Hash-pinned tests reproduce committed values regardless.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FduW6Krm3PPQv3P5iwBYtx
Squashes the arc's work into one commit; the workflow-file edit it originally
carried is excluded (see the end of this message).
## Lane 1 — Workbench recorded a proved answer as ungrounded
With deduction_serving_enabled ratified ON (ADR-0256), workbench/api.py's live
chat route builds a bare ChatRuntime(), so the deduction composer decides
Workbench turns and stamps grounding_source="deduction" — but
_coerce_grounding_source carried a hand-copied whitelist of the six pre-arc
labels and silently rewrote anything else to "none". The runtime comment
reasoned this was inert because "REPL turns do not flow through Workbench's
CognitivePipelineRecord path". True, and irrelevant: the traffic flows the
other way. Stale since 2026-07-24.
Scope is one field. workbench/api.py:818 prefers TurnEvent.epistemic_state,
which read epistemic_state_needed — honest. So the UNregistered path degraded
honestly while the hand-copied whitelist asserted a falsehood; a second copy of
a closed enum was worse than no copy. Hence registration AND derivation:
GROUNDING_SOURCES exposes the Literal's members, and the coercion reads it.
workbench-ui badges/tokens/snapshot follow; enumCoverage.test.ts forces atomicity.
## Lane 2 — the ratification ceremony
The discovery loop was instrumented but not closed. teaching/ratification.py
turns a reviewed decision into a chain record, a corpus commit, and a receipt.
Its design turns on one observation: _ratified_rows DROPS unadmissible rows
silently — correct when serving, a trap when ratifying, because the file grows,
the commit lands, and the band count does not move. So the ceremony refuses to
call an append a ratification until it has re-read the curriculum through the
real loader and seen the chain arrive; a non-admitted append is rolled back.
Validation is a pre-flight courtesy, admission is the proof.
Arena queue entry and ledger reseal are deliberately NOT performed (bridge rule
1); the receipt names them. Front door: `core proposal-queue ratify`, a sibling
of `review` rather than a flag on it.
## Lane 3 — structural closures
- ADR-0263 gains rule 5: absence policy is DECLARED in CAPABILITY_LEDGERS, not
passed at the call site. An AST-matched test fails if a serving path passes
missing_ok again.
- Deductive suite added WHOLE to the pre-push gate: 285 tests in 29s against
smoke's 216 in 62s, so no coverage trade was needed.
- Smoke/CI parity assertion made bidirectional. It was one-directional, and had
drifted.
- test_prior_surface_deduction_binding.py pins correction binding on the
deduction path. The review's diagnosis did NOT reproduce — hash_surface moves
in lockstep — so it pins what is there. Mutation-checked.
- Domain-keyed ADR index over 312 flat-numbered files, explicitly partial.
- Arc-close brief template, plus this arc's own brief filled in against it.
## Lanes 4 and 5 — two premises falsified by measurement, one of them mine
Math 4.2: baseline reproduced (correct=5 wrong=0 refused=495); all four named
cases traced to one seam with each gap isolated by one-variable probes. Then the
number that changes the recommendation: the gap blocking case 0000 affects 1
case in 500, the 'than' gap blocking 0001 affects 2. ADR-0251's prohibition on
per-case growth now rests on a count. No reader change made.
CGA: versor_condition is 0.22% of a turn, not the "~10x proof latency" I claimed
— that multiplied an isolated microbenchmark by a call count and compared it to
a single verdict's latency. The real cost is geometric_product at 33,986
calls/turn (~73%) via cga_inner in search paths. The obvious closed form is NOT
bit-exact (954/4000 in f32); backend.vault_recall's serial fold IS (3000/3000,
worst-rel 0) and is the correct target. cargo test could not run —
static.crates.io is denied by the sandbox network policy — so the Rust parity
question stays open and the typestate lane is carried forward, not shipped
uncompiled.
## Not landed: three lines owed to .github/workflows/smoke.yml
The CI smoke gate is narrower than the local one —
test_pack_draft_serve_boundary.py (ADR-0253 INV-33) has been local-only, unseen
because the parity pin checked one direction. The edit was authored and rejected
at push for lacking the `workflow` OAuth scope, so it is recorded as a named,
dated PENDING_IN_CI exception rather than dropped: the assertion still fires on
any new divergence, and a second guard fires once the three land.
[Verification]: pre-push gates all green — smoke 236 passed, warmed_session 10
passed, deductive 285 passed. Ratification 14, ADR index 5, CLI suites 10.
Grounding/epistemic sweep 741 passed 1 skipped. workbench-ui 598 passed across
73 files, tsc -b clean. capability index 11 passed, digest unchanged. Math
holdout correct=5 wrong=0 refused=495. Committed chain corpora byte-unchanged
after the tests that write to them.
Environment caveat: the repo pins requires-python ==3.12.13, which uv cannot
fetch for linux-x86_64, so `uv sync --locked` fails. All Python runs used a
scratch venv on 3.12.11 with declared deps — not the locked universe, not the
full ~12k suite. The pin was left untouched. Re-run on a 3.12.13 host before
treating this as merge evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FduW6Krm3PPQv3P5iwBYtx