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
The -j N vs -j 1 byte-identical determinism gate — the one src/dataflow/index.ts:92-95 names as the correctness guarantee for the worker path —
"correctness is guarded either way by the byte-identical N-vs-1 gate"
does not hold on a multi-tsconfig project, and the default (sequential) path is the losing side.
The two paths build their ts-morph Project from different file sets:
Sequential (extractSequential, src/dataflow/index.ts:156-170) reuses the main-thread project, which is the tsconfig-scoped program.
Workers (projectFor, src/dataflow/worker.ts:53-62) construct with skipAddingFilesFromTsConfig: true and then add everything discoverSourceFiles(root) finds — whole-repository discovery, which is what the symbol-table build also uses.
So the worker path's file set matches the symbol table and the sequential one does not. indexCallableDecls then fails to find a declaration node for every callable outside the tsconfig program, and extractSequential skips it (if (!fn) continue).
Consequence:-j defaults to sequential (cli.ts:50-51, index.ts:96), so by default the analyzer emits L3/L4 graphs for less than half the callables it put in the symbol table.
Reproduction
OWASP Juice Shop (3 tsconfigs: root, frontend/tsconfig.json, frontend/tsconfig.base.json), -a 4 --tsc-only --skip-tests --no-build, fresh cache per run:
-j 1 (default)
-j 8
callables in symbol table
2,493
2,493
callables with a CFG
1,093 (43.8%)
2,344 (94.0%)
ddg edges
11,147
15,925
param_in
4,886
5,333
param_out
1,033
1,535
artifact
12.4 MB
14.3 MB
Not byte-identical, and not close.
Pre-existing — reproduced on 8032d08 (before #92/#93 landed) at 437 vs 946 with a CFG. The anonymous-callable work scaled the gap but did not create it.
Why CI never caught it
Every fixture in test/fixtures/ is a single-tsconfig project whose include covers all its sources, so the tsconfig-scoped set and the whole-repo set coincide and the paths agree. Verified: anon-app, dataflow-app and sample-app are all byte-identical between -j 1 and -j 8. The gate can only fail on a fixture where the two file sets differ, and no such fixture exists.
Scope boundary
Fixes the file-set divergence between the sequential and worker extraction paths, and adds a fixture that can actually fail the gate.
Does not decide which file set is correct — that is #58 (honor tsconfig boundaries vs. make whole-repository discovery explicit). This issue only requires the two paths to agree, whichever #58 settles on. Does not thread per-program tsconfigs into the workers (#77); nested-program under-resolution is orthogonal and stays as documented at core.ts:30-37.
Goals
Make extractSequential and projectFor derive their file set from one shared helper, so the two paths cannot drift
Add a multi-tsconfig fixture (root program excluding a subdirectory that still contains callables) to test/fixtures/
Add an -j 1 vs -j N byte-identity assertion over that fixture to the suite — the gate index.ts:92-95 already claims exists
Re-run the determinism gate on Juice Shop and record the numbers
Whichever file set wins changes L3/L4 output volume substantially in one direction or the other; that is a user-visible change and needs the same migration-note treatment as any other.
The -j 0 → 1 default means most users have only ever seen the under-populated output, so "fixing" this will look like a large unexplained growth in artifact size unless it is called out.
Definition of done
-j 1 and -j N outputs are byte-identical on a multi-tsconfig fixture, asserted in the suite and failing before the fix
Juice Shop at -a 4: -j 1 and -j 8 produce byte-identical analysis.json
The claim at src/dataflow/index.ts:92-95 is either true or rewritten to say what is actually guaranteed
Problem
The
-j Nvs-j 1byte-identical determinism gate — the onesrc/dataflow/index.ts:92-95names as the correctness guarantee for the worker path —does not hold on a multi-tsconfig project, and the default (sequential) path is the losing side.
The two paths build their ts-morph
Projectfrom different file sets:extractSequential,src/dataflow/index.ts:156-170) reuses the main-threadproject, which is the tsconfig-scoped program.projectFor,src/dataflow/worker.ts:53-62) construct withskipAddingFilesFromTsConfig: trueand then add everythingdiscoverSourceFiles(root)finds — whole-repository discovery, which is what the symbol-table build also uses.So the worker path's file set matches the symbol table and the sequential one does not.
indexCallableDeclsthen fails to find a declaration node for every callable outside the tsconfig program, andextractSequentialskips it (if (!fn) continue).Consequence:
-jdefaults to sequential (cli.ts:50-51,index.ts:96), so by default the analyzer emits L3/L4 graphs for less than half the callables it put in the symbol table.Reproduction
OWASP Juice Shop (3 tsconfigs: root,
frontend/tsconfig.json,frontend/tsconfig.base.json),-a 4 --tsc-only --skip-tests --no-build, fresh cache per run:-j 1(default)-j 8Not byte-identical, and not close.
Pre-existing — reproduced on
8032d08(before #92/#93 landed) at 437 vs 946 with a CFG. The anonymous-callable work scaled the gap but did not create it.Why CI never caught it
Every fixture in
test/fixtures/is a single-tsconfig project whoseincludecovers all its sources, so the tsconfig-scoped set and the whole-repo set coincide and the paths agree. Verified:anon-app,dataflow-appandsample-appare all byte-identical between-j 1and-j 8. The gate can only fail on a fixture where the two file sets differ, and no such fixture exists.Scope boundary
Fixes the file-set divergence between the sequential and worker extraction paths, and adds a fixture that can actually fail the gate.
Does not decide which file set is correct — that is #58 (honor tsconfig boundaries vs. make whole-repository discovery explicit). This issue only requires the two paths to agree, whichever #58 settles on. Does not thread per-program tsconfigs into the workers (#77); nested-program under-resolution is orthogonal and stays as documented at
core.ts:30-37.Goals
extractSequentialandprojectForderive their file set from one shared helper, so the two paths cannot drifttest/fixtures/-j 1vs-j Nbyte-identity assertion over that fixture to the suite — the gateindex.ts:92-95already claims existsCaveats and known risks
-j 0 → 1default means most users have only ever seen the under-populated output, so "fixing" this will look like a large unexplained growth in artifact size unless it is called out.Definition of done
-j 1and-j Noutputs are byte-identical on a multi-tsconfig fixture, asserted in the suite and failing before the fix-a 4:-j 1and-j 8produce byte-identicalanalysis.jsonsrc/dataflow/index.ts:92-95is either true or rewritten to say what is actually guaranteed