fix: exclude parameters and interface/type members from dead-role classification#1811
Conversation
…ssification codegraph roles --role dead flagged every function parameter as dead-leaf and every interface/type member as dead-unresolved, regardless of actual usage. Root cause: the role classifier's fan-in-based "no callers = dead" heuristic is meaningless for these two symbol categories, since neither can ever have inbound call edges by construction: - Parameters: `kind = 'parameter'` nodes were unconditionally force-assigned dead-leaf via a fast-path bypass in classifyNodeRolesFull/Incremental (TS) and do_classify_full/do_classify_incremental (native), before any fan-in was even computed. A parameter's liveness is a local dataflow question (is it referenced within its own function body), not a call-graph reachability question, so this produced ~90% noise in --role dead output. - Interface/type members: every language extractor qualifies interface/type members as `Owner.member` top-level definitions (mirroring class method qualification), and they never receive inbound call edges (they're consumed via type annotations, not calls). Lacking any recognition of this, they fell through the normal fan-in/fan-out path and landed in dead-unresolved. Fix: - Parameters are now fully excluded from role classification (role stays NULL), the same treatment already given to file/directory nodes. - Interface/type members are now recognized in the classifier by resolving the Owner.member prefix against same-file TYPE_DEF_KINDS declarations (interface/type/struct/enum/trait/record) and classified `leaf` unconditionally. Class methods use the identical Owner.member naming convention but are unaffected since `class` is not in TYPE_DEF_KINDS, so real dead methods/functions remain detected. Applied to both the TS/WASM classifier (graph/classifiers/roles.ts, features/structure.ts) and the native Rust classifier (graph/classifiers/roles.rs) per the dual-engine parity requirement; verified both engines produce identical results end-to-end against this repo's own graph. Fixes #1723 Impact: 6 functions changed, 5 affected
Greptile SummaryThis PR fixes two false-positive dead-code classification bugs (#1723): function parameters were unconditionally assigned
Confidence Score: 4/5The fix is correct and well-tested for the practical cases; only minor consistency gaps remain between the pure-function and SQL-backed paths. The core logic is sound: parameters are excluded from all queries and receive no role, and interface/type members are correctly short-circuited to leaf via the new isTypeDeclarationMember helper in both TS and Rust. Two minor inconsistencies remain: LEAF_KINDS still includes parameter in both roles.ts and roles.rs, and the SQL leaf path unconditionally marks all property-kind nodes as dead-leaf before isTypeDeclarationMember can inspect them. src/graph/classifiers/roles.ts and crates/codegraph-core/src/graph/classifiers/roles.rs (stale LEAF_KINDS); src/features/structure.ts has the latent pure-vs-SQL divergence for property-kind type members. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Node from DB] --> B{kind?}
B -->|parameter| C[Excluded from all queries\nrole = NULL]
B -->|property| D[Leaf SQL query\ndead-leaf]
B -->|file / directory| E[Excluded from all queries\nrole = NULL]
B -->|method / function / class / etc.| F[Main rows query]
F --> G{isTypeDeclarationMember?\nOwner in TYPE_DEF_KINDS\nsame file}
G -->|yes| H[leaf]
G -->|no| I{fanIn == 0 &&\nnot exported?}
I -->|yes| J[classifyDeadSubRole\ndead-leaf / dead-ffi / dead-entry / dead-unresolved]
I -->|no| K{fanIn > 0?}
K -->|yes| L[core / utility / adapter / leaf\nbased on fan shape]
K -->|no, exported| M[entry]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Node from DB] --> B{kind?}
B -->|parameter| C[Excluded from all queries\nrole = NULL]
B -->|property| D[Leaf SQL query\ndead-leaf]
B -->|file / directory| E[Excluded from all queries\nrole = NULL]
B -->|method / function / class / etc.| F[Main rows query]
F --> G{isTypeDeclarationMember?\nOwner in TYPE_DEF_KINDS\nsame file}
G -->|yes| H[leaf]
G -->|no| I{fanIn == 0 &&\nnot exported?}
I -->|yes| J[classifyDeadSubRole\ndead-leaf / dead-ffi / dead-entry / dead-unresolved]
I -->|no| K{fanIn > 0?}
K -->|yes| L[core / utility / adapter / leaf\nbased on fan shape]
K -->|no, exported| M[entry]
|
Codegraph Impact Analysis6 functions changed → 5 callers affected across 2 files
|
Summary
codegraph roles --role deadforce-assigneddead-leafto every function parameter unconditionally (via aWHERE kind IN ('parameter', 'property')bypass), regardless of whether the parameter was used.Owner.memberdeclarations with no call edges by construction) fell through todead-unresolvedwith no way to distinguish them from a genuinely dead class method.src/graph/classifiers/roles.ts,src/features/structure.ts) and the mirrored native Rust classifier (crates/codegraph-core/src/graph/classifiers/roles.rs) so parameters get no dead-role at all and interface/type members classify asleaf.Closes #1723
Test plan
npm test— full suite green (3356 passed, 0 failed)npm run lint— cleanroles --role dead --file src/extractors/helpers.ts -T --jsonnow returns 0 false positives (was 56).nodebinary: identical results, 0 dead-role false positives for parameters/interface members across 18.9k nodes; 64 genuinely dead functions still correctly flaggedNote: this PR is stacked on #1808 (base branch
fix/issue-1721-batch-complexity-file-target) — only the roles.ts/structure.ts/roles.rs/test diff is this issue's actual change.