Skip to content

A citation in the wrong namespace: file the second cause on the class that owns the invariant - #10841

Merged
briansrls merged 2 commits into
mainfrom
session/smart-ant-528-namespace-citation
Sep 8, 2026
Merged

briansrls merged 2 commits into
mainfrom
session/smart-ant-528-namespace-citation

Conversation

@gunbai-bot

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

Copy link
Copy Markdown
Contributor

Appends a receipt to unlanded_citation_indistinguishable_at_the_citing_end. One file, no new class, no repairs to other authorities.

Why a receipt and not a new row

Checked the row directory whole at origin/main first. The invariant is already owned: that row rules "a canonical row may cite only what resolves on main at the moment the row lands." A Rust item spelled in .dag dotted syntax violates exactly that rule, so this is a second cause for one invariant, not a new class.

positional_citation is the other near neighbour and is distinct — it owns file:line and text-anchored edits, where the handle is positional by construction.

The specimen

An annotation cited v1.compiler.cli_run run_dag_parse_sweep and v1.compiler.bin.v1_src_dag_parse. Neither module exists or ever will: both are Rust items — a crate module and a cargo bin — wearing .dag dotted-module syntax.

The discriminator, which is why the repairs differ

The timing cause cites a real identity early: it resolves eventually, and all three admissible forms that row ranks work by managing that interval — name the PR and its openness, or describe by shape until it lands.

The namespace cause never resolves. There is no PR to name and no landing to wait for, so none of the three forms applies; the repair is to cite the symbol in its own namespace. Same invariant, different cause, different repair.

It is a rule gap, not four sloppy authors

DESIGN §3 says cite the symbol rather than the position and says nothing about namespace, so a Rust item in dotted form violates no stated rule — and the dotted form is the only citation idiom the prose has, making it the default spelling for a cross-language symbol. That is a defect of the available vocabulary, exactly as this row's filed receipt is a defect of the available word.

The proposed lens trigger is refuted, by the owning row

The proposal was a lens refusing a dotted prefix matching no declared module. That row's own ceiling paragraph already rules it out: deciding whether an identity-shaped token in a paragraph is a citation or a mention is undecidable, so a prose scanner is a heuristic and §5 forbids dressing one as a wall.

The demonstration is self-applying — such a lens would red on the receipt's own paragraph, which names every non-resolving spelling in order to record it. A check whose first false positive is its own class's ledger entry is not a wall.

The trigger is instead a typed cross-language symbol reference. std.decl_ref DeclarationRef carries module_path + decl_name and resolves against .dag modules, so a Rust citation has no typed form to climb into and stays prose by necessity, not by choice. Until that exists the cause sits where the row already puts the class: outside the modeled guarantee, observed and repaired by reading.

Population named, not counted, and not repaired

The members are enumerated by symbol rather than counted — a count of a live population is the transcribed-measurement decay surface §6 forbids, and an identity list is what a later reader can re-join. The instrument (a corpus grep against origin/main, not the working tree) is named so it can be re-derived.

None is repaired. Three separate authorities, not this filing's subject, and a row that silently repairs its own evidence leaves a reader unable to check it.

Honesty

Rung unchanged at mitigatable. The receipt was written by the author who introduced the specimen, two hours after fixing the identical spelling in another PR where a reviewer flagged it — so the census after a correction has to run forward over what is written next, not only backward. The same pass swept the PR body, a second asserting site no diff-scoped check reads.

Verification

  • v1_src_dag_parse: 5235 files parse-clean.
  • gunbc compile with this row as entry: 0 blocking errors, no diagnostic on the edited module.
  • Only pre-existing text change is the closing paren moving to the new final receipt; the sentence it was attached to is preserved verbatim.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MuB8wHjijaFwNoyzm78stF

… the invariant

Checked the row directory whole at origin/main before writing. The invariant is
already owned: unlanded_citation_indistinguishable_at_the_citing_end rules that
a canonical row may cite only what resolves on main at the moment it lands. A
Rust item spelled in .dag dotted syntax violates that rule, so this is a second
CAUSE for one invariant, not a new class — filed as a receipt rather than a row.

The discriminator is why the repairs differ: the timing cause cites a real
identity early and its three admissible forms manage that interval; the
namespace cause never resolves, so naming a PR or waiting for a landing is
useless and the repair is to cite in the symbol's own namespace.

THE PROPOSED LENS TRIGGER IS REFUTED BY THE OWNING ROW, and the refutation is
recorded because it is more useful than the proposal. That row already rules
that deciding citation-versus-mention inside prose is undecidable, so such a
scanner is a heuristic. It would red on the receipt's own paragraph, which
mentions every non-resolving spelling in order to record it. The trigger is
instead a TYPED CROSS-LANGUAGE SYMBOL REFERENCE: DeclarationRef resolves
against .dag modules only, so a Rust citation has no typed form to climb into.

The four sites are named rather than counted and are NOT repaired — three
separate authorities, and a row that silently repairs its own evidence leaves a
reader unable to check it.

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

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head review of 28e15cc: REQUEST_CHANGES.

The fold into unlanded_citation_indistinguishable_at_the_citing_end is sound. The new specimen shares the row's invariant (a canonical citation that cannot resolve at the citing end), while the cause differs from the timing case; rejecting the proposed prose lens is also correct, because citation-vs-mention is not decidable from an identity-shaped token in prose and the proposed scanner demonstrably reds on the receipt that describes it.

One load-bearing trigger claim is false on the current tree. The new receipt says a typed Rust-symbol reference can resolve against the seed's own declaration index, which the parse sweep already builds. That index does not index Rust items. run_dag_parse_sweep parses every .dag file under DAG_PARSE_SWEEP_ROOTS and constructs one ModuleDeclarationRecord per declared .dag module; its cited-symbol wall resolves authored DeclarationRef literals against those .dag declaration records. A Rust crate module, Rust function, or Cargo-bin identity is outside that index's population by construction.

Keep the capability-grain trigger — a typed cross-language/Rust-symbol reference is a defensible next rung — but do not claim the existing .dag declaration index already supplies its resolver. The trigger must name the missing Rust-symbol authority/producer (or a future cross-language index that includes it) without pre-solving that design. Otherwise the row records another trigger that appears buildable from an existing capability but cannot actually be retired by the construction it names.

I would also narrow or remove the claim that dotted form is the ONLY citation idiom the prose has; that exclusivity is not needed to establish the vocabulary gap. The load-bearing point is that DESIGN/std.decl_ref provides no typed Rust-symbol carrier, not that authors have no textual way to write a Rust path.

Freshness is separate: current main advanced after this head, so any corrected/integrated head is a new subject. No merge action taken.

…is unbuilt

The trigger named the seed's declaration index as what would resolve a typed
cross-language reference. It cannot: ModuleDeclarationRecord carries a .dag
module_path plus the item names authored in that module, built by parsing .dag
sources, so Rust crate modules, functions and cargo bins are outside its
population entirely. Pointing a cross-language trigger at it would make the
trigger look reachable while nothing it names could ever resolve a Rust symbol
— the trigger-grain defect this ledger keeps recording, and the third variant
of it I have written today.

The capability stands; its Rust-side producer is stated as genuinely unbuilt.

Also dropped the exclusivity claim that the dotted form is the ONLY citation
idiom the prose has. The vocabulary gap does not need it, and it was the
stronger claim of the two available.

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

gunbai-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Both findings addressed in 0f313544f7, pushed 17:30:09Z — after this review was submitted at 17:19:33Z against 28e15ccde7, so they crossed.

The declaration-index claim. Verified in source before rewriting rather than from the review text: ModuleDeclarationRecord carries module_path, rel_path, declared, variants — .dag module paths and the items authored in them, built by parsing .dag sources. Rust crate modules, functions and cargo bins are outside that population by construction, exactly as stated. The row now records the retraction rather than quietly repointing, and says the Rust-side producer is genuinely unbuilt:

ITS PRODUCER IS GENUINELY UNBUILT AND THIS ROW MUST NOT BORROW ONE, which an earlier revision did and is corrected here rather than quietly: it named the seed's own declaration index as the resolver. THAT INDEX CANNOT SERVE.

The exclusivity claim is dropped — now "the idiom every in-corpus citation uses" rather than "the ONLY citation idiom the prose has." You're right that the vocabulary gap does not need it; it was the stronger of the two available claims and the one I could not have established.

The finding is worth more than the fix, and I'd rather name it than let it pass as a wording nit: this is the third variant of the same trigger-grain defect I wrote today — one trigger naming an already-built capability, one naming a surface the corpus forbids, and this one naming a producer that exists but cannot serve. All three look reachable while nothing they name can retire them. That the third landed inside a row about citations that cannot resolve is the part I should have caught.

On freshness: agreed that an integrated head is a new subject. Holding integration until there is a merge to catch, rather than re-integrating against a base that keeps advancing while nothing can land.

— sent from smart-ant-528

@briansrls
briansrls merged commit 4866fd7 into main Sep 8, 2026
4 checks passed
@briansrls
briansrls deleted the session/smart-ant-528-namespace-citation branch September 8, 2026 18:11
briansrls pushed a commit that referenced this pull request Sep 9, 2026
…tor's declared input (#10871)

* The third state of `0 -> 1`: a derived module's binding to its generator's declared input

The wave-admission wall has refused every change that ADDS a failure-mode row file
since gunbc#10822, and admitted every change that edits one. Measured across five
lanes and seven changes with no exceptions: #10710, #10842 and #10837 refuse;
#10832, #10841, #10811 and #10835 pass. #10835 is the one that names the predicate
correctly -- it is additions-only by diffstat and PASSES, so "additive" is not the
discriminator and no diffstat can be. The predicate is a row MODULE THAT IS NEW AT
THE BASE, which is a question about state.

WHY IT REFUSED. binding_disposition reads `0 -> 1` through authorship: the target grew
a name this module was reaching for (a coincidence in the pool, cause elsewhere) versus
this module's own author writing what resolves a name it already spelled (the repair
the wall wants). THAT DISCRIMINATOR PRESUMES A MODULE THAT HAS AN AUTHOR. Since
gunbc#10822 the roster is generated from the row directory, so it has none:
`authored_here` is false for every binding it will ever acquire, and each new row read
as a coincidence. The membership arm already reached the opposite answer on the same
files -- an added row edge auto-admits as ExplicitlyEvaluatedZeroDelta, "reached by a
name this module authors" -- so the two arms disagreed about one file, which is the
tell that the disposition and not the population was wrong.

This is the SAME SHAPE as the 2026-08-27 split that created AuthoredReferenceResolution
after the wall refused gunbc#9485, and it lands the same way: one symbol carrying two
states with opposite owners and opposite repairs, separated rather than weakened.

WHAT IS ADMISSIBLE IS NOT "THE MODULE IS GENERATED", and that distinction is the whole
arm. Exempting the category would auto-admit every binding any generated module ever
acquires, on the one surface where a wrong binding has no human reader -- the same
state-space conflation committed in the fail-open direction. What is admissible is a
binding that is THE MECHANICAL IMAGE OF THE GENERATOR'S DECLARED INPUT RELATION:
derived_row_roster declares the roster is produced by reading ROW_MODULE's directory,
so a roster binding whose every candidate is a module of that directory is the
deterministic consequence of a file the change adds, decidable from the generator's own
constants rather than from a reader's judgement.

EVIDENCE, BOTH ARMS IN THIS COMMIT
  a_derived_roster_binding_to_a_new_row_module_is_the_generators_declared_input
    classifies DerivedGeneratorInputResolution AND adjudicates. Disabling the new arm
    turns it RED, so the green is the fix's and not the fixture's.
  a_derived_roster_binding_outside_its_generators_inputs_still_refuses
    same derived module, same `0 -> 1`, same absence of an author, target outside the
    generator's inputs: stays NewPoolCoincidenceResolution and stays unadjudicated.
    It is GREEN IN BOTH STATES -- with the arm and without it -- which is what makes it
    a positive control rather than a mirror of the first test. If it ever greens as
    admitted, the wall was widened rather than sharpened.
Full wall suite 52/52, including the vocabulary check that refuses when the host enum
and the .dag authority disagree about the coproduct.

THE FIXTURE ITSELF CARRIES A FINDING. A first version had the roster spell the row name
bare, and produced ZERO deltas -- because a row module is a SIBLING of the roster, so
the bare name resolved to nothing on both sides and the sets were equal. Both arms were
then asserting over an empty list: a test that cannot fail, for a reason unrelated to
what it claims to test. The generated roster imports each row explicitly, which is what
makes the candidate set move `{} -> {module}`, and the fixture now reproduces that
transition rather than resembling it -- verified against the subject and detail string
the production report emits.

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

* Enumerate the new declaration, and state the partition where the partition is stated

review 62773, both findings verified against the tree and both real.

THE INTERLOCK ONE IS THE DEFECT I HAVE BEEN FILING ALL DAY, COMMITTED BY ME. The
partition paragraph enumerated FOUR auto-admitted dispositions; the arm I added made
it five, and I recorded the fifth only beside the arm. One authority then answered
the same question two ways -- a section 3 fork, and a stale-claim instance in
miniature: my edit was correct and it falsified a sentence elsewhere that nothing
joins to it. The sentence now carries the fifth member, with a note saying why it
belongs there rather than only at the declaration that introduced it.

THE SEED-GROWTH ONE: derived_generator_input_binding is enumerated in
hand_authored_declarations, in the CLASS A prose list, and in the trigger's
pure-fold list -- the three places that roster claims exact name-bijection, the
bijection gunbc#10856 repaired and which decays the moment a lane adds a declaration
without a row. Verified by IDENTITY JOIN rather than by count, filtered on
module_path: 43 rostered for this module against 43 declared, empty in both
directions. The unfiltered join reports a false positive (`dotted_chain`, a
legitimate row for v1_compiler.declaration_index), which is why the filter is part
of the check rather than a detail.

AND THE RECEIPT IS HONEST ABOUT WHAT THIS GROWTH BOUGHT: NOTHING WAS DELETED. No
scaffold removed, no fork consolidated; the count goes 42 to 43. What it buys is the
wall's ability to admit an append the generator itself produces, which before this
refused across five lanes and seven changes. The alternative adding NO declaration --
widening authored_here so every generated module counts as authored -- is the
fail-open direction of the conflation this split repairs, so the declaration is the
price of not weakening the wall. CLASS A, dissolving with its neighbours unchanged.

Wall suite 52/52 after both edits.

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

* Re-home the doc block: the set-disposition paragraphs describe binding_disposition

review 62782, verified. Inserting the new predicate directly above
binding_disposition attached that function's ENTIRE doc block to the new symbol --
"Which disposition a changed candidate SET carries", "EVERY ARM IS OVER SETS",
"`0 -> 1` IS TWO STATES", and the discriminator paragraph -- and left
binding_disposition, whose signature this PR changed, with no documentation at all.
The block also carried two summary lines for one item.

THIS IS THE SAME CLASS AS THE FINDING ONE ROUND EARLIER, and that is worth naming
rather than fixing quietly: a correct edit silently re-homed a claim about a
DIFFERENT symbol, with nothing joining the claim to the thing it describes. The
interlock partition sentence, the roster's bijection, and now this -- three
instances in one change, each caught by a reader and none by a mechanism.

Re-split so each block sits on the symbol it describes: the set-disposition and
third-state paragraphs on binding_disposition, only the generator-input paragraphs
on derived_generator_input_binding.

AND ONE THE REVIEW DID NOT RAISE, WHICH THE RE-SPLIT EXPOSED. That paragraph said
"the discriminator BELOW" -- a positional reference. The move happened to make it
accurate again, which is exactly why the form is wrong: a position silently
re-points under any edit above it and cannot be checked, which is what section 3's
cite-the-symbol rule is for. It now names `authored_here`.

Wall suite 52/52.

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

* Remove a fabricated default from an auto-admission path; the generator owns its module name

review 62792 (APPROVE, non-blocking) and it is worth fixing rather than deferring.
The wall recovered the roster's module name with
`ROSTER_BASENAME.strip_suffix(".dag").unwrap_or("roster")` -- a GUESS substituted
when the suffix is absent. It cannot fire today, but the arm it guards is an
AUTO-ADMISSION on a safety wall: respell that constant and the predicate keeps
comparing against a plausible fabricated name instead of refusing, which is the
fabricated plausible output section 5 forbids outright.

FIXED AT THE AUTHORITY RATHER THAN THE CONSUMER, which is the reviewer's sharper
half: the wall was re-deriving a name its GENERATOR owns. derived_row_roster now
declares ROSTER_MODULE, with the reason recorded there -- any consumer recovering
the name must decide what to do when the suffix is missing, and every such choice
is a guess about a name that module owns. The wall consumes the constant, so there
is no default left to guess: the state is unwritable rather than defaulted, which
is construction over a better fallback.

The seed-growth receipt records it honestly: this adds a constant to ANOTHER
module's roster and REMOVES a fabricated default from this one, rather than adding
capability here.

Wall suite 52/52, clippy --all-targets clean.

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

* Enumerate ROSTER_MODULE in the generator's own roster, with the removal receipt

A consequence of the previous commit, caught before CI: derived_row_roster carries
its OWN seed-growth roster, so declaring ROSTER_MODULE there put THAT module's
name-bijection out by one -- the same decay review 62773 flagged on the wall's
roster, one module over. It is enumerated now, and the receipt records what the
addition actually is: it REMOVES a consumer's guess rather than adding capability.
One constant added, one strip-and-default recovery deleted from an auto-admission
path, no new host capability, dissolving with this row's existing trigger.

AND A NOTE ON THE INSTRUMENT, because it nearly produced a large wrong repair. My
first join over that file reported `rostered: 0, declared: 14` -- a module with
nothing enumerated at all. The roster was fine; my regex assumed multi-line
DeclarationRef blocks while that file writes them on ONE line. Trusting it would
have meant "repairing" fourteen rows that were already correct. A join is only as
good as its extractor, and an extractor that silently matches nothing reports the
same shape as a genuinely empty roster.

Wall suite 52/52; the generator's bijection is empty in both directions again.

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

* State the arm's residual risk in the tree, not in a review thread

The arm trusts the generator's DECLARED inputs, and what it checks is the
declaration rather than the generator's behaviour. A generator whose implementation
drifts from what it declares -- reading a second directory, emitting a binding no
input explains -- would be auto-admitted against a stale premise, silently, because
that premise is precisely what the wall is not in a position to re-derive.

Recorded beside the arm because a residual risk that lives only in a review thread
is not reachable from the thing it qualifies. It is an honest boundary rather than a
rung: the ceiling is a generator whose declared inputs ARE its inputs by
construction, and until that exists the mitigation is that declaration and
implementation share one module, so drift is a same-file edit rather than action at
a distance.

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

* Disclose that the arm answers for ONE generator, and name what a second would need

The prose explained the arm well enough that a reader would reasonably conclude it
generalizes over generators with declared inputs. It does not: the realization
refuses every module that is not the failure-mode roster, so a second derived module
is refused exactly as the first was and the repair would be someone editing the
predicate to name it. That is a hand-maintained membership list where each member
costs an edit -- the shape gunbc#10822 has just finished deleting one layer up.

DISCLOSED RATHER THAN GENERALIZED, because the narrowness is probably right: it is
decided from that generator's OWN constants rather than a literal spelled in the
wall, and a general arm needs a carrier where a generator declares its input
relation. That carrier does not exist -- gunbc.generated_artifact's GeneratedArtifact
is a closed coproduct of artifact IDENTITIES and carries no inputs -- so there is
nothing for a general predicate to consult, and inventing one inside a required-gate
repair would be modelling a substrate concept to unblock a wall.

The absence is the trigger, and it is now stated in the authority rather than left
for the next author to discover by hitting a refusal and reading prose that overstates
its own reach. That failure -- an authority that keeps claiming what stopped being
true, with nothing reclassifying it -- is the class this lane filed a row about
yesterday.

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

---------

Co-authored-by: gunbai-bot[bot] <289086189+gunbai-bot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Brian Searls <briansearls1@gmail.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