You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#2032 added a transitive-reachability check to the dead-code classifier. To avoid over-promoting genuinely-dead methods to "root" status (a gap Greptile flagged during that PR's review), isInterfaceDispatchMethodRoot (src/graph/classifiers/roles.ts, mirrored as is_interface_dispatch_method_root in crates/codegraph-core/src/graph/classifiers/roles.rs) only treats a method-kind, fan-in-0, hasActiveFileSiblings-rescued method as an unconditional reachability root when its bare name matches an actual interface/type declaration member somewhere in the codebase (e.g. enterNode matching interface Visitor { enterNode?(...): ...; }).
This correctly narrows the false-positive class Greptile identified (an ordinary unused class method with no relation to any interface). But it also means a method-kind callback registered with a runtime event emitter (Node's Worker/EventEmitter.on('event', cb) pattern, not a TypeScript-declared interface) no longer qualifies as a root, since there's no local interface/type declaration for codegraph to match against.
Confirmed real instance (self-build)
WasmWorkerPool.onMessage in src/domain/wasm-worker-pool.ts:276 is a genuine, live method (presumably wired up via worker.on('message', ...) or similar) with fanIn === 0 — nothing in the graph resolves a call to it, since Node's built-in EventEmitter registration isn't a TypeScript interface member. Post-#2032, it is correctly still classified leaf itself (via the existing hasActiveFileSiblings rescue, untouched by the reachability downgrade), but it is no longer promoted to root status, so its own callees are wrongly flagged dead:
deserializeResult, deserializeCoreFields, deserializeBindingFields, deserializeMapFields (all in wasm-worker-pool.ts) — called only by onMessage, now dead-unresolved.
Checked: onMessage does not repeat across multiple files in this codebase (ruled out a "same name in ≥2 files" heuristic as an easy fix — it wouldn't help here, since this is a singular occurrence, structurally indistinguishable from a genuinely dead singular method by name-repetition alone).
Either fix needs the equivalent change in both src/graph/classifiers/roles.ts and crates/codegraph-core/src/graph/classifiers/roles.rs for dual-engine parity.
Summary
#2032 added a transitive-reachability check to the dead-code classifier. To avoid over-promoting genuinely-dead methods to "root" status (a gap Greptile flagged during that PR's review),
isInterfaceDispatchMethodRoot(src/graph/classifiers/roles.ts, mirrored asis_interface_dispatch_method_rootincrates/codegraph-core/src/graph/classifiers/roles.rs) only treats amethod-kind, fan-in-0, hasActiveFileSiblings-rescued method as an unconditional reachability root when its bare name matches an actualinterface/typedeclaration member somewhere in the codebase (e.g.enterNodematchinginterface Visitor { enterNode?(...): ...; }).This correctly narrows the false-positive class Greptile identified (an ordinary unused class method with no relation to any interface). But it also means a method-kind callback registered with a runtime event emitter (Node's
Worker/EventEmitter.on('event', cb)pattern, not a TypeScript-declared interface) no longer qualifies as a root, since there's no local interface/type declaration for codegraph to match against.Confirmed real instance (self-build)
WasmWorkerPool.onMessageinsrc/domain/wasm-worker-pool.ts:276is a genuine, live method (presumably wired up viaworker.on('message', ...)or similar) withfanIn === 0— nothing in the graph resolves a call to it, since Node's built-inEventEmitterregistration isn't a TypeScript interface member. Post-#2032, it is correctly still classifiedleafitself (via the existinghasActiveFileSiblingsrescue, untouched by the reachability downgrade), but it is no longer promoted to root status, so its own callees are wrongly flagged dead:deserializeResult,deserializeCoreFields,deserializeBindingFields,deserializeMapFields(all inwasm-worker-pool.ts) — called only byonMessage, nowdead-unresolved.Checked:
onMessagedoes not repeat across multiple files in this codebase (ruled out a "same name in ≥2 files" heuristic as an easy fix — it wouldn't help here, since this is a singular occurrence, structurally indistinguishable from a genuinely dead singular method by name-repetition alone).Suggested fix
One of:
.on('event', methodRef),EventEmittersubclass method binding, etc.) a realcalls-style edge from the registration call site to the bound method, the same way Dispatch-table function references (resolve: fn) inconsistently flagged dead-unresolved depending on unrelated fanOut #1771/roles --role dead: object-literal property-value references count as liveness without checking if the property is ever invoked (false negative) #1895 did for object-literal value-refs — the most precise fix, but real extraction work..on(,.addEventListener(,.once() even without a matching interface declaration — cheaper, but needs care to avoid reopening the exact "ordinary unused method" gap roles --role dead: non-transitive fan-in means a function called only by another dead function is never flagged dead #2032 just closed.Either fix needs the equivalent change in both
src/graph/classifiers/roles.tsandcrates/codegraph-core/src/graph/classifiers/roles.rsfor dual-engine parity.Related
isInterfaceDispatchMethodRoot's name-match requirement