Skip to content

Reparsed barrel candidates never get interprocedural dataflow regenerated (both engines) #2489

Description

@carlos-alm

Context

Raised by Greptile on PR #2488 (issue #2339 fix): the JS/WASM engine's reparseBarrelFiles now deletes dataflow rows referencing a barrel candidate's outgoing edges before deleting those edges (mirroring the Rust engine's pre-existing #979 fix), but never regenerates that dataflow afterward. Investigated whether this is a NEW regression from PR #2488 or a pre-existing dual-engine characteristic.

Finding: pre-existing in both engines, by design — not a regression

Rust (crates/codegraph-core/src/domain/graph/builder/pipeline.rs):

  • reparse_barrel_candidates (~L925-1053) re-parses barrel candidates via parallel::parse_files_parallel(&to_parse, root_dir, false, false) (L981) — hardcoding include_dataflow=false. The comment at L977-980 states this explicitly: "Dataflow/AST analysis is skipped because the barrel is not itself a 'changed' file; Stage 7 will reconstruct all outgoing edge kinds from the fresh parse."
  • parallel.rs::parse_files_parallel (L17-40) only sets symbols.dataflow if include_dataflow — so barrel candidates' FileSymbols.dataflow stays None.
  • write_dataflow (~L2066-2109), the sole INSERT INTO dataflow writer, skips any file whose symbols.dataflow is None (L2103-2106) — even though barrel candidates ARE included in analysis_scope by the time Stage 8 runs (file_symbols is mutated in place by Stage 6b), they're skipped because the field was never populated.
  • Net effect: dataflow rows for a reparsed barrel candidate are deleted (L1003-1009, the bug: incremental rebuild leaks ~249 duplicate edges per run #979 fix) and never regenerated in that same incremental build — by explicit design.

JS/WASM (src/domain/graph/builder/):

  • reparseBarrelFiles (stages/resolve-imports.ts L128-180) parses barrel candidates with the build's real engineOpts (L155), so dataflow IS actually extracted if the build requested it — but merges results only into ctx.fileSymbols (L158), never into ctx.allSymbols.
  • ctx.allSymbols is populated once in stages/parse-files.ts (L20) from the original changed-file set and is a separate Map from ctx.fileSymbols; nothing in resolve-imports.ts adds barrel candidates to it.
  • runAnalyses (stages/run-analyses.ts L11-25) — the sole dataflow-persistence entry point — operates on ctx.allSymbols, so barrel candidates' freshly-computed dataflow is silently discarded, never reaching the DB.

Both engines converge on the same observable behavior: a barrel candidate reparsed during an incremental build never gets its interprocedural dataflow rows regenerated, because dataflow persistence is scoped exclusively to the genuinely-changed-file set in both pipelines. This holds independent of PR #2488 — that PR only fixed a crash (silently-swallowed FK constraint exception aborting the entire JS barrel reparse, dropping import/reexport/call edges too, a strictly worse outcome than today's "just missing dataflow rows").

Follow-up (not blocking #2488)

Decide whether to extend dataflow analysis scope to reparsed barrel candidates in both engines (Rust: pass include_dataflow through to reparse_barrel_candidates instead of hardcoding false, and add the write to persistence scope; JS: merge barrel-candidate entries into ctx.allSymbols too, or run dataflow persistence against ctx.fileSymbols). Given hybrid barrel files can have real call edges (the core motivation for #2339/#979), it's plausible their interprocedural dataflow should also survive incremental rebuilds — needs product/perf tradeoff discussion since extending scope adds parse cost to a path currently optimized to skip it.

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