Embedded-region dispatch: EMBEDDED_DISPATCH_SEMANTICS_VERSION = 0, so no file can carry two producers and #77's criterion 2 is unexercisable #119
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
h-dv/code-index#119
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split out of #77 by the #76–#79 audit, so that #77 can close on the work it actually owns without laundering an unexercised criterion.
The gap
activation::EMBEDDED_DISPATCH_SEMANTICS_VERSION = 0. Routing is whole-file, single-owner (crates/indexer/src/dirty.rs:181-191). One file has exactly one producer, always.So #77's criterion 2 — "a mixed-language file carries multiple producers" — cannot be exercised in this build. Not "is untested": there is no configuration of this system in which it could be true.
What is NOT missing, and this is the important half
The provenance model for it is complete and graded:
m0044_row_languagetook row language offfiles.lang, so language is a row-level fact rather than a file-level one;file_contributionscarriesregion_start/region_end, keyed per generation — the storage for two contributions in one file already exists;provenance_invariants.rs::deleting_one_contribution_takes_only_its_own_rowsproves the per-contribution isolation that multi-producer routing depends on.The schema is ready. The dispatcher is what does not exist. That is why this is a named feature rather than a hole in #77's design, and why it belongs to the routing layer (#78/#79) rather than to the resolver-provenance issue.
Why it is worth its own issue rather than a line in #77's close
#75's governing text asks for a mixed-language file with multiple producers as a demonstration of the architecture, and XAML→C# is the motivating case. Closing #77 quietly would leave that requirement owned by nothing.
It is also the honest reading of a pattern this project keeps paying for: a criterion whose test cannot run is indistinguishable from one that passes. #84's axis C graded zero and passed; #109's weekly jobs skip on every scheduled run; #116's ceiling cannot fail for either regression its own comment names. "C2 is met because the schema supports it" would be the same move.
Acceptance
file_contributionsrow with its ownregion_start/region_endand its own row language.EMBEDDED_DISPATCH_SEMANTICS_VERSIONmoves off 0, and the version is part of the activation identity so a dispatch-semantics change invalidates what it should.Related
Split from #77 (criterion 2). Feeds #75's mixed-language demonstration. Adjacent to #112 (three non-pool language gates a package cannot close) — both are cases where the packaged path is structurally narrower than the builtin one.
Verdict, asked directly: not closable now. It needs the #154 design, and specifically two of #154's three missing primitives.
Judged against this issue's own four acceptance criteria rather than against the schema, because the schema half is exactly the half that is already done.
What is genuinely ready, re-verified
file_contributionscarriesregion_start/region_endkeyed per generation (m0043, re-keyed by m0051), m0044 made language a ROW fact rather than a file fact, andprovenance_invariants::deleting_one_contribution_takes_only_its_own_rowsproves the per-contribution isolation criterion 2 depends on. Criterion 2 of the acceptance — "deleting one contribution takes only its own rows, now with TWO live contributions in one file" — is a strictly weaker statement than what that invariant already proves, once two contributions can exist. Nothing there is in the way.What is in the way, and it is not the dispatcher alone
The issue says "the dispatcher is what does not exist". That is true and it understates it. Routing is whole-file single-owner in
classify_walked, and turning it into region routing needs four things this tree has none of:A region DETECTOR, and it has to belong to somebody. Who says where the
<script>block in an HTML file ends? Not the host — it has no HTML grammar. Not the second producer — it is not running yet. So the OUTER producer has to be able to emit "bytes [a,b) are language L", which is a new fact kind on the extraction wire, not a routing change. Nothing incode_index_abi::recordcan say it today.A region-scoped source view. A guest receives the file and emits spans into it. A second producer handed only
[a,b)emits spans relative toa; one handed the whole file may emit spans outside its own region, and the ABI's strongest check —name == src[name_span]— cannot tell those apart. Whichever is chosen is a wire-contract decision.Precedence when regions overlap or a claim is ambiguous.
UNIQUE (file_id, component_id, region_start)permits two rows; it does not say which wins when two producers claim overlapping bytes, and #91's duplicate-id ordering settles a different question.A containment constraint so the second producer's rows are worth having. This is the point at which #119 stops being independent of #154. A
<script>block dispatched to the JS producer yields JS symbols in an HTML file, and the interesting edges — the handler named by an attribute, the member of this component class — are exactly #154's wall: "the candidate side is the whole project's symbols of one kind with no containment constraint at all". Region dispatch without #154's primitive 1 produces a second set of rows that bridges can only join by bare name, which is the un-bridgeablemember_accessthe XAML{Binding …}case already demonstrates.So: which is it?
Criterion 3 alone is closable in an afternoon and MUST NOT BE.
EMBEDDED_DISPATCH_SEMANTICS_VERSIONmoving off 0 with no dispatcher behind it would be precisely the move this issue's own text warns about — "a criterion whose test cannot run is indistinguishable from one that passes" — with the version bump standing in for the evidence. The constant is honest at0today:activation.rs's doc says in as many words that zero means whole-file single-owner routing, and that is a true description ofclassify_walked. It should stay at 0 until something changes routing, and it should move in the SAME commit that changes it, because its whole job is to invalidate indexes built under the old semantics.Recommendation: keep #119 open, and re-scope its dependency line from "adjacent to #154" to blocked on #154 primitives 1 (containment constraint) and, for the detector, on a new region fact on the extraction wire. It is a feature with a wire change in it, not a hole in #77.
One correction to this issue's text
It cites #112 as a sibling — "both are cases where the packaged path is structurally narrower than the builtin one". That is still the right pairing, but #112 is now fixed, by one gate (
code_index_core::lang_profile) rather than three exceptions, and measured on the #84 Ruby parity leg: the three pinned mechanisms went1260 -> 0,53 -> 0,19 -> 0in a single pass while the two mechanisms it does not touch stood still. The remaining structural narrowness of the packaged path is #86's missing qualifier TEXT field (876 rows) and this issue. That is a shorter list than it was.🤖 Generated with Claude Code
https://claude.ai/code/session_01K1zj5VcFJvJt3pQxe9259K
Second lane, same verdict: not closable, and not attempted here. Two of the previous comment's claims are now confirmed FROM THE CODE rather than argued, and one acceptance criterion turns out to be half met already.
The packaged-language lane held #119 today. It was not built, and the reason is not effort — it is that two of its four prerequisites are somebody else's design decision and the third is a wire change. What this comment adds is evidence for the parts that were previously reasoning.
Confirmed from the code: the bridge really has no containment constraint
The previous comment made #119's dependency on #154 turn on this, and #154 asserts it in prose. It is exact.
fill_bridge_cands(crates/indexer/src/index.rs:2826-2867) builds the candidate side with:That is every symbol in the project of one language and one kind. The only narrowing applied afterwards is the scope predicate —
same_file/paired_file/same_directory, carried asdirandpair_keycolumns — and every one of those is FILE-shaped. None of them can say "a member of the class this file names".So a
<script>block dispatched to a second producer would yield rows that bridges can join by bare name across the whole project. That is the same wall that makes XAML's{Binding …}emit as un-bridgeablemember_access, and it is why region dispatch without #154's primitive 1 buys a second set of rows that cannot be joined usefully to the first.Confirmed from the code: there is still no region fact on the extraction wire
code_index_abi::ReasoncarriesFactRegionOutOfRangeandFactRegionDepthExceeded— which looks, at a glance, like the wire already speaks regions. It does not. Both are codes with no producer, and the tree grades that fact rather than leaving it ambiguous:crates/abi/tests/reason_producers.rs:86-92asserts they are emitted by nothing, and their only other mentions in the tree are//!doc lines inconform.rs,expect.rsanddirty.rsexplaining why.That is the honest state, and it is worth saying plainly because the codes' existence is exactly the kind of thing a later reader mistakes for a shipped mechanism.
One correction to the acceptance list: criterion 3 is HALF MET
Criterion 3 reads "
EMBEDDED_DISPATCH_SEMANTICS_VERSIONmoves off 0, and the version is part of the activation identity so a dispatch-semantics change invalidates what it should."The second half already holds.
crates/indexer/src/activation.rs:168foldsembedded_dispatch_version: EMBEDDED_DISPATCH_SEMANTICS_VERSIONinto the activation identity today. So the invalidation machinery is in place and waiting; what is missing is only the routing change that would justify moving the number.This strengthens rather than weakens the previous comment's warning. Criterion 3 alone is now even cheaper than "an afternoon" — it is one character — and it MUST NOT be taken that way. The constant is honest at
0:activation.rs's own doc says zero means whole-file single-owner routing, and that is a true description ofclassify_walked. Moving it with no dispatcher behind it would invalidate every index in the field to record a semantics change that did not happen, and would stand in for evidence exactly as this issue's text warns.It should move in the SAME commit that changes routing. Nothing else.
Status of the four prerequisites
name == src[name_span]; a second producer handed only[a,b)and one handed the whole file are indistinguishable to itUNIQUE (file_id, component_id, region_start)permits two rows and says nothing about who winsfill_bridge_candsRecommendation, unchanged and now evidenced
Keep open. Blocked on #154 primitive 1 (containment constraint), and on a new region fact on the extraction wire — a feature with a wire change in it, not a hole in #77. The schema half (
file_contributions.region_start/region_end, m0044's row language,deleting_one_contribution_takes_only_its_own_rows) remains ready and is genuinely not in the way.Sequencing: #154's primitive 1 first, because it is the one that decides whether region dispatch produces useful edges or a second pile of name-joined rows.
🤖 Packaged-language lane, 2026-09-06, master
4f866e5