Skip to content

fix(sync): record only indexed files as synthesis inputs (#2565) - #2574

Closed
inth3shadows wants to merge 4 commits into
colbymchenry:mainfrom
inth3shadows:fix/2565-synthesis-input-fk
Closed

inth3shadows wants to merge 4 commits into
colbymchenry:mainfrom
inth3shadows:fix/2565-synthesis-input-fk

Conversation

@inth3shadows

@inth3shadows inth3shadows commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2565.

A lazy value that loads a workspace package by name, like dynamic(() => import('icons').then((mod) => mod.EdgeFunctions)), records the module it loads as a synthesis input (lazyValueModules, #2420). The import resolves a workspace package to its directory, packages/icons, which is not an indexed file. synthesis_inputs.file_path references files(path), so publishing the synthesis refresh failed with FOREIGN KEY constraint failed.

  • Extraction had already committed, so only the synthesis refresh rolled back.
  • synthesis_pending stayed set, so every later sync failed too, whichever file changed.
  • A full index writes its inputs through the same replaceSynthesisInputs call and hit the same constraint. The synthesis step is best-effort there and swallows the error, so it left synthesis_inputs empty instead of failing.

Fix:

  • One normalizing writer. replaceSynthesisInputs stores each input under the indexed file's own path and skips a path that is no indexed file. Paths are normalized first: a pass can be handed a module spelled the way its import wrote it (import('@/widgets/Chart/') gives src/widgets/Chart//index.ts, and a path can carry a ./ segment). Without that, a real file would be dropped and a later edit to it would never redraw.
  • A re-check at publish. SynthesisStage.publish checks the staged inputs against files again inside its write lock, because they were staged before it took the lock.

Tests (verified) in __tests__/sync-synthesis-input-package.test.ts. All 4 fail on upstream/main and pass here:

  • the issue's one-package pnpm workspace: the loading file is recorded after a full index, and a sync after editing it succeeds (on main: expected [] to …contain 'src/App.tsx', then FOREIGN KEY constraint failed);
  • the issue's own trigger, an edit to another file with markup: the sync succeeds;
  • a barrel imported as @/widgets/Chart/ or src/widgets/./Chart, then rewired: the barrel is recorded, and the synced render edges equal a fresh index's.

sync-lazy-route-value, sync-rebuild-convergence, migrations-synthesis-json, sync-jsx-import-forwarding and sync-nested-barrel-route still pass. Full suite on Linux / Node 22 (before the round-1 changes): Tests 1 failed | 6784 passed | 360 skipped (7145). The one failure, ui-server-api.test.ts > the engine's own busiest symbol, fails the same way on upstream/main in this checkout, because it reads a stale .codegraph here. This repo has no CI workflow that runs on pull requests.

Known limits (observed, and the same on main):

  • Workspace packages resolve to a directory. The resolver returns the package directory, so the package's entry file (packages/icons/src/icons/index.ts) is never recorded as an input, and no edge is drawn from Chart to EdgeFunctions. Fixing that means resolving a workspace package through its main/exports and rejecting directories in import resolution. That is a wider change than this crash fix.
  • Unindexed files. A pass can read a file that is on disk but not indexed, for example a gitignored barrel. It can't be recorded, because the column has a foreign key to files. If the file is indexed later, nothing marks it as an input until another refresh runs.

…y#2565)

A lazy value that loads a workspace package by name, like
`dynamic(() => import('icons').then((mod) => mod.EdgeFunctions))`, records
the module it loads as a synthesis input. The import resolves a workspace
package to its directory (`packages/icons`), which is no indexed file, and
`synthesis_inputs.file_path` references `files(path)` — so the commit failed
with "FOREIGN KEY constraint failed" and every sync after an edit to that
file rolled back.

Both writers (SynthesisStage.publish and replaceSynthesisInputs) now keep
only paths that are in `files`.
inth3shadows added a commit to inth3shadows/codegraph that referenced this pull request Oct 15, 2026
inth3shadows added a commit to inth3shadows/codegraph that referenced this pull request Oct 15, 2026
colbymchenry#2565)

Review round 1 on colbymchenry#2574:
- An input spelled the way its import wrote it (`import('@/widgets/Chart/')`
  → `src/widgets/Chart//index.ts`, or a `./` segment) named a real indexed
  file but missed the exact-match filter, so the barrel was dropped and
  rewiring it never redrew the tag. Inputs are now normalized to the index's
  spelling before the lookup.
- The publish-time filter was redundant: on the stage connection
  replaceSynthesisInputs already writes the temp table through the filter.
  It is removed, so the rule lives in one writer.
- The test no longer pins the exact input set (a resolver that finds the
  package's entry file would rightly add it), and covers the issue's own
  trigger: an edit to another file with markup.
- CHANGELOG: the failure hit every sync once a redraw was needed, not only
  edits to the loading file, and extraction was committed; add the upgrade
  note.
…rite lock (colbymchenry#2565)

Review round 2 on colbymchenry#2574: with the publish-time filter removed, the
indexed-files check ran only when inputs were staged, outside the write
lock; a file deleted before publish would fail the FK and roll back the
whole refresh. The filter is back, naming its column rather than copying
SELECT *. CHANGELOG: a full index on an affected version could leave the
inputs empty, which only a re-index repairs. Test: one fixture writer,
and the package directory is checked after the sync too.
danusha2345 pushed a commit to danusha2345/codegraph that referenced this pull request Oct 15, 2026
colbymchenry#2565)

Review round 1 on colbymchenry#2574:
- An input spelled the way its import wrote it (`import('@/widgets/Chart/')`
  → `src/widgets/Chart//index.ts`, or a `./` segment) named a real indexed
  file but missed the exact-match filter, so the barrel was dropped and
  rewiring it never redrew the tag. Inputs are now normalized to the index's
  spelling before the lookup.
- The publish-time filter was redundant: on the stage connection
  replaceSynthesisInputs already writes the temp table through the filter.
  It is removed, so the rule lives in one writer.
- The test no longer pins the exact input set (a resolver that finds the
  package's entry file would rightly add it), and covers the issue's own
  trigger: an edit to another file with markup.
- CHANGELOG: the failure hit every sync once a redraw was needed, not only
  edits to the loading file, and extraction was committed; add the upgrade
  note.

(cherry picked from commit 65a8078)
danusha2345 pushed a commit to danusha2345/codegraph that referenced this pull request Oct 15, 2026
…rite lock (colbymchenry#2565)

Review round 2 on colbymchenry#2574: with the publish-time filter removed, the
indexed-files check ran only when inputs were staged, outside the write
lock; a file deleted before publish would fail the FK and roll back the
whole refresh. The filter is back, naming its column rather than copying
SELECT *. CHANGELOG: a full index on an affected version could leave the
inputs empty, which only a re-index repairs. Test: one fixture writer,
and the package directory is checked after the sync too.

(cherry picked from commit f525cb5)
danusha2345 pushed a commit to danusha2345/codegraph that referenced this pull request Oct 15, 2026
danusha2345 pushed a commit to danusha2345/codegraph that referenced this pull request Oct 16, 2026
danusha2345 pushed a commit to danusha2345/codegraph that referenced this pull request Oct 19, 2026
@colbymchenry

Copy link
Copy Markdown
Owner

Thanks @inth3shadows, this was the right diagnosis and the right fix. It landed as #2688, which filters synthesis inputs to indexed files at both places they're written: replaceSynthesisInputs and the stage's publish. You're credited in the CHANGELOG alongside @bompus's report. Closing this one as superseded, and thank you again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

codegraph sync fails with "FOREIGN KEY constraint failed" after d0bb9be5 when a file lazy-loads a workspace package

2 participants