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
docs/design/specs/defuse-linker-call-graph.md (committed on the work branch). Parity precedent: codeanalyzer-python 1.2.0 (#148 there) — PyCG → Jedi + defuse linker, spec codeanalyzer-python/docs/design/specs/2026-08-25-defuse-linker-call-graph-design.md.
Problem
The union call graph's Jelly leg is the analyzer's scale ceiling: a whole-program flow analysis (the same cost class as python's removed PyCG) plus ~the largest piece of the bundled binary (main.ts__jelly dispatch, patches/, @cs-au-dk/jelly). On vscode-scale targets it is unusable. Measured on our fixtures, jelly-only edges reduce to four classes — decorator invocations, library-mediated callback edges (lambda passed to .map/app.get), receiver-element typing inside anons, and param-flow calls — all recoverable by a deterministic per-callable linker over the def-use machinery that already exists for L3 (src/dataflow/defuse.ts).
Scope boundary
codeanalyzer-typescript only, one PR. Schema v2 shape, ids, levels, monotonicity: unchanged (schema_version stays 2.1.0; prov token swap only). NOT in scope: python-sdk's tsc_only kwarg removal (follows in the SDK's next minor once this releases — recorded in the spec's release plan), and the giant-JSON streaming-emit fix for whole-vscode analysis.json (separate issue; the vscode benchmark here measures the analyze/compute phase and the Bolt path).
Goals
Remove Jelly wholesale: jellyProvider.ts, the union provider, --call-graph-provider, --tsc-only, the __jelly binary dispatch, CANTS_SELF_JELLY, the @cs-au-dk/jelly dependency and its patches — one code path (BREAKING: released flags removed)
Defuse linker at L2, targeted kernels: only callables with unresolved call sites after the tsc leg; per-callable, no fixpoint, sorted iteration, prov: ["defuse"] (merged ["defuse","tsc"] when both find an edge)
Tier ladder, landed in order until the Joern ledger is clean: local alias/value chase → decorator-invocation edges (edge-only, no body node — jelly's own behavior) → external-callback rule (function value passed to external/unresolved callee ⇒ enclosing→lambda edge; deliberate, documented divergence from python) → interprocedural param/return/property votes (bounded rounds) → CHA-by-name fallback
Reference validation: iterate until the call graph is a strict superset of every real (existing-target, non-synthetic) edge Joern jssrc2cpg produces on the validation corpus (repo fixtures + one real-world express/nest app), with documented exception classes for Joern synthetics
vscode scale benchmark in the PR: L1/L2 time/RSS/edge counts on microsoft/vscode, vs Joern jssrc2cpg where it survives
A/B determinism: byte-identical call_graph across paired runs on the corpus; jelly-recovery % (union vs new) reported in the PR (spike metric, no hard gate)
Caveats and known risks
The external-callback rule is a semantic divergence from python (python emits no library-mediated callback edges). Deliberate: JS is callback-central and 2.1.0's anonymous-callable nodes need incoming edges. Recorded in the spec; the parity clause covers vocabulary, not per-language recall.
Removing released CLI flags is BREAKING in a minor — python 1.2.0 precedent, release notes must flag it. python-sdk pins and passes --tsc-only when tsc_only=True; until the SDK follow-up lands, that combination breaks against the new binary.
Joern jssrc2cpg's TS/JS output has its own synthetic-node families; the superset gate is against REAL edges only, and the exception ledger must be audited per class, python-style — not waved through.
Some jelly-only edges may be junk (decorator edges are arguably metadata); the ledger decides — recovery % is reported, Joern superset is the enforced gate.
Definition of done
git grep -li jelly -- src packaging patches package.json → nothing; the compiled binary shrinks and has no __jelly mode.
Plan
docs/design/specs/defuse-linker-call-graph.md (committed on the work branch). Parity precedent: codeanalyzer-python 1.2.0 (#148 there) — PyCG → Jedi + defuse linker, spec
codeanalyzer-python/docs/design/specs/2026-08-25-defuse-linker-call-graph-design.md.Problem
The union call graph's Jelly leg is the analyzer's scale ceiling: a whole-program flow analysis (the same cost class as python's removed PyCG) plus ~the largest piece of the bundled binary (
main.ts__jellydispatch,patches/,@cs-au-dk/jelly). On vscode-scale targets it is unusable. Measured on our fixtures, jelly-only edges reduce to four classes — decorator invocations, library-mediated callback edges (lambda passed to.map/app.get), receiver-element typing inside anons, and param-flow calls — all recoverable by a deterministic per-callable linker over the def-use machinery that already exists for L3 (src/dataflow/defuse.ts).Scope boundary
codeanalyzer-typescript only, one PR. Schema v2 shape, ids, levels, monotonicity: unchanged (schema_version stays 2.1.0;
provtoken swap only). NOT in scope: python-sdk'stsc_onlykwarg removal (follows in the SDK's next minor once this releases — recorded in the spec's release plan), and the giant-JSON streaming-emit fix for whole-vscodeanalysis.json(separate issue; the vscode benchmark here measures the analyze/compute phase and the Bolt path).Goals
jellyProvider.ts, the union provider,--call-graph-provider,--tsc-only, the__jellybinary dispatch,CANTS_SELF_JELLY, the@cs-au-dk/jellydependency and its patches — one code path (BREAKING: released flags removed)prov: ["defuse"](merged["defuse","tsc"]when both find an edge)Caveats and known risks
--tsc-onlywhentsc_only=True; until the SDK follow-up lands, that combination breaks against the new binary.Definition of done
git grep -li jelly -- src packaging patches package.json→ nothing; the compiled binary shrinks and has no__jellymode.selectProvidergone;analyze()L2 = tsc resolver + defuse linker.