Skip to content

Record the class where a diagnostic's name is accurate about the situation and silent about the mechanism - #9414

Merged
briansrls merged 1 commit into
mainfrom
design/diagnostic-name-mechanism-silent
Aug 27, 2026
Merged

briansrls merged 1 commit into
mainfrom
design/diagnostic-name-mechanism-silent

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

What

One row in dag/gunbc/recurring_failure_mode.dag, registered in recurring_failure_mode_roster: a diagnostic's NAME is accurate about the situation and silent about the mechanism. Nothing in the name is wrong, which is why review reads past it, and a reader who treats the name as a cause builds a coherent story with no load-bearing contact with the code.

Ruled in by direction (warm-hawk-909), who verified receipts 2 and 3 at their sites rather than taking them on relay.

The three receipts, with provenance per receipt

A row about not trusting a name you have not traced to its producer must not itself rest on an untraced relay, so the provenance is inside the row.

1 — measured by me, and it leads because the reader was the author of the story. rustc labels reading expected Rc<Vector<i64>>, found String at 49 sites plus 2 reversed. I inferred a representation fork in the model type Symbol and published it. Measured: Symbol renders consistently as String, Connective.Atom carries identity: String, and the .dag is well-typed with the same declared type on both sides.

And the check failed the same way the reading did — this is the instructive part, not decoration. I grepped for the printed type name, got zero, and read zero as absence. The source spells Rc<Vec<i64>>, and lib.rs carries use im::{OrdSet as BTreeSet, Vector as Vec}, so rustc was printing the resolved underlying name. I read a name as a fact about the tree twice in one investigation — once in the diagnostic, once in refuting it.

What the 49 sites actually are is named and left unchased: Rc<Vec<i64>> is how List<Int> renders, so they read expected List<Int>, found String. The amendment closed the wrong explanation, not the defect.

2 — reported by quick-bat-372, independently verified by warm-hawk-909 at 04_infer.dag:3541. MethodNotFound does not say which predicate gates it: method_existence_decision gates on kernel_profile_lookup, so a fully resolved user product with no kernel profile answers MethodExistenceUndecided.

3 — same provenance, verified by exhausting the producers (04_patterns.dag:356, :362, 04_infer.dag:6234): FieldNotFound has no field-ACCESS producer at all. The clause about what field access raises instead is dropped — it was not verified, and this row must not carry an untraced name.

Why it earns a row

Two of the three would have shipped as permanently-green witness arms — an assertion that a wall fired, over a wall that cannot fire for that input. That is §4b's decoration-cited-as-coverage reached by a route no existing row names, and all three were caught by reading the producer, not by review.

Distinctness, since it borders two existing rows and is neither: identical diagnostic text is not identical cause is about two sites sharing a spelling; a suggestion names where the failure was detected, not caused is about location. This is about the named concept — one name, accurate and mechanism-silent.

The row carries its own rate caveat: three instances in one night is a suggestive rate and not a base rate; all three surfaced while several lanes were unusually deep in diagnostic populations.

Placement

Appended after remediation_mutated_view so the roster stays append-only and the carrier's own empty-diff projection oracle is preserved — its header notes that sorting the rows would destroy that oracle.

DESIGN.md is not regenerated by this PR, and that is not a defect this change introduced

No route in this repository regenerates it. Measured, not assumed:

  • generated_artifact_body_for_path is not CLI-callable — gunbc run refuses with returned GeneratedArtifactPathBody, not ProcessExit. It is reached only through the interpreter, by claim_executor, for drift checking.
  • Both consumers of GeneratedArtifactPathBody::Produced are read-only.
  • No --heal, --converge, --write-artifact or --regen-artifact on any bin under src/v1/stage0/src/bin.
  • The hooks do cargo fmt and repo-local git config only.
  • claim_executor's own comment beside the Produced arm names byte identity here as "exactly the drift check that has had no owner since" the floor cut — and DESIGN's unguarded list names heal, which was the writer.

So the artifact is stale with respect to this row until an actuator exists. Direction ruled this route explicitly over the alternatives: hand-editing DESIGN.md cannot be verified without the generator's output, which would make it an unverifiable hand-edit dressed as a regeneration — strictly worse than an honest divergence, and the thing #9402 was closed for. The actuator is dispatched as its own lane, because a write beside an existing read is load-bearing enough to deserve its own reasoning and review rather than being waved through as unblocking a doc row.

Verification

Module compiles as an entry: 0 blocking diagnostics.

🤖 Generated with Claude Code

…ation and silent about the mechanism

A diagnostic's NAME describes the state it was raised in faithfully and says nothing
about WHICH PREDICATE produced it. Nothing in the name is wrong, which is why review
reads past it, and a reader who treats the name as a cause builds a coherent story with
no load-bearing contact with the code.

Three receipts in one night from three readers, provenance stated per receipt inside the
row because a row about untraced names must not itself rest on an untraced relay:

  1. Measured by this author, and it leads because the reader was the author of the
     story. rustc labels reading `expected Rc<Vector<i64>>, found String` at 49 sites
     plus 2 reversed; a representation fork in the model type `Symbol` was inferred and
     published. Measured: `Symbol` renders consistently as `String`, `Connective.Atom`
     carries `identity: String`, and the .dag is well-typed with the same declared type
     on both sides. AND THE CHECK FAILED THE SAME WAY THE READING DID -- a grep for the
     printed type name returned zero and zero was read as absence, when the source spells
     `Rc<Vec<i64>>` and lib.rs carries `use im::Vector as Vec`, so rustc was printing the
     resolved underlying name. What the 49 sites actually are is left named and UNCHASED:
     `Rc<Vec<i64>>` is how `List<Int>` renders. The amendment closed the wrong
     explanation, not the defect.
  2. Reported by quick-bat-372, independently verified by warm-hawk-909 at
     04_infer.dag:3541: `MethodNotFound` does not say which predicate gates it --
     `method_existence_decision` gates on `kernel_profile_lookup`, so a fully resolved
     user product with no kernel profile answers `MethodExistenceUndecided`.
  3. Same provenance, verified by exhausting the three FieldNotFound construction sites
     (04_patterns.dag:356 and :362, 04_infer.dag:6234): there is no field-ACCESS
     producer at all.

Two of the three would have shipped as permanently-green witness arms -- an assertion
that a wall fired, over a wall that cannot fire for that input. That is 4b's
decoration-cited-as-coverage reached by a route no existing row names, and all three
were caught by reading the PRODUCER rather than by review. The row carries its own rate
caveat: three instances in one night is a suggestive rate and not a base rate.

Distinctness, since it borders two existing rows and is neither: "identical diagnostic
text is not identical cause" is about two SITES sharing a spelling; "a suggestion names
where the failure was detected, not caused" is about LOCATION. This is about the NAMED
CONCEPT -- one name, accurate and mechanism-silent.

DESIGN.md IS NOT REGENERATED BY THIS COMMIT, AND THAT IS NOT A DEFECT THIS CHANGE
INTRODUCED. No route in this repository regenerates it. `generated_artifact_body_for_path`
is not CLI-callable (it returns `GeneratedArtifactPathBody`, not `ProcessExit`) and is
reached only through the interpreter by claim_executor for drift CHECKING; both consumers
of `Produced` are read-only. There is no --heal, --converge, --write-artifact or
--regen-artifact on any bin, and the hooks do cargo fmt and repo-local git config only.
claim_executor's own comment beside the Produced arm names byte identity here as "exactly
the drift check that has had no owner since" the floor cut, and DESIGN's unguarded list
names heal -- which was the writer. The artifact is therefore stale with respect to this
row until an actuator exists; the actuator is dispatched as its own lane rather than
riding here, because a write beside an existing read is load-bearing enough to deserve
its own reasoning and review.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls merged commit dabe4c5 into main Aug 27, 2026
3 checks passed
@briansrls
briansrls deleted the design/diagnostic-name-mechanism-silent branch August 27, 2026 13:27
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
Second merge of main in one resolution: main advanced 9 commits while the
first regeneration was running, so the same two generated projections
re-conflicted. That is a property of the projection being SHARED -- nearly
every lane edits DESIGN.md -- not of the resolution, and no amount of care
wins the race, only merging sooner.

The .dag authorities merged cleanly again, carrying BOTH main's new
`diagnostic_name_mechanism_silent` row (#9414) and this branch's restored
`bound_shaped_closure`. Only the projections conflicted, and they are
regenerated rather than hand-resolved.

THE REGENERATED DESIGN.md NOW DIFFERS FROM MAIN BY THREE LINES AND ALL
THREE ARE ACCOUNTED FOR. Two are this branch's own edits. The third is the
recurring-failure-mode line, and it differs because MAIN'S DESIGN.md IS
STALE AGAINST ITS OWN AUTHORITY IN THE OPPOSITE DIRECTION FROM THE ORPHAN
REPAIRED IN THE PREVIOUS COMMIT:

  main  DESIGN.md 'accurate about the situation'        -> 0
  main  recurring_failure_mode.dag diagnostic_name_...  -> 3

#9414 landed the authority row without regenerating the projection, so
main's committed DESIGN.md does not render a class its own authority
declares. Regenerating here renders it, which is the correct projection
rather than an edit by this branch.

So this repository currently has generated-artifact drift in BOTH
directions on one file: content in the projection that no authority
produces (repaired in the previous commit), and content in the authority
that the projection does not render (rendered here). Both are invisible to
anyone who does not diff a regeneration against the committed copy and
account for every changed line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 27, 2026
#9414 added a row to `gunbc.recurring_failure_mode` on main. That module is an
input to `gunbc.design_document`, so the merge result's authority no longer
matches the committed projection.

WORTH RECORDING BECAUSE IT IS A PROPERTY OF THE PHASE AND NOT A ONE-OFF: CI
adjudicates the PULL REQUEST MERGE COMMIT, not the branch head, so the phase
compares the projection against the MERGED authorities. A branch that is
internally consistent goes red the moment main lands an authority change under
it -- which is correct, since the post-merge tree is what would sit on main --
and the remedy is always the same: merge and regenerate, never hand-edit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 27, 2026
…a required CI phase — the writer exists and is run by hand, so the gap is enrolment, not a missing regenerator (#9415)

* No route checked DESIGN.md or ROADMAP.md against their authorities: enrol the whole committed generated-artifact population as a required CI phase

`gunbc.generated_artifact_emit` `generated_artifact_body_for_path` is a pure
projection over the three authorities `main_wet` folds -- the committed-artifact
roster, `artifact_path`, and the single `artifact_generate` dispatch -- and it
answers, for any repo-relative path, exactly what the tree ought to hold there.
THE PRODUCER WAS NEVER MISSING AND NEITHER WAS THE WRITER. THE CHECKER WAS.
(Premise correction from warm-hawk-909, who wrote the brief: the work item's
title says no route REGENERATES these files, and that is false --
`tools.generated_artifact_gate` `main_wet` is a declared writer. Nothing here
adds a second one; every repair below was installed by invoking that one.)

From the 2026-08-15 floor cut until this change, the only route that ASKED the
projection anything was `claim_executor`'s behavioural-receipt census, which asks
only about paths of the form `src/v1/stage0/src/<mirror>` because its subject is
emitted Rust mirrors. Every committed artifact that is not a Rust mirror --
`DESIGN.md`, `ROADMAP.md`, the workflow YAML, `.gitignore`, `.gitattributes`, the
githooks, the plans -- was compared by nothing. DESIGN's own CI paragraph named
the generated-artifact drift gates on the re-add queue that cut created; this is
the first item taken off it.

WHAT THE PHASE FOUND ON ITS FIRST EXECUTION, measured at 441ce5c (stated with its
subject sha because the gate's whole purpose is to make this number zero, so it
is not re-derivable from a later tree):

  rostered=72 adjudicated=72 matches=68 drifted=2 absent=2 unadjudicated=0

TWO WERE DRIFT AND ARE REGENERATED HERE:

  DESIGN.md                                  this change's own authority edit
  docs/plans/realization-measurement-loop.md #9394 dissolved the ContainerRuntime
                                             nickname in the authority and the
                                             projection still named it

The second is the headline: an authority-side divergence with a provenance I did
not author, wrong since #9394, invisible to everything. It is also what proves
the generator READS the authority -- a checker comparing a file to itself cannot
produce it.

THE OTHER TWO WERE NOT DRIFT AND ARE NOT REGENERATED. `docs/plans/v2-corpus-self-host.md`
was DELETED ON PURPOSE by a295e17, whose entire subject is the ruling that the
.dag carrier is the authority and the markdown should not exist;
`docs/plans/import-namespace-program.md` has never existed at that path. An
earlier revision of this branch regenerated both. That was wrong, and the way it
was wrong is the most dangerous shape this phase can have: a drift gate makes
whatever it adjudicates BINDING, so an absence that was inert before becomes a
line-stop, and the cheapest way to move the line is to regenerate -- converting a
dormant registry mistake into a standing obligation to recreate deleted files,
green either way. Caught in review by warm-hawk-909.

THE STALE HALF WAS THE REGISTRY ROW, NOT THE MISSING FILE, so the repair runs the
other way: `gunbc.plan` gains `PlanProjection`, a plan declares whether its
markdown is a committed artifact at all, and `artifact_commit_policy` asks the
plan instead of answering `CommitRequired` for every slug. `PlanIsAuthorityOnly`
carries the ruling that removed the projection, so the row cannot drift from its
reason. It is NOT an exemption list and NOT a shrink: both plans stay rostered,
stay generated, and still refuse if generation refuses -- only whether their bytes
are expected on disk changes. The field is required, so a new plan cannot omit the
decision.

CONSTRUCTION, not another roster. The host resolves `generated_artifact_emit` once
and asks it for BOTH the roster (`committed_generated_artifact_paths`) and each
body, so an artifact added to `generated_artifact_registry` is enrolled with no
edit to the host, and a path list in Rust -- the second roster DESIGN 3 forbids --
does not exist. Production precedes adjudication in the TYPE: every verdict is
reached through the produced population, so "refused, having compared nothing" has
no spelling outside the arms that carry no population.

TWO COUNTS, NEVER ONE. A rostered member that reaches no verdict is reported and
stops the line SEPARATELY from a drifted one. `0 drifted` over a population
nothing asked about is the execution-provenance loss DESIGN names, and the
discriminating unit test asserts exactly that: an outcome whose every verdict
matched is NOT clean while one member is unadjudicated, and is still not reported
as drift.

READ-ONLY BY CONSTRUCTION: no write path, no flag that opens one. Installing a
regenerated artifact stays `main_wet`'s job, because a gate that can also write
its own subject is a gate whose green proves nothing.

The bridge `claim_executor` had declared privately (`GeneratedArtifactPathBody`,
`generated_artifact_ctx`, `generated_artifact_body_for_path`) is hoisted into
`v1_compiler::cli_run::generated_artifact_boundary_host` and re-exported through
`cli_run`, the way the regen and partition-crate producers already are, rather
than copied -- two hosts asking one projection is the forked dispatch DESIGN 3
forbids. The new file is registered as seed-retained hand Rust in
`v2.compiler.self_host.stage0_crate_layout`, beside `partition_crate_boundary_host`;
its layout projections are regenerated.

The refusal names a route that EXISTS, in one place
(`GENERATED_ARTIFACT_PRODUCING_COMMAND`), because a stop whose only sanctioned move
is unavailable does not stop the line, it launders a hand edit.

EXECUTED, whole build lane, from binaries built out of this tree:

  regen first_generation_equal=true
  v2-emission EmissionCompleted blocking=0
  partition-crates rendered=14 matches=14
  generated-artifact rostered=70 adjudicated=70 matches=70 drifted=0 absent=0 unadjudicated=0
  lane=build phases_run=4 failed=0

WHAT IS NOT CLAIMED: `main_wet` generates and writes one artifact at a time, so a
refusal partway would install a mixed projection epoch. That is a mechanism read,
not an executed receipt -- no generation refused here -- and it is left to its own
PR with its own receipt rather than repaired on a hypothesis.

THE SEED-GROWTH OBLIGATION FOR THE NEW HOST RUST (codex/gpt-5.6-sol, review 56588).
The registration in `stage0_crate_layout` acknowledges the file; it does not
reconcile it with DESIGN 7's shrinking-seed mandate, and that reconciliation is
what the gate requires. `gunbc.generated_artifact_boundary_seed_growth` now
carries it, joined into `gunbc.seed_growth_admission`'s roster: 19 declarations
enumerated at identity grain rather than counted, the reason Rust is needed at
all (the comparison is against BYTES ON DISK, a host effect the hermetic floor
refuses by construction), the rejected alternative and why (running the existing
gate through the interpreter in Wet mode makes the interpreter load-bearing for a
NEW required phase while two lanes delete it, and would drag in
`artifact_extra_valid`'s `ci_yml_parses` as a second unasked subject), the owning
lane (`v1-hand-queue-drain`), and a trigger that names the capability rather than
an artifact: delete all 19 when a modeled operation can read a committed file's
bytes inside the required envelope.

THE FOUR INHERENT METHODS BECAME FREE FUNCTIONS TO PAY THAT OBLIGATION HONESTLY.
`std.decl_ref` offers `WholeDeclaration` or `NamedField` and neither names a
method on an `impl` block, so every method would have been an item this roster
could not cite -- growing exactly the uncitable-item class
`gunbc.seed_growth_admission` counts. There is now no `impl` block in the file
and zero of the 19 rows are uncitable.

NET, STATED SO THE ROSTER IS NOT MISREAD AS A DIFF: three of the 19
(`GeneratedArtifactPathBody`, `generated_artifact_ctx`,
`generated_artifact_body_for_path`) are DELETED from `bin/claim_executor.rs` in
this same change, so the corpus-wide delta for those three is zero and only their
home moved.

THE PROJECTION DECISION DESCENDS INSTEAD OF COLLAPSING (codex/gpt-5.6-sol,
review 56610). The first cut of `PlanProjection` carried a
`plan_projects_committed_markdown(p) -> Bool` predicate that matched the coproduct
into true/false, and `artifact_commit_policy` then branched on the Bool. That is
the predicate residue DESIGN 6 forbids, and it is also the "total at the level
examined, blind one level down" shape one entry over: a second projection state
would have had to pick an existing Bool rather than failing to compile at the
decision. The predicate is DELETED and `artifact_commit_policy` matches
`plan.projection` directly, so a new `PlanProjection` variant fails to compile
exactly where the commit policy is decided.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Regenerate two plan projections the merge left behind

`docs/plans/budget-tree.md` and `docs/plans/ci-humming.md` are projections of
`gunbc.plans.budget_tree` and `gunbc.plans.ci_humming`, both of which git
auto-merged when main came in. The regeneration ran, but its output was left
UNSTAGED and `git commit` on a merge commits the index -- so the merge commit
carried the merged authorities and the pre-merge projections.

Caught by the `generated-artifact` phase this branch adds, on its own branch,
naming both paths. That is the phase doing exactly what it exists for, on the
class it exists for, against its own author.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* An empty roster reported clean: refuse it at the producer and at the predicate

Found in review (codex/gpt-5.6-sol, review 56696), and it is a real defect in
exactly the class this phase exists to close. `boundary_is_clean` required that
every verdict matched and nothing was unadjudicated -- both VACUOUSLY TRUE of an
outcome carrying zero members. So a run that adjudicated NOTHING rendered
identically to a run that adjudicated seventy paths and found them all correct,
and neither reporting branch in the phase body fired, so the line did not stop.

That is the empty-observation narrow DESIGN names -- bottom-as-answer conflated
with bottom-as-ignorance -- and it is strictly worse than the widen 5 already
forbids: a widen is merely expensive, a narrow is silently uncovered. The PR body
claimed "nothing was asked cannot appear clean". It could.

CLOSED AT THREE LEVELS, none of them redundant with the others because each is
reachable where the next is not:

  PRODUCER. `run_generated_artifact_boundary` refuses an empty roster with a
  typed cause. `committed_generated_artifacts` filters a module-scope literal, so
  empty is never a fact about the tree -- it means the projection or this bridge
  lost sight of the population, which is ignorance and must refuse.

  PREDICATE. `boundary_is_clean` no longer admits an empty population. This
  covers any outcome VALUE, including one a caller or a fixture builds by hand,
  which is the only boundary at which the state is still expressible now that the
  producer refuses it -- and therefore the only boundary at which its RED is
  authorable, which is what 4b requires before a check is worth writing.

  PHASE. The phase's verdict now derives from `boundary_is_clean` alone; the two
  reporting branches name WHAT went wrong, they no longer decide WHETHER anything
  did. A state neither branch happens to describe refuses with an explicit
  unnamed-cause line rather than falling between them. A second definition of
  clean beside the carrier's is the fork that lets a ledger and a gate disagree
  about one run.

THE DISCRIMINATING RED IS AUTHORED AND CARRIES ITS POSITIVE CONTROL:
`an_empty_population_is_not_clean_even_though_no_verdict_disagreed` asserts the
empty outcome is not clean AND that a single matching member still is, so the
conjunct is emptiness rather than a blanket refusal. It returns green under the
previous code, which is the state it exists to forbid. Five tests pass.

The seed-growth roster grows by one to 20 and its trigger is re-counted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Regenerate DESIGN.md against main's recurring-failure-mode addition

#9414 added a row to `gunbc.recurring_failure_mode` on main. That module is an
input to `gunbc.design_document`, so the merge result's authority no longer
matches the committed projection.

WORTH RECORDING BECAUSE IT IS A PROPERTY OF THE PHASE AND NOT A ONE-OFF: CI
adjudicates the PULL REQUEST MERGE COMMIT, not the branch head, so the phase
compares the projection against the MERGED authorities. A branch that is
internally consistent goes red the moment main lands an authority change under
it -- which is correct, since the post-merge tree is what would sit on main --
and the remedy is always the same: merge and regenerate, never hand-edit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Install the regenerated stage0 layout mirror: the merge resolution took main's copy, which predates this branch's host registration

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <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.

1 participant