Repository navigation
fix(sync): a name imported through a barrel links when an edit gives the barrel its re-export - #2744
Merged
Merged
Conversation
…er-f99e69 # Conflicts: # __tests__/sync-import-binding-retry.test.ts # src/db/reference-tail.ts # src/index.ts # src/resolution/import-resolver.ts
…n the module is a project file with that key
…odule lacks the name
This was referenced Oct 21, 2026
timothybrush
pushed a commit
to timothybrush/codegraph
that referenced
this pull request
Oct 21, 2026
…olves another way (colbymchenry#2752) A named import that a name match linked to a declaration elsewhere while its module did not export the name kept that link after an edit gave the module the name. A barrel's `export { EmptyState } from './EmptyState'` declares nothing, so no definition delta, failed-ref retry or barrel walk saw it (the "retargets" PR colbymchenry#2744 left). A name match into the module itself, a class exported only as its default and imported by name, kept its link after the default was dropped, where a fresh index finds nothing. reopenNameMatchedImports (module-importers.ts): for each module the sync modified, its importers' binding edges that resolved some other way than their import (getImportBindingsResolvedElsewhere, an indexed range per importer), whose import statement names this module, are resolved again against the graph as it is (ReferenceResolver.resolveNow, writing nothing). When the answer differs, the importer's edges through the name and into the members of what the name match took go back for the sweep. Regression test sync-name-matched-imports.test.ts: 4 cases comparing the synced graph with a fresh index of the final tree. Fresh indexes are byte-identical on 8 repos. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
danusha2345
pushed a commit
to danusha2345/codegraph
that referenced
this pull request
Oct 21, 2026
…mchenry#2759; EXTRACTION_VERSION 52 for Go `error` embedding) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
codegraph syncand the file watcher now linkimport { useInvocation } from './context', and every use of the name, when an edit gives the barrelcontext/index.tsthat re-export after the importing file was indexed. Before, the import, its calls and its JSX or template tags stayed unlinked until the importing file changed or the project was re-indexed.Why it stayed unlinked: the barrel declares none of the names it passes on, so sync's retry by name never reached the importers' failed references. The edit adds no file and changes no definition, so neither the importer re-open through added files (fix(sync): imports through a re-exporting module follow it when it is deleted or added #2512) nor the barrel walk (fix(sync): a lazy route relinks a page that appears below its barrel #2560 / fix(sync): an import a barrel passes on under another name relinks when its module gains it #2665) runs.
The change:
importBindingTailnow parks the whole name of a plain named import under its module's key (module:context), as fix(sync): a reference through an import binding links its module when the module appears later #2450 does for default, namespace and aliased bindings and fix(sync): a Python import of a name a package re-exports links when the package appears later #2507 for Python's unaliased imports. It does so only while:The by-name lookup from fix(sync): a reference through an import binding links its module when the module appears later #2450 still finds the reference by its own name.
Re-verified on current main first
The shapes originally reported (late-file hold scenario) now converge on main without this change:
useInvocation);ThemeToggle, passed on asdefault as ThemeToggle).#2512's importer re-open and #2560 / #2665's barrel walks cover them. A probe on ada1445 passed both add cases and failed the edit case with 2 of 8 links. This PR covers the edit.
Why the rule is narrow
Three versions were measured on the same 18 repos. All three fix the same barrel-edit cases; they differ only in how many references they park, which sync then retries whenever a file with that key changes.
What the narrower rules leave out can't be satisfied through the key:
@vben/icons,@follow/constants) resolves to the package folder, and its entry file (src/index.ts) never has the folder's key;Tests
__tests__/sync-import-binding-retry.test.ts:forwardedfrom a barrel yet to pass it on →module:lib;@main, an alias of a file with another key → name tail;LIMIT, a constant its module exports, passed as a function → name tail.Red on main ae0fc63: the barrel-edit case (2 of 8 links) and the tail test fail. The two add cases pass on main through #2512 / #2665 and stay as regression coverage.
Mutations:
@mainassertion (module:@main);LIMITassertion (module:consts).Full suite on this branch, with main 51be28d merged, the kernel built and
CODEGRAPH_KERNEL_EXPECT=1: 689 files, 8,185 passed, 0 failed, 82 skipped. The related sync suites (12 files) passed as well.A/B (main ae0fc63 vs this branch, 18 repos, each arm's sync vs its own fresh index)
Fresh index: nodes, edges and files are identical in all 18 repos. 10 repos are byte-identical (controls include gin, django-realworld and vue-realworld). The rest differ only in the tail of refs that fail on both arms.
Late sync, every 7th source file:
$tcalls and its layout components, vue-element-admin'sTagsView,SidebarandSettings, milo-ui's chart utils, folo'sNoopChildren. What remains on both arms is same-edge metadata and retargets, which predate this change.**.*vben hold: this is a side effect, not part of the design. Its 844 failing$trefs end up split between their name tail (462) andmodule:locales(382), so both by-name lookups fall under the 500-name ceiling. On main all 844 sit under one name, over it.**infrahub hold: ref rows only, with identical edges. Refs intogenerated/types.ts(2.1 MB, indexed with no nodes) failed while the file was held out, kept their name tail, and nothing re-resolves them after it returns. A fresh index parks them undermodule:types. They fail on both arms; only the bookkeeping differs.Cost
constants/ui.ts, 89 → 206 ms. Whole syncs stay within noise. These were timed with the "module file must carry the key" version, which parks a superset of this PR's refs.uri.ts,lifecycle.ts) is unchanged;The A/B ran on ae0fc63; this branch was then synced to 51be28d (#2743, extraction), which touches none of its files. The validation kit lives in
D:\cgwork\ubarreland is deleted after the merge.🤖 Generated with Claude Code