Repository navigation
Description
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 __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__jellybinary dispatch,CANTS_SELF_JELLY, the@cs-au-dk/jellydependency 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-onlywhentsc_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__jellymode.- One code path:
selectProvidergone;analyze()L2 = tsc resolver + defuse linker. - Joern superset ledger committed with the PR: per-fixture real-edge coverage = 100%, every residual classified.
- Determinism gate green (paired-run byte-identical call_graph); full suite + typecheck + monotonicity gates green.
- vscode benchmark table in the PR description (time, peak RSS, edges by prov, vs Joern where feasible).
- README/CLAUDE.md call-graph sections rewritten (no union/jelly language); release notes drafted with the BREAKING flag lines.
Activity
feat(callgraph): JS source discovery + the T4c ctor-field callback ch…
fix(syntactic): a .d.ts beside its .js is declarations, not the module (
test(ledger): rounds 5-8 — JS discovery, T4c chain; vscode 99.66%, re…
docs(ledger): residual heading count (#98)
fix(syntactic): force allowJs on, so discovered .js files resolve
feat(callgraph)!: defuse linker, propagation tiers, and the repositor…