Frameworks do not generalise: claims are basename-only, and bridges have no containment constraint, no project-wide scope and no type-driven join #154
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#154
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?
Found by a third-party-pluggability review. The owner's question was "are we on the way to a pluggable system for multiple languages and frameworks?" — languages: yes. Frameworks: two structural walls, both independent of the ABI.
Wall 1 — a framework is not a language, and the host language is taken
Rails support lives inside the Ruby extractor. Django, Spring and Angular all sit on languages a builtin owns, so
.py,.ts,.csare unavailable to a package. A third party cannot ship Django or Angular-component awareness at all today.What they can ship is the framework's own unclaimed file type —
.xaml,.vue,.erb,.htmltemplates — bridged into the host language. That is exactly the XAML shape, and it is currently the only shape that fits. (#87's operator-consented override changes the arithmetic here; this issue is about what remains after it.)Wall 2 — claims are basename-only
crates/package/src/claim.rssupportsExt,Name,Suffix— no directory component, and it notes that a fourth key kind "is a decision, not a convenience". Soapp/models/,*/migrations/*.py,src/main/java/**are inexpressible.Framework conventions are overwhelmingly directory-shaped. This is the single most load-bearing gap for the framework story. See also #135 (
claim::Keyhas no bounded path globs, and thebounded_glob_claimfixture tests no glob).What the two existing mechanisms actually do
derived_namesis genuinely fail-closed and the design is right. The guest computes the string, nothing verifies it, and an ungranted derived ref refuses the whole file withfact.span_name_mismatch— withwithheld_grant_witnessre-validating with the grant to distinguish "missing grant" from "buggy span". But it is one permission bit, not a capability system:camelize/singularizelive in the guest, there is no host transform registry, andTier::Declarativeis retired specifically so there is no rule surface. New inflection means new wasm.Bridges are a name-join with three fixed scopes (
same_file,paired_file,same_directory), three name maps, andambiguitywith exactly one member. The candidate side is the whole project's symbols of one kind with no containment constraint at all — in the shipped XAML e2e,Click="OnSaveClick"binds any C# method of that name in the paired file, not a member of the classx:Classnames. AndMAX_BRIDGES = 16against 3×6 = 18 possible pairs, so one language pair cannot be fully covered.Mapped concretely
ForeignKey('app.Model')Model— i.e. the normal repourls.pyimplement/inheritref kinds are declared but emitted by no plugin{Binding …}emit as un-bridgeablemember_accessThe three missing primitives, in blast-radius order
Plus a directory component on claims (wall 2), which is arguably prerequisite to all three.
Related
🤖 Generated with Claude Code
https://claude.ai/code/session_01K1zj5VcFJvJt3pQxe9259K
EMBEDDED_DISPATCH_SEMANTICS_VERSION = 0, so no file can carry two producers and #77's criterion 2 is unexercisable #119claim::Keyhas no bounded path globs, and a fixture row namedbounded_glob_claimtests no glob #135EMBEDDED_DISPATCH_SEMANTICS_VERSION = 0, so no file can carry two producers and #77's criterion 2 is unexercisable #119Both walls verified from the code, one of the three primitives is now measured rather than asserted, and a FOURTH instance of wall 2 landed this week. Not attempted in this lane, with the reason stated.
The packaged-language lane held this today alongside #86, #119 and #124. It was not built — see the last section for why, in numbers — but every claim in the body was checked against master
4f866e5rather than taken forward, and two of them can now be cited to a line.Wall 2 — claims are basename-only: CONFIRMED, exactly as filed
crates/package/src/claim.rs:99-106. The enum is three variants and none of them sees a directory:matchestakesbaseand nothing else. Soapp/models/,*/migrations/*.pyandsrc/main/java/**are inexpressible, and the body's reading is right: framework conventions are overwhelmingly directory-shaped, so this is the most load-bearing gap for the framework story. See also #135.Wall 2 has a FOURTH instance, and it is a HOST gate, not a manifest one
Worth adding to this issue because it is the same family arriving from a different direction — and because it is the first one that cost a suite.
manifest_package_dirs(crates/indexer/src/index.rs:1801) discovers package boundaries by BASENAME:That is blind to any packaged language whose files a package claims under a different extension — the same shape as #112's three language-id-keyed allowlists, and as this issue's wall 2. It surfaced as #167, where it made
ruby_package_parity's two legs run the origin gate against different data (17 unexplained ref deltas, in both directions).The product fix was implemented TWICE and refused on measurement, which is the part worth carrying here:
package_root_of(parent dir)And neither is measurable on the pinned corpus — all nine repos carry discoverable manifests, so the fallback never fires and the bind digest is byte-identical under both. #167 was closed with a harness fix and
nearest_package_dirleft carrying a doc that records both refutations.The lesson for this issue: a directory component on claims is not only a manifest-vocabulary addition. The host already has directory-shaped reasoning, it is basename-keyed in at least one place, and there is no ground truth for the manifest-less case. Whoever takes primitive 4 should read #167's thread first; that is the same decision arriving early.
Primitive 1 — the containment constraint: CONFIRMED, and it is one SQL statement
This is the one the body states in prose and #119 now depends on. It is exact.
fill_bridge_cands(crates/indexer/src/index.rs:2826-2867):Every symbol in the project of one language and one kind. The scopes narrow it afterwards through
dirandpair_keycolumns — and all three ofsame_file,paired_file,same_directoryare FILE-shaped. There is no column, and no join, that could express "a member of the class this file names".So the body's XAML observation is structural rather than incidental:
Click="OnSaveClick"binds any C# method of that name in the paired file, because the relation has no way to know which classx:Classnamed.MAX_BRIDGES = 16against 3×6 = 18 possible pairs also holds (crates/package/src/limits.rs:215), as doesBRIDGE_AMBIGUITY = &["unique"]— one member (crates/package/src/bridge.rs:148).derived_names— the body's assessment holds, and it now has a shipped precedent"Genuinely fail-closed and the design is right… but one permission bit, not a capability system" is accurate. Worth noting for whoever builds the transform registry: #103 shipped the full pattern — a requested, granted, fail-closed authority with a
withheld_grant_witnessthat re-validates with the grant to distinguish "missing grant" from "buggy span", folded into the activation digest. #86's remaining gap 4 (qualifier TEXT) is queued to copy the same shape. A transform registry would be the third instance, so the mechanism is no longer speculative — only the vocabulary is.Why this lane did not build any of it
Stated so the refusal is inspectable rather than just cautious.
BridgeDeclfield, an activation-digest bit, a rebuilttests/packages/xaml(wasm bytes,WASM_ARTIFACTSsha,.digest,plugin.tomlversion, recorded expectations) and a re-blessed cost band. That is a full coupled landing, not a clause.claim.rssays a fourth key kind "is a decision, not a convenience", and #167 has just demonstrated what happens when directory-shaped reasoning is changed without ground truth: two implementations, seven red fixtures between them, and no corpus repo that can tell them apart. #135 holds that decision.Recommended sequencing, from what was measured
One correction to the body's related list: #112 is closed (one
lang_profilemechanism, not three exceptions), and #167 is closed (harness fix; the product finding stands and is recorded in-tree).🤖 Packaged-language lane, 2026-09-06, master
4f866e5