Repository navigation
[Bug]: 3.17.0: member calls on imported object/instance bindings (named or default export) never produce call edges; callback references not counted as uses #2663
Description
Correction after a second pass (3.17.0): finding (1) is not a name-collision problem. The composer handler exports a globally unique instance name (
pathDefinitionHandlerinsource/commons/handlers/comp.task-definition.apigw.lambda.handler.js) and its entry filesource/adapters/inbound/aws-lambda/task/task_definition/index.jscallspathDefinitionHandler.apiGatewayLambdaHandler(event, context)statically, yet on 3.17.0fn-impact ComposerPathDefinitionHandler.apiGatewayLambdaHandler -Tsays "No callers found",context handler -f task_definition/index.js -Tsays "no call edges ... may be invoked dynamically", andflow handler -f task_definition -Treaches 0 nodes. Default-exported singletons show the same miss (callCohere.rerank(...),callOpenAI.completion(...), see the comment below). The defect is that a member call on any imported object or instance binding, named or default export, never produces a call edge, while intra-classthis.method()and plain imported-function calls do resolve. Everything below is kept as originally written.
Description
Two JavaScript resolution gaps on the latest release 3.17.0, found while validating a change in optave/core-orchestrator-svc with five agents that had to grep-verify every dead / "No callers found" claim.
1. A cross-file call through an imported class instance has no callers when the exported instance name is shared by several modules. Ten handler modules in the repo each end with const oCoLambdaHandler = new <SomeHandler>(); export { oCoLambdaHandler }; and nine Lambda entry files do import { oCoLambdaHandler } from '<that module>'; ... oCoLambdaHandler.apiGatewayLambdaHandler(event, context). On 3.17.0 the entry method of the aggregation handler has zero callers, so every method under it is flagged dead. Intra-class this.method() calls do resolve on 3.17.0 (aggregationFlow correctly lists apiGatewayLambdaHandler as its caller), so the break is specifically the cross-file call through the imported instance. A handler whose exported instance has a unique name (pathDefinitionHandler in comp.task-definition.apigw.lambda.handler.js) resolves its apiGatewayLambdaHandler -> definePath -> defineAssistantPath chain, which points at the receiver binding picking the wrong class when the same export name exists in multiple files.
2. Functions passed by reference (array.map(fn)) are not counted as uses. strip in the aggregation handler is only used as publishedItems.map(strip) and proseItems.map(strip); it is reported dead.
Minor, same family as (1): exports <file> -T reports the constant export QUERY_MAX_CODE_POINTS from source/adapters/outbound/controllers/dataplane.controller.js as (no consumers) although source/commons/handlers/exec.retriever.apigw.lambda.handler.js:325 imports and uses it; function and class exports in the same file are attributed correctly. (QUERY_WIRE in the same output is correctly reported as unused outside tests.)
Steps to Reproduce
On optave/core-orchestrator-svc at commit ca32aee92 (branch claude/opus-sonnet-orchestration-94be94):
npx -y @optave/codegraph@3.17.0 build --no-incremental
npx -y @optave/codegraph@3.17.0 fn-impact ExecAggregationHandler.apiGatewayLambdaHandler -T
npx -y @optave/codegraph@3.17.0 fn-impact ExecAggregationHandler.aggregationFlow -T # shows the intra-class caller, so this.* works
npx -y @optave/codegraph@3.17.0 fn-impact ComposerPathDefinitionHandler.definePath -T # control: unique export name resolves
npx -y @optave/codegraph@3.17.0 roles --role dead -T | grep exec.aggregation
npx -y @optave/codegraph@3.17.0 exports source/adapters/outbound/controllers/dataplane.controller.js -TMinimal shape for (1):
// a.js
class A { run() { return this.step(); } step() {} }
const oCoLambdaHandler = new A(); export { oCoLambdaHandler };
// b.js
class B { run() { return this.step(); } step() {} }
const oCoLambdaHandler = new B(); export { oCoLambdaHandler };
// entry-a.js
import { oCoLambdaHandler } from './a.js'; export const handler = () => oCoLambdaHandler.run();
// entry-b.js
import { oCoLambdaHandler } from './b.js'; export const handler = () => oCoLambdaHandler.run();Minimal shape for (2):
function strip(x) { return x.id; }
export const ids = (items) => items.map(strip);Expected Behavior
A.runhas callerentry-a.js:handlerandB.runhas callerentry-b.js:handler. In the repo,fn-impact ExecAggregationHandler.apiGatewayLambdaHandlerlistssource/adapters/inbound/aws-lambda/task/aggregation/index.js:handlerand nothing under it isdead.stripis a used symbol because it is referenced as a callback argument.exports ... -TattributesQUERY_MAX_CODE_POINTStoexec.retriever.apigw.lambda.handler.js.
Actual Behavior
Function impact: o ExecAggregationHandler.apiGatewayLambdaHandler -- source/commons/handlers/exec.aggregation.apigw.lambda.handler.js:132
No callers found.
Total: 0 functions transitively depend on ExecAggregationHandler.apiGatewayLambdaHandler
Function impact: o ExecAggregationHandler.aggregationFlow -- .../exec.aggregation.apigw.lambda.handler.js:156
-- Level 1 (1 functions):
^ o ExecAggregationHandler.apiGatewayLambdaHandler .../exec.aggregation.apigw.lambda.handler.js:132
roles --role dead -T | grep exec.aggregation -> 10 symbols:
eventElements:74, readStructuredResult:94, aggregationFlow:156, strip:215, loadPolicy:296,
toSourceItem:344, buildFacts:386, buildStructuredParts:436, publishSources:510, buildOutput:545
exports dataplane.controller.js -T
C QUERY_MAX_CODE_POINTS [leaf] :52 (no consumers) <- used at exec.retriever.apigw.lambda.handler.js:325
C QUERY_WIRE [leaf] :62 (no consumers) <- correct, tests only
f normalizeRetrieveResponse ... <- DataPlaneController.retrieve (correct)
* DataPlaneController ... <- ExecRetrievalHandler.runKnowledgeSearch, .runStructuredQuery (correct)
stats: Files 402; Graph Quality 88/100; caller coverage 72.4%; call confidence 97.8%; entry 60; dead 418
The call sites codegraph misses: source/adapters/inbound/aws-lambda/task/aggregation/index.js:19 (oCoLambdaHandler.apiGatewayLambdaHandler(event, context), imported at line 11) and exec.aggregation.apigw.lambda.handler.js:216 / :223 (.map(strip)).
Codegraph Version
3.17.0 (npx -y @optave/codegraph@3.17.0)
Node.js Version
v22.18.0
Operating System
Windows 11 Pro 10.0.26200 (x64), Git Bash shell
Parser Engine
native (Active engine : native (v3.17.0))
Additional Context
- Already fixed in 3.17.0, listed so nobody re-reports it: the locally installed 3.9.4-dev.8 does not resolve any
this.method()/new ClassName()call at all (everyexport const handlerundersource/adapters/inbound/aws-lambda/*/index.jsisdead-unresolved, entries 18 instead of 60, dead 2,245 native / 3,527 wasm, quality 76/100, caller coverage 47%). Upgrading resolves that; the two findings above remain. - The Lambda entry and handler modules follow one uniform pattern (
const oCoLambdaHandler = new XHandler(); export { oCoLambdaHandler };in 10 files undersource/commons/handlers/, imported by 9 files undersource/adapters/inbound/aws-lambda/), so a fixture with two same-named exported instances should cover (1). - Commands that stayed accurate throughout the validation pass on both versions:
complexity,deps,impact,diff-impact,branch-compare,cycles,path/query. - The Terraform symbol-extraction regression from the same pass is filed separately.
Activity
carlos-alm commentedon Sep 8, 2026
Follow-up from a second validation pass on 3.17.0, which narrows the root cause of finding (1):
The defect is calls through a default-exported singleton in general, not only same-named exports. Two uniquely named, single-consumer default exports show the same miss:
source/commons/services/cohere.execution.services.jsexportscallCohere(default);source/commons/handlers/exec.retriever.apigw.lambda.handler.js:206callscallCohere.rerank(...).fn-impact rerank -Tlists only the module-internalcallCoherealias as a dependent and neverExecRetrievalHandler.runKnowledgeSearch;flow retrievalFlownever reachesrerank.source/commons/services/openai.execution.services.jsexportscallOpenAI(default); the same handler callscallOpenAI.embedding(...)at:589andcallOpenAI.completion(...)at:759. Neither is reached byflow retrievalFlow.Intra-class
this.method()calls in the same file do resolve on 3.17.0, and file-levelimpact source/commons/services/cohere.execution.services.js -Tcorrectly lists the 5 dependent files, so the import edge exists; it is the member-call edge fromimportedDefault.method()to the method that is not created. The same-namedoCoLambdaHandlercase in the original report is one instance of this.Exported constants:
exports <file> -Talso reportsQUERY_WIREas(no consumers); it is used within its own file atdataplane.controller.js:129,132,205,498,499,526,531,543. Together withQUERY_MAX_CODE_POINTS(imported and used atexec.retriever.apigw.lambda.handler.js:15and:325), exported-constant consumers appear not to be tracked at all, only function and class exports.Minimal shape for the default-export case:
[-][Bug]: 3.17.0: cross-file call through a same-named exported instance has no callers; callback references not counted as uses[/-][+][Bug]: 3.17.0: member calls on imported object/instance bindings (named or default export) never produce call edges; callback references not counted as uses[/+]carlos-alm commentedon Sep 8, 2026
Diagnostic hint from the repository-level pass on 3.17.0:
audit --quick source/commons/handlers/comp.task-definition.apigw.lambda.handler.jsdoes list theindex.js -> pathDefinitionHandler.apiGatewayLambdaHandler(...)call in its Data Flow section, so the edge is extracted at some layer; it is the caller/role classification (fn-impact,context,flow,roles --role entry|dead) that does not consume it. That suggests the fix is in how member calls on imported bindings are attached to the callee symbol rather than in parsing. Net effect on this repo: 36 of the 59 true entrypoints classified asentry, and 26 handler-class methods across four handlers reported dead although every one is reached from a Lambda entry.