Repository navigation
Description
Summary
Jelly call-graph edges are never persisted to analysis.json or Neo4j. They are only reachable as a replacement graph via --call-graph-provider jelly, and the both mode — the one explicitly meant to combine/compare the two — silently discards them.
Details
All three emit paths read from a single app.call_graph, which is whatever the selected provider returns (src/core.ts:28-29):
const cg = provider.build({ project, symbol_table, root: opts.input, log, phantoms: opts.phantoms });
const call_graph = cg.edges;analysis.json and the Neo4j projection both consume that one array, so they share the same fate.
1. Jelly is not used by default
The default provider is tsc (src/semantic_analysis/provider.ts:71-72, and the callGraphProvider option default). This is documented as intended, but it means a default run never sees any Jelly-resolved edges (higher-order / callback edges the resolver misses).
2. both mode does not persist Jelly edges to analysis.json
bothProvider.build() (src/semantic_analysis/provider.ts:37-51) runs tsc + jelly, logs an edge-set diff, then return tsc; — Jelly's edges are computed and thrown away. They only feed the diffEdges log line, never the emitted graph:
build(ctx) {
const tsc = tscProvider.build(ctx);
let jelly: CallGraphResult;
try { jelly = jellyProvider.build(ctx); } catch (e) { /* ... */ return tsc; }
diffEdges(tsc, jelly, ctx.log); // log-only
return tsc; // jelly edges discarded
}So after --call-graph-provider both, analysis.json contains zero Jelly-only edges.
3. Same gap for Neo4j
Because Neo4j projects the same app.call_graph, both mode also emits zero Jelly edges to the graph DB. There is no mode that persists tsc ∪ jelly (merged) to either target — --call-graph-provider jelly replaces tsc rather than augmenting it.
Proposed design
Flip the default so the richer graph is what you get unless you ask otherwise:
- Default (no flag): union of tsc + jelly. Run both providers and emit the merged edge set to
analysis.jsonand Neo4j. Edges keep theirprovenancetag (["tsc"]/["jelly"]), and an edge resolved by both carries both provenances, so consumers can still tell them apart and the diagnostic diff is still derivable. --tsc-only: explicit opt-out. The only way to drop Jelly and get the tsc resolver graph alone (the current default behavior). For users who can't run Jelly (e.g. environment constraints) or want the fast, resolver-only path.- Merge semantics: union by
(source, target)key. On collision, sum/keep weight and mergeprovenance+tagsrather than letting one provider's edge clobber the other. The existingdiffEdgesbecomes a logging detail of the union step, not a reason to discard.
Migration notes for the option surface
- The current
--call-graph-provider tsc|jelly|bothenum no longer maps cleanly. Options:- Keep
--call-graph-providerwith valuesunion(new default),tsc,jelly; add--tsc-onlyas sugar for--call-graph-provider tsc, or - Make union the implicit default and add only
--tsc-onlyas the documented opt-out, retainingjelly/bothas advanced/diagnostic values.
- Keep
botheither becomes an alias for the union default or is kept as the diagnostic-only (diff, no persist) mode — needs a decision.- If Jelly fails at runtime, union should degrade to tsc-only (as
bothalready does on catch) and log it, so the default never hard-fails on a Jelly error.
Repro (current behavior)
cants <project> --call-graph-provider both -o out/
# out/analysis.json call_graph has no provenance=["jelly"] edges
grep -c '"jelly"' out/analysis.json # → 0
Activity
[-]Jelly edges never persisted: discarded in 'both' mode, absent from analysis.json and Neo4j[/-][+]Default to tsc∪jelly union; make --tsc-only the explicit opt-out (jelly edges currently never persisted)[/+]Merge pull request #12 from codellm-devkit/fix/issue-11-missing-jelly…