resolution_by_kind is distorted by construction: receiver heads emitted as type, member_access 100% circular, local rows in denominators #549

Closed
opened 2026-11-09 08:35:50 +01:00 by buildagent · 2 comments
Member

Consolidated scope (triage 2026-11-09)

Priority: Medium: the per-kind numbers point at the wrong gaps.

This issue is now the canonical tracker for:

  • the written verdict on composition vs plugin gap; satisfied by the before/after per-language tables here (from #46, closed and merged here; its full report stays readable there)
  • a gap miner (shape aggregation and WONTFIX register) to build AFTER this issue, or it ranks the receiver-head artifacts first (from #47, closed and merged here; its full report stays readable there)

Original report

Summary

project_overview.resolution_by_kind and resolution_gaps are what agents and operators use to judge where the index is weak. In several languages those percentages are distorted by construction, so they point at gaps that do not exist and hide the ones that do.

Distortion Evidence
The head of every receiver chain is emitted as a type ref (ctx in ctx.x, locals, module names) Python emit_receiver_type_refs_d (python.rs ~1726), TS typescript.rs:2027-2045. In zod, z alone accounts for 7,418 type rows, about a third of all of them, and dominates top_unresolved. flask's unqualified type is 4,626 refs at 5.7%. JS type is 3,429 at 0%. C# emits namespace segments (System, Data, about 200) and local receivers as type.
member_access 100% is circular Ruby and JS guests never emit that kind; the host relabels a ref as member_access only after it resolved (comment at crates/guest/ruby/src/ruby.rs:2349). So the row is 100% by construction, and Ruby's type % is understated by 760 successes.
Local-scope rows pollute symbols and name fallback js-express: 1,775 of 1,917 symbols are static, and 1,392 are declared local. top_referenced_symbols is all require aliases. get_symbol View lists 5 test-local functions as candidates. find_references(res) returns 950 rows of handler parameters, none resolved, even though the walker marks them LOCAL (parity-deltas.toml scope-verdict).
Std/vendor denominators django's qualified calls resolve 0.3%, and the top unresolved names are all stdlib. That is a denominator artifact the payload does not separate out.

Proposal

  • Emit a receiver head as read (or a dedicated receiver role) until it is proven to be a type. C# namespace segments become import-like and leave the denominator.
  • Report member_access under the kind it was emitted as, with the relabel shown as an outcome, not a kind.
  • Refs carrying the LOCAL scope verdict are excluded from name fallback and from resolution denominators. visibility: local symbols are hidden by default from file_outline, search_symbols, top_referenced_symbols and ambiguity candidate lists, behind an opt-in flag.
  • Resolution figures split in-project candidates from external/std names, as internal_resolution_pct already partly does, per kind.

Acceptance

  • Per-language before/after tables of resolution_by_kind, with a written explanation of every move.
  • The corpus baseline moves only in the measured denominators, never in binds.
  • A registry test asserts that no guest emits a receiver head as type without the type-position role.

Related: #46 (honest internal-resolution spread), #522.


Filed from the per-language review on 2026-11-09: 8 agents, one per language plus one for Vue/Svelte/XAML/timeline, run against copies of the pinned corpus repos (tests/corpus/corpus.toml) using installed build 2dcfc615, which differs from master only by XAML/CI commits. The top claim of every issue was spot-checked in the main session. Artifacts live under the review session's scratchpad lang-out/<lang>/ and are available on request.

## Consolidated scope (triage 2026-11-09) **Priority: Medium**: the per-kind numbers point at the wrong gaps. This issue is now the canonical tracker for: - [ ] the written verdict on composition vs plugin gap; satisfied by the before/after per-language tables here (from #46, closed and merged here; its full report stays readable there) - [ ] a gap miner (shape aggregation and WONTFIX register) to build AFTER this issue, or it ranks the receiver-head artifacts first (from #47, closed and merged here; its full report stays readable there) --- ## Original report ## Summary `project_overview.resolution_by_kind` and `resolution_gaps` are what agents and operators use to judge where the index is weak. In several languages those percentages are **distorted by construction**, so they point at gaps that do not exist and hide the ones that do. | Distortion | Evidence | |---|---| | **The head of every receiver chain is emitted as a `type` ref** (`ctx` in `ctx.x`, locals, module names) | Python `emit_receiver_type_refs_d` (`python.rs` ~1726), TS `typescript.rs:2027-2045`. In zod, `z` alone accounts for **7,418** `type` rows, about a third of all of them, and dominates `top_unresolved`. flask's unqualified `type` is 4,626 refs at 5.7%. JS `type` is 3,429 at 0%. C# emits namespace segments (`System`, `Data`, about 200) and local receivers as `type`. | | **`member_access` 100% is circular** | Ruby and JS guests never emit that kind; the host relabels a ref as `member_access` only *after* it resolved (comment at `crates/guest/ruby/src/ruby.rs:2349`). So the row is 100% by construction, and Ruby's `type` % is understated by 760 successes. | | **Local-scope rows pollute symbols and name fallback** | js-express: 1,775 of 1,917 symbols are `static`, and 1,392 are declared local. `top_referenced_symbols` is all `require` aliases. `get_symbol View` lists 5 test-local functions as candidates. `find_references(res)` returns 950 rows of handler parameters, none resolved, even though the walker marks them LOCAL (`parity-deltas.toml` `scope-verdict`). | | **Std/vendor denominators** | django's qualified calls resolve 0.3%, and the top unresolved names are all stdlib. That is a denominator artifact the payload does not separate out. | ## Proposal - Emit a receiver head as `read` (or a dedicated `receiver` role) until it is proven to be a type. C# namespace segments become `import`-like and leave the denominator. - Report `member_access` under the kind it was **emitted** as, with the relabel shown as an outcome, not a kind. - Refs carrying the LOCAL scope verdict are excluded from name fallback and from resolution denominators. `visibility: local` symbols are hidden by default from `file_outline`, `search_symbols`, `top_referenced_symbols` and ambiguity candidate lists, behind an opt-in flag. - Resolution figures split **in-project candidates** from **external/std names**, as `internal_resolution_pct` already partly does, per kind. ## Acceptance - Per-language before/after tables of `resolution_by_kind`, with a written explanation of every move. - The corpus baseline moves only in the measured denominators, never in binds. - A registry test asserts that no guest emits a receiver head as `type` without the type-position role. Related: #46 (honest internal-resolution spread), #522. --- _Filed from the per-language review on 2026-11-09: 8 agents, one per language plus one for Vue/Svelte/XAML/timeline, run against copies of the pinned corpus repos (`tests/corpus/corpus.toml`) using installed build `2dcfc615`, which differs from master only by XAML/CI commits. The top claim of every issue was spot-checked in the main session. Artifacts live under the review session's scratchpad `lang-out/<lang>/` and are available on request._
Author
Member

Dogfood triage 2026-11-09: a function path used as a VALUE is labelled member_access

find_references("crates/test-support/src/frozen.rs:123") (fn frozen::dir) returns crates/daemon/tests/precision_gate.rs:297 and crates/test-support/src/shipped.rs:86 as resolved refs of kind member_access. Both are crate::frozen::dir passed as a function value (install(..., crate::frozen::dir)). That is not a member access, and it adds to the "member_access 100% circular" distortion this issue tracks. It should be a value use (read, or a dedicated value kind). It matters for the false "earned zero" family too (#535): a value use is the only evidence that such a fn is live. The find_callers disclosure part is in #521.

## Dogfood triage 2026-11-09: a function path used as a VALUE is labelled `member_access` `find_references("crates/test-support/src/frozen.rs:123")` (fn `frozen::dir`) returns `crates/daemon/tests/precision_gate.rs:297` and `crates/test-support/src/shipped.rs:86` as resolved refs of kind **`member_access`**. Both are `crate::frozen::dir` passed as a function value (`install(..., crate::frozen::dir)`). That is not a member access, and it adds to the "member_access 100% circular" distortion this issue tracks. It should be a value use (`read`, or a dedicated value kind). It matters for the false "earned zero" family too (#535): a value use is the only evidence that such a fn is live. The `find_callers` disclosure part is in #521.
Author
Member

Merged into #536.
No denominator-only migration is verified; Python emit_receiver_type_refs_d still emits receiver heads as type refs.
Remaining: Resolution populations, including the tables, invariant gate and later gap miner.

Merged into #536. No denominator-only migration is verified; Python emit_receiver_type_refs_d still emits receiver heads as type refs. Remaining: Resolution populations, including the tables, invariant gate and later gap miner.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
h-dv/code-index#549
No description provided.