Skip to content

follow-up: receiver-type-aware invoked-property matching to reduce dead-code false negatives #2088

Description

@carlos-alm

Deferred from PR #2034 review.

Original reviewer comment: inline comment — #2034 (comment)

Context:

collectInvokedPropertyNames (src/domain/graph/builder/call-resolver.ts, mirrored as collect_invoked_property_names in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs) adds a property name to its evidence set whenever ANY call in the processed files has a non-empty receiver and that name — with no check that the receiver is plausibly the same dispatch-table object referenced by the object-literal being evaluated. A completely unrelated logger.resolve() or promise.resolve() call anywhere in the codebase will add resolve to the set and prevent { resolve: neverCalled } from being flagged dead, even if the actual dispatch table is never read.

This is the conservative error direction (false negative for dead-code — it can never misclassify genuinely live code as dead), so it was accepted as-is for #2034: that PR's stated scope was "require any invocation evidence" as a deliberately coarse "one hop further" heuristic (see the doc comment on collectInvokedPropertyNames), not precise receiver-type correlation. Tightening it now would require:

  • Extending the existing points-to/type-map machinery to track each receiver call site's inferred type/binding.
  • Correlating that inferred type back to the specific object-literal (or dispatch-table variable) that defines the property being checked.
  • Implementing this identically in both the WASM/TS and native Rust engines, per this repo's dual-engine parity requirement.

That's a nontrivial dataflow precision improvement, not a small tweak, so it's being tracked separately rather than folded into #2034's narrower "any evidence at all" fix.

What the fix entails: teach collectInvokedPropertyNames/resolveFallbackTargets (and their Rust mirrors) to only count a x.name(...) call as evidence for a given object-literal's { name: fn } property when x's resolved type/binding plausibly refers to that same object (e.g. via the existing typeMap/points-to infrastructure), rather than matching on bare property name alone.

Activity

  1. added
    follow-upDeferred work from PR reviews that needs tracking
    on Jul 11, 2026
  2. carlos-alm commented on Aug 7, 2026

    @carlos-alm
    ContributorAuthor

    Investigated as part of a /fixer pass.

    Confirmed the issue's characterization is still accurate against current main (post-#2087): collectInvokedPropertyNames (src/domain/graph/builder/call-resolver.ts) and its Rust mirror collect_invoked_property_names (crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs) still add a property name to the evidence set whenever ANY call anywhere in scope has a non-empty receiver, with zero correlation between that receiver's inferred type and the specific object-literal/dispatch-table variable the property check is actually being evaluated against.

    Why this isn't implemented in this pass

    This is a genuine dataflow-precision feature, not a bug fix or plumbing change — and it's asymmetric with the other #2034-deferred follow-ups (#2086, #2087) in an important way: those were correctness bugs (the registry produced actively wrong — false-positive — call edges). This one is the opposite: the current behavior is conservative (a false negative for dead-code detection; it can never misclassify genuinely live code as dead), so nothing downstream is producing incorrect results today. It's a recall improvement to an advisory command (roles --role dead), not a soundness bug in the graph itself.

    Actually closing the gap requires real algorithm design, not a wiring fix:

    • Extending the points-to/type-map machinery to track, per call site, which object-literal/dispatch-table instance a receiver plausibly refers to (not just its nominal class/type name — a bare { resolve: fn } returned from a factory has no name to match against, so this needs value-identity tracking through the existing points-to solver, or a new mechanism).
    • Correlating that instance-level binding back to the specific literal declaring the property under test.
    • The usual dual-engine parity burden: identical semantics in both the WASM/TS points-to solver and the native Rust one, each independently verified.

    I looked for a narrower, bounded partial fix (e.g. an exclusion list for common non-dispatch-table receiver names like promise/logger) and decided against it — that trades one unprincipled heuristic for another (a hardcoded name list needing perpetual tuning, exactly the kind of ad-hoc special-casing this repo's conventions steer away from) without actually implementing the receiver-type correlation the issue asks for.

    No change made. Leaving open — the fix direction in the issue body remains accurate and actionable for whoever picks this up with room to design the points-to extension properly.

  3. added
    blockedCannot be worked right now (excluded from /fixer's queue)
    on Aug 7, 2026
  4. carlos-alm commented on Aug 7, 2026

    @carlos-alm
    ContributorAuthor

    Applying the blocked label so this issue stops consuming a /fixer batch slot on every future pass while it remains what it was diagnosed as above: a genuine points-to/dataflow algorithm-design project, not a bounded bug fix or plumbing change. Remove the label whenever someone is ready to design the receiver-instance correlation extension described above.

  5. removed
    blockedCannot be worked right now (excluded from /fixer's queue)
    on Aug 23, 2026
  6. carlos-alm commented on Aug 24, 2026

    @carlos-alm
    ContributorAuthor

    claiming issue-2088 (plan, via /oversee) — docs/plan-issue-2088

  7. self-assigned this
    on Sep 3, 2026
  8. carlos-alm commented on Sep 3, 2026

    @carlos-alm
    ContributorAuthor

    claiming issue-2088 (execute, via /oversee — approved plan #2612) — feat/2088-correlated-invoked-property-evidence

  9. carlos-alm commented on Sep 3, 2026

    @carlos-alm
    ContributorAuthor

    execute PR opened: #2654 (feat/2088-correlated-invoked-property-evidence). Not merging — human merge only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

follow-upDeferred work from PR reviews that needs tracking

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions