Skip to content

[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

@carlos-alm

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 (pathDefinitionHandler in source/commons/handlers/comp.task-definition.apigw.lambda.handler.js) and its entry file source/adapters/inbound/aws-lambda/task/task_definition/index.js calls pathDefinitionHandler.apiGatewayLambdaHandler(event, context) statically, yet on 3.17.0 fn-impact ComposerPathDefinitionHandler.apiGatewayLambdaHandler -T says "No callers found", context handler -f task_definition/index.js -T says "no call edges ... may be invoked dynamically", and flow handler -f task_definition -T reaches 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-class this.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 -T

Minimal 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.run has caller entry-a.js:handler and B.run has caller entry-b.js:handler. In the repo, fn-impact ExecAggregationHandler.apiGatewayLambdaHandler lists source/adapters/inbound/aws-lambda/task/aggregation/index.js:handler and nothing under it is dead.
  • strip is a used symbol because it is referenced as a callback argument.
  • exports ... -T attributes QUERY_MAX_CODE_POINTS to exec.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 (every export const handler under source/adapters/inbound/aws-lambda/*/index.js is dead-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 under source/commons/handlers/, imported by 9 files under source/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

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdogfoodFound during dogfooding

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions