Skip to content

L3/L4 populate 0.7% of callables on multi-program repos — dataflow uses one root tsconfig #111

Description

@rahlk

Problem

src/core.ts warns that the L3 dataflow stage uses the root tsconfig for every program, calling it
"nested-program files may under-resolve (see #56)". Measured on vscode, the effect is far larger
than under-resolution: levels 3 and 4 populate almost nothing.

-a 4 --graphs cfg,dfg,pdg,sdg on microsoft/vscode (18,391 files, 9,351 modules, 174,767
callables), analyzer v1.1.0, exit 0 in 12m22s / 24.7 GB:

callables with cfg 1,204 of 174,767 (0.7%)
callables with cdg / ddg / summary 1,200 / 1,191 / 830
modules with any cfg 44 of 9,351
param_in / param_out 2,683 / 1,164
statement body nodes 5,438 (against 538,601 call nodes)

The 44 modules that do get flow are all top-level scripts outside src/ (.github/skills/...,
scripts/chat-simulation/...). vscode has no root tsconfig.json — its TypeScript lives under
src/tsconfig.json — so the single root program the dataflow workers build covers essentially none
of the repository.

The L4 output is only ~5 MB larger than the L2 output (1,030 MB vs 1,026 MB), which is the tell:
the run succeeds and produces nearly no flow.

Scope boundary

The level-2 call graph is already fully per-program and is NOT affected — 1,149,984 edges on the
same run. Levels 1 and 2 are correct. Single-root-tsconfig repositories are unaffected: the same
binary on a repo with a root tsconfig populates cfg for a majority of its callables.

This is pre-existing and shipped in v1.1.0; it is not a regression from the checker-guard or
allowJs fixes in #103.

Cause

src/core.ts passes mat.tsConfigFilePath (one root config) to startExtraction, and
src/dataflow/worker.ts builds its Project from that single config. Each BuiltProgram already
carries its owning configPath — the file-to-program map exists at the call site — but it is not
threaded into the workers. The code comment at src/core.ts documents this as deferred.

Goals

  • Thread each file's owning program config into the dataflow workers, as buildSymbolTable
    already does for the symbol table and the call graph
  • Make the shortfall observable: report how many callables received flow versus how many were
    collected, so a near-empty L3 cannot pass as success
  • Regression fixture: a multi-program project with no root tsconfig, asserting flow lands for
    callables in the nested program

Caveats and known risks

  • The current warning understates the failure ("may under-resolve" vs 0.7% populated) and fires
    only when programs.length > 1; a repo with no root tsconfig and one nested program is silent.
  • Fixing this will substantially increase L3/L4 cost on large repos — the vscode run is fast today
    precisely because it does almost no work.
  • Worker memory is the reason to be careful: each worker builds its own Project, so per-program
    projects may need pooling rather than one project per worker per program.

Definition of done

-a 4 on a multi-program repository populates cfg/cdg/ddg for the large majority of collected
callables, verified by re-running the vscode measurement above — not by fixture tests alone.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions