Skip to content

SEED-STRING-DECODE-CENSUS: the authority/realization coupling is spelling-keyed (census only) - #10180

Merged
gunbai-bot[bot] merged 8 commits into
mainfrom
session/quick-newt-318
Sep 3, 2026
Merged

gunbai-bot[bot] merged 8 commits into
mainfrom
session/quick-newt-318

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Census of the class #9975 found by accident: the seed reads .dag values through the interpreter and addresses them by spelling — type name, variant name, field name, entry-function name, all string literals in Rust. Seed and authority share no Rust type, so a rename has no compile-time link to the decoder that depends on it.

Adds docs/plans/seed-string-decode-census.md. No repair, no ledger enrolment — per brief.

Mechanism (the closeable part). Five primitives, all bottoming out in four InterpContext methods (sym, sym_eq, field, resolve): P1 sym_eq (87 sites), P2 ctx.field (103), P3 resolve().as_str() matched against string-literal arms (61), P4 run_in_context with a literal entry (30 of 142), P5 file-local wrappers over P1–P3 (36). P3 and P5 are invisible to a grep written from the #9975 sym_eq specimen — 97 further sites in 9 files. Mint side: 262 more sites in the opposite direction.

I also looked for decoders using some other mechanism and say so in the doc: positional (2 sites, both in a #[cfg(test)] block, both still assert the name), rendered-text (0 live), shape-only (a different class).

Subject: 25 unambiguously-attributed .dag authority modules. The join is on the BARE name and 8 of 79 names have several declarers (Refused ×7), so those attributions are an upper bound and are marked as such.

Second already-fired instance, found by the census. cli_run.rs calls run_in_context(&ctx, "roadmap_acceptance_event_history", true); no declaration of that name exists in the corpus. gunbc.roadmap_authority renamed it to roadmap_acceptance_event_history_load and changed the result shape — the pre-rename declaration is still visible at git show 9ce6526c528:dag/gunbc/roadmap_authority.dag. The only test over the route is #[ignore]d and feeds the decoder the authority text from that same pinned SHA, so it can never observe the break.

Rung 1, and the reason is better than expected: every decode site read fails closed with a typed Err. The class is not silent-wrong-answer — it is silent at compile time and loud only where executed, which is exactly how instance 2 survived.

Ceiling 3 (possibly 4), trigger stated as the capability, not an artifact: emitted typed decoders (Value → mirror type) and typed constructors for every .dag type the seed decodes or mints, sufficient that no hand-written spelling of a .dag type/variant/field name survives in src/v1/stage0/src. A grep-and-join lens is explicitly named as not the climb — validation standing where construction is available.

Residue stated in the doc: per-site execution coverage, the .dag file-path axis (420 literals), and the deliberate exclusion of generated mirrors.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ

gunbc-ci-auto-heal and others added 4 commits September 3, 2026 02:58
… a second already-fired instance

The seed reads .dag values through the interpreter and addresses them by SPELLING -- type
name, variant name, field name, entry-function name, all string literals in Rust. Seed and
authority share no Rust type, so a rename has no compile-time link to the decoder that
depends on it. #9975 found this by accident. This is the population.

Five decode primitives, all bottoming out in four InterpContext methods; two of them (P3
resolve-and-match-arm, P5 file-local wrappers) are invisible to a grep written from the
#9975 sym_eq specimen and carry 97 further sites in 9 files. 25 unambiguously-attributed
.dag authorities are decoded; the mint side carries 262 more sites in the other direction.

Second already-fired instance, found by the census rather than by accident: cli_run.rs calls
run_in_context "roadmap_acceptance_event_history", which no declaration in the corpus
carries -- gunbc.roadmap_authority renamed it to _load and changed the result shape. The
only test over the route is #[ignore]d AND pins the authority text to the pre-rename SHA, so
it can never observe the break.

Rung found at 1: every decode site read fails closed with a typed Err, so the class is not
silent-wrong-answer but silent-at-COMPILE-time. Ceiling 3, trigger stated as the capability:
emitted typed decoders and constructors sufficient to leave no hand-written .dag spelling in
the seed. Census only -- no repair, no ledger enrolment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ
…the join key is (name, revision)

I reported cli_run.rs's run_in_context "roadmap_acceptance_event_history" as a live break
because no declaration of that name exists AT HEAD. That was a defect in my census method,
not in the seed.

The decoder is the carrier-introduction bootstrap: it fires only when the JSONL carrier is
ABSENT at the merge-base, and it decodes git.Core.Show of the merge-base revision's
roadmap_authority.dag -- not the worktree's. The two facts were bound in one commit: at
bfaaf3e^ (#7791) the function exists and the carrier is absent; at bfaaf3e the
carrier exists and the function is gone. So the arm's own guard implies the old spelling is
present in the text it is about to read. Correct for exactly the revisions where it can
fire, unreachable everywhere else.

The probe question, answered rather than assumed: the pin to 9ce6526 is LEGITIMATE and
stays. That revision is an ancestor of bfaaf3e^, carries the function, and has no
carrier -- a faithful representative of the revision class the decoder serves. A live probe
that reddens on a rename would assert a property the code never claimed. The #[ignore] is
separately declared (live-corpus) and hid nothing.

The class this actually names is a census-method class: a spelling-keyed decode whose
subject is a REVISION-ADDRESSED text must be joined against the revision it reads, not
against HEAD. It narrows to P4; P1/P2/P3/P5 decode values from the current resolved graph,
so the HEAD join is right for them. Recorded because a reader copying the method would
repeat the error.

Also states what the rung refinement costs: priced by deferred detection, not corrupted
output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ
…ore primitives found, and the shape axis named

ATTRIBUTION. All 42 literal-entry run_in_context sites -- the first pass said 30; a stricter
re-extraction finds 42 -- attributed by reading each caller's context construction.
17 HEAD/live-worktree (ctx from default_source_roots/workspace_root), 24 in-file synthetic
source (the module text and the entry name are authored in the same expression, so a rename
edits both and they are not exposure at all), and exactly 1 revision-addressed: the
carrier-introduction bootstrap already adjudicated. The residue is closed; all 17 HEAD-subject
names resolve today.

TWO MORE PRIMITIVES, found by this pass rather than the first sweep, taking the set 5 -> 7.
P7: entry/function names passed as subprocess ARGV (--entry/--function) -- 35 sites in 3
files, larger than P4 and completely invisible to a run_in_context grep. All HEAD-subject,
all 11 names resolve. P6: str::replace rewriting a live-HEAD .dag file's own text, 2
producers / 6 call sites, and the ONLY primitive in the set that can fail OPEN -- replace
returns the input unchanged on a miss. Its two arms differ: a missed module-path rewrite hits
the module-path collision wall (loud); a missed /tmp-path rewrite makes the witness write to
the shared path instead of its scratch dir (silent). Scored per arm, not per primitive.

THE SHAPE AXIS, named as residue on the design authority's ruling. The class is any change to
a .dag schema element consumed reflectively by host code, not renames alone -- including
changing optionality, cardinality or shape while preserving every identifier. All seven
primitives are NAME-keyed, so that axis passes every one of them and still breaks the decode:
the population measured here is the NAME-KEYED SUBSET. Not hypothetical -- the retracted
instance was half a shape change, since the .dag side also moved List<T> to a Load coproduct.
The ceiling is unaffected: a generated typed decoder makes a shape change a type error exactly
as it makes a rename one. The ceiling is right; only the census is narrow.

Also adopts the four routes by which a compiler-silent class becomes operationally silent:
the path does not run, a fixture bypasses it, a default absorbs the mismatch, or a stale
artifact answers instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ
…s on an absent pattern

str::replace returns its input UNCHANGED on a miss, so an ordinary edit to a .dag literal
made interp_recorded_fixture_witness's scratch copy silently unrewritten -- DESIGN section 5's
failure arm that widens instead of refusing. Two arms, only one loud: a missed module-path
rewrite produced a same-name duplicate the module-path collision wall refuses, while a missed
/tmp rewrite made the witness write to the SHARED path instead of its per-run scratch
directory, unreported, landing as cross-run interference in another session's witness.

Being caught by a neighbouring wall is a property of that wall, not of this rewrite, so all
five substitutions across both producers now route through `substituted`, which refuses when
the pattern is absent and names the PATTERN and the SOURCE FILE -- whoever trips it will be
editing the .dag with no reason to know a Rust harness depends on its literal text.

Evidence, 3 passed remotely: a discriminating RED (pattern edited out -> refuses, asserting
the refusal names both), a positive control (pattern present -> substitutes), and a
COUNTERFACTUAL running bare str::replace on the identical input and asserting it answers with
the source unchanged and no error. The counterfactual is load-bearing: `substituted` did not
exist before, so the RED alone would show only that a function which refuses, refuses.
Placement stated honestly in the doc -- these run under cargo test --workspace, not the
required lane, which is --lib only.

The census also records that the primitive is not repository-specific: the script adding that
counterfactual used a Python str.replace whose pattern did not match, silently changed
nothing, exited 0, and produced a green remote run of the two tests already present. `2
passed` rather than 3 was the only tell.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ
@gunbai-bot

gunbai-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

The approving review's premise is now false — flagging rather than letting it stand as coverage.

Review 59080 approved 60aefd9d3ac on the basis that this PR is "census-only … No code, no .dag, no seed changes; explicitly repairs/enrols nothing." That was accurate at the time. aff564ca8a7 adds seed code: the P6 repair in src/v1/stage0/src/bin/interp_recorded_fixture_witness.rs, authorized separately after the fail-open was verified on main.

So the approval covers a diff that no longer exists. It will still count as a current approval in the dashboard summary — an approval on a superseded head reads as 1/1 with no staleness signal — and I would rather say so than have it read as review coverage for code no reviewer has seen. The census half is unchanged in substance since that read.

What the new commit does. str::replace returns its input unchanged on a miss, so an ordinary edit to a .dag literal made the harness's scratch copy silently unrewritten. Two arms, only one loud: a missed module-path rewrite produced a same-name duplicate that the module-path collision wall refuses; a missed /tmp rewrite made the witness write to the shared path instead of its per-run scratch directory, unreported, landing as cross-run interference in another session's witness. Being caught by a neighbouring wall is a property of that wall, not of this rewrite, so all five substitutions across both producers now refuse on an absent pattern, naming the pattern and the source file.

Evidence, 3 passed remotely: discriminating RED, positive control, and a counterfactual that runs bare str::replace on the identical input and asserts it answers with the source unchanged and no error. That third one is load-bearing — substituted did not exist before the repair, so the RED alone would show only that a function which refuses, refuses.

— sent from quick-newt-318

gunbc-ci-auto-heal and others added 3 commits September 3, 2026 03:30
… the hour

Promoted from a parenthetical to its own section, because it is the only observation in the
document that shows the class ARISING rather than being inventoried, and it happened to the
person writing the inventory.

Adding the counterfactual test to the P6 repair -- the repair whose entire subject is
str::replace failing open on a missed pattern -- the editing script used a Python str.replace
whose pattern did not match, because \n and \" escaping differed between script and file.
Every signal agreed with success: the call returned a string (the file, unchanged), cargo fmt
reported "modified 1 file" from an unrelated reformat, the command exited 0, and the remote
run came back GREEN because it ran the two tests that already existed. `2 passed` where 3 was
expected was the entire discriminating signal, caught by reading the run's test NAMES rather
than its exit code.

Three consequences, none about Python. The primitive is not .dag- or seed-specific: it
reproduced in a different language against a different file one hour after the paragraph
explaining why it is dangerous was written, which is the strongest available evidence that the
population estimated here is a FLOOR rather than a ceiling -- the class needs only a
substitution whose failure arm widens, not the seed/authority seam. Assert the pattern is
PRESENT before replacing; the edits that worked did, the one that vanished did not, and that
is the whole difference. And a green run is not evidence a test EXISTS -- a run reports the
tests that are there, never the ones you meant to add, so a vanished edit and a passing suite
are indistinguishable by colour, exit code, or any single-number summary. Same shape as a
vacuous `0 passed; 0 failed; N filtered out`; both are caught by arithmetic, not suspicion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ
…seam of a non-seam-specific primitive

The census began as a census of a seed defect. The P6 incident shows the class is not
seam-specific -- it needs only a substitution whose failure arm widens, and reproduced in a
different language against a different file within the hour, on the author repairing it. So
what is measured is ONE SEAM of a primitive that is not seam-specific, and the population is
a FLOOR rather than a ceiling. Stated up front rather than left as an inference from the
incident section.

Separately, docs/plans/review-instrument-observations.md records two findings about the
review and merge-readiness tooling, kept out of the census proper because they are facts
about the instrument rather than about the seed.

(1) stale_provider_count does not fire even where both operands are local. One payload
carried the approving review's sha, the dashboard's own head_sha, and gh's headRefOid as
THREE DIFFERENT VALUES, with stale_provider_count 0 and meets_approval_rule true. The lag
reading -- stale=0 means "not yet noticed", not "judged current" -- is true and worth knowing,
but incomplete: the approval sha differs from the dashboard's OWN head_sha in the same object
and staleness still reads 0. So comparing dashboard head_sha to gh headRefOid is necessary but
NOT sufficient; the reader must compare reviews[].sha to headRefOid themselves. A softer form
is also recorded: an approval can be superseded in PREMISE rather than in sha, as this PR's
was ("census-only, no code" over a head that later added code).

(2) A refused review burns its sha slot invisibly. Review 59066 failed with a worktree
freshness refusal -- correct behaviour, but the slot is consumed and never retried, leaving no
trace in approvals, request_changes or stale_provider_count. The pairing is the finding: one
half of the system refuses to review unless its checkout matches the PR head exactly, while
the other half reports staleness as 0 across a three-sha spread.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ
…w from five primitives to seven (review 59095)

Both findings are real and both were introduced by APPENDING P6/P7 without revisiting the
sentence and column that described the set of five.

(1) "All of them ultimately bottom out in four InterpContext methods" was true of P1-P5 and
false the moment P6 and P7 were added: P6 is a str::replace over file text and P7 is a
subprocess argument vector, and neither touches InterpContext. Corrected -- and the correction
carries the reason rather than just the fact, because it is the census's own thesis: every
earlier sweep was keyed on the interpreter surface, so a name crossing into .dag by any other
route was outside the search BY CONSTRUCTION. That is exactly why P6 and P7 were missed. The
primitives are grouped by the ROUTE a name takes, not by a shared implementation.

(2) The P6 row read "2 producers, 6 call sites" in a column whose other rows count
substitution/decode sites, next to prose saying "all five substitutions". Those are two
different quantities -- five substitutions inside two producer functions, which are reached
from six call sites -- but the column made them read as a contradiction. The row now states
the substitution count in the column's own unit (5, as 3 + 2) and names the other two
quantities inline; the prose and the residue entry agree with it.

Verified against the code: 8 `substituted(` occurrences = 1 definition + 3 in
unique_fs_witness_entry + 2 in closure_scale_witness_entry + 2 in the tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ
@gunbai-bot

gunbai-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Both findings in review 59095 are correct and both are fixed in dee613521e4. They share a cause worth naming: each was introduced by appending P6 and P7 to a document written when the set was five, without revisiting the sentence and the column that described the five.

1. The InterpContext claim. "All of them ultimately bottom out in four InterpContext methods" was true of P1–P5 and false the moment P6 and P7 were added — P6 is a str::replace over file text, P7 is a subprocess argument vector, and neither touches InterpContext. Corrected, and the correction now carries the reason rather than just the fact, because it is the census's own thesis: every earlier sweep was keyed on the interpreter surface, so a name crossing into .dag by any other route was outside the search by construction — which is precisely why P6 and P7 were missed. The primitives are grouped by the route a name takes, not by a shared implementation.

2. The P6 count. The row read "2 producers, 6 call sites" in a column whose other rows count substitution/decode sites, beside prose saying "all five substitutions". Those are two different quantities — five substitutions inside two producer functions, reached from six call sites — but putting the call-site number in that column made them read as a contradiction. The row now states the substitution count in the column's own unit (5, as 3 + 2) and names the other two quantities inline; the prose and the residue entry agree with it.

Verified against the code rather than against the prose: substituted( occurs 8 times = 1 definition + 3 in unique_fs_witness_entry + 2 in closure_scale_witness_entry + 2 in the tests.

Since the stated deliverable is an accurate census, a reviewer catching two internal contradictions in it is the review doing exactly what it should. Both are the kind of drift that arrives when a document grows by accretion, which is the same failure mode the census is about — a claim that was true of the old population surviving unchanged into the new one.

— sent from quick-newt-318

…ayload refutes it

I wrote that the staleness comparison "does not fire even when it has everything it needs",
on one payload. A later payload on the same PR reports stale_provider_count: 1, correctly
marking the provider whose latest review is behind head. So the field is not inert and that
sentence is wrong as written.

Both observations are now tabulated, and the hypothesis that fits them is labelled as a
hypothesis rather than a measurement: staleness is likely evaluated at review INGEST against
the head known then, and stored, while head_sha is read live at query time -- under which the
first observation is a stored verdict that went false underneath rather than a comparison
that failed to run. Distinguishing the two would need a payload sampled at a known ingest
boundary, which has not been done.

The operative rule is unchanged, which is why the correction does not disturb it: a
stored-and-gone-stale verdict and a non-firing comparison are indistinguishable to a reader,
and both report 0 on an approval that is not on the current head. Compute
reviews[].sha == headRefOid yourself.

Also records the same shape for request_changes_count: a codex REQUEST_CHANGES vanished from
the counter after the next push. Its findings WERE addressed in that push, but the counter
would read 0 either way, because a REQUEST_CHANGES is superseded by any push regardless of
whether anything was fixed. The commit and the reply are the evidence; the zero is not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ
@gunbai-bot

gunbai-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

One correction to review 59114, which approves — so this is not a dispute, only a premise I don't want a later reader to inherit.

It describes the docs as "appropriate ledger updates." They are not ledger updates, and the distinction is load-bearing here. This work item explicitly scoped out enrolment: "do not enrol a row in any ledger — report findings, I route enrolments." Nothing in this PR touches docs/design-failure-modes.md or docs/design-rung-drops.md, which are the ledgers DESIGN §4b names and whose authorities are gunbc.recurring_failure_mode and gunbc.rung_drop. Both files added here are analyses under docs/plans/, linked from the section that governs them, carrying no roster row and claiming no rung on anyone's behalf.

That matters because a reader who took "ledger updates" at face value would look for rows that don't exist, or would treat the census's rung findings as already enrolled and therefore already ranked — which is the opposite of true. The routing decision is still open and belongs to the lane that asked for the census.

Verified against the diff rather than the description: git show --stat for this branch touches docs/plans/seed-string-decode-census.md, docs/plans/review-instrument-observations.md, and src/v1/stage0/src/bin/interp_recorded_fixture_witness.rs only.

The rest of review 59114 is accurate, including the file and line spans for substituted and the three enrolled probes.

— sent from quick-newt-318

@gunbai-bot
gunbai-bot Bot merged commit fdfa34e into main Sep 3, 2026
7 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/quick-newt-318 branch September 3, 2026 05:39
@briansrls
briansrls restored the session/quick-newt-318 branch September 3, 2026 05:47
gunbai-bot Bot added a commit that referenced this pull request Sep 3, 2026
dag/gunbc/roadmap/roadmap_authority.dag's annotation opens "roadmap_acceptance_event_history
is the single authority for acceptance facts". No declaration of that name exists in the
corpus. #7791 replaced it with roadmap_acceptance_event_history_load, returning
RoadmapAcceptanceEventHistoryLoad instead of List<RoadmapAcceptanceEvent>, in the same commit
that introduced the JSONL carrier -- and the prose did not move with it.

The bare spelling is a symbol citation rather than conceptual shorthand, and the surrounding
block is what settles it: every other referent in the same annotation is named by its exact
symbol -- roadmap_acceptance_receipts, RoadmapAcceptanceReceiptsProjectionRefused,
gunbc.roadmap_acceptance_history_observation,
AcceptanceHistoryIntegrityRefusedPriorHistoryObservation, git.Core.Show. One name in that
register that resolves to nothing is stale, not informal.

DESIGN section 3's standing rule predicts exactly this rot: a citation nothing checks decays
silently, and no wall reads annotation prose, so nothing went red when the symbol left. The
class is the reason section 3 asks for the symbol rather than the position, applied to a name
that was correct when written.

Annotation-only, so by section 4c it cannot alter any semantic occurrence identity,
resolution result, semantic hash, or emitted bytes.

Found while censusing seed-side spelling-keyed decode (#10180); filed separately because a
stale citation is its own class and would have been lost bundled with a census correction.


Claude-Session: https://claude.ai/code/session_01FbsVmKQEBj7KAwfKEn6JCQ

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants