Skip to content

CI-only: fix/study-cross-repo-bridges at b7aca1a4, small layout (do not merge) - #64

Draft
peterkc wants to merge 111 commits into
mainfrom
ci/fix/study-cross-repo-bridges
Draft

peterkc wants to merge 111 commits into
mainfrom
ci/fix/study-cross-repo-bridges

Conversation

@peterkc

@peterkc peterkc commented Oct 25, 2026

Copy link
Copy Markdown
Owner

Fork-only draft to run CI for pi-gortex's fix/study-cross-repo-bridges at b7aca1a (Go cross-repo imports fix), plus one fork-only commit with the small zzet#941 test layout. Do not merge.

@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one): 1
  • coderabbit

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Central YAML; Path: .coderabbit.yaml
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 7bb09a86-ec3c-4b9b-ab44-4b097aacc2f1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@peterkc
peterkc force-pushed the ci/fix/study-cross-repo-bridges branch 3 times, most recently from 3d57203 to 56c3635 Compare October 27, 2026 00:21
The go.mod module-path bridge linked Go calls between tracked
repositories, but file-to-package import edges into a tracked module
stayed on dep::<module> terminals, even after a full warmup. The
resolver's own comments say tracked sibling imports resolve through the
file graph; the dep fallback is for modules with no matching files. The
fallback also collapses subpackage paths to the module ID.

Add an import-only bridge. It reads the retained import statement nodes
for the exact package path, picks the provider package with the same
module and workspace rules as the call bridge, and points the import
edge at the provider's package file with the origin and confidence of
other resolved cross-repo imports. Dependency contract nodes and their
consumes edges are unchanged. It runs on full and mutation-frontier
passes and reuses the module revision retry state, and it handles
consumers whose go.mod is in a subdirectory.

Re-indexing a provider file deletes incoming import edges (existing
behavior in SQLite file eviction). The bridge records which consumer
import statements point into each provider and re-creates those edges
when the provider is re-indexed. After a restart the record is rebuilt
once, lazily, by filtering import node IDs by path before loading any
file; later edits do not scan.

Package identities are cached per module revision. Repository sweeps
filter by import path before hydrating files and release the resolve
lock between batches.

Tests cover both track orders, IndexAll, consumer edits and re-index,
subdirectory go.mod consumers, provider file and repository re-index,
an unchanged warm restart followed by a provider edit, duplicate paths
and counts, and lock handling under panic. They fail before this change
on memory and SQLite stores.
The import recovery recorded a repository's imports of its own module,
so each save in a repository that imports its own packages reloaded
nearly every file, even with one tracked repository. Record and restore
only imports whose provider is a different tracked repository, and skip
restore when fewer than two repositories are in the graph.

The provider package cache was not cleared on the whole-graph fallback
paths, so a consumer edit after a provider file was deleted could bind
the import to the deleted file. Clear the cache on those paths and apply
import rebinds through the same live-target check as call rebinds.

An import lifted from an external:: fallback is now counted as resolved,
not unresolved. The one-time lazy seed runs from the public entry points
before the resolve lock is taken, so no lookup helper releases its
caller's lock.

New tests fail before this change.
Recovery of retained Go imports now takes the caller's context and
stops between batches when it is cancelled.

The presence check matched only the statement line, so two imports on
one line were treated as one. It now matches the import path. It also
accepts an import bound to a longer tracked module (for example
example.com/lib/v2 next to example.com/lib), which avoids a duplicate
edge on every full pass. File nodes load only when a same-line edge is
a dep:: terminal.
Use indexed module paths and retain import identity through provider eviction.
Recheck file bindings on module changes and bound incoming import recovery.
Verify provider lifecycles against independent cold indexes.
…budget

Recognize caller-local replace targets before restoring import rows.
Keep import recovery and restart seeding on a separate bounded budget
so incoming call binding and terminal retries still run.
…very

Seed retained import identities once without hydrating files or rewriting
edges. Keep provider import recovery on its own bounded budget so a large
workspace cannot disable recovery after a warm restart.
Recover retained imports for the existing module-change repository set,
not only the saved repository. Bound this recovery independently so an
import refusal cannot suppress incoming call binding or terminal retry.
A Rust `use other_crate::x` import of a crate whose source is another
tracked repository stayed external. Directory matching does not know
crate roots, Cargo package names or item paths, and Gortex had no map
from crate names to repositories.

Map each tracked repository's Cargo crates (root package and listed,
non-excluded workspace members) to their exposed name ([lib].name, else
the package name with dashes as underscores) and root file ([lib].path,
else src/lib.rs). An external Rust import links only when the crate that
owns the importing file declares the dependency in its own Cargo.toml
([dependencies], dev, build and target tables, and workspace-inherited
entries), including `alias = { package = ... }` renames, and exactly one
eligible tracked crate provides it. The rest of the path resolves to a
module file in that crate, falling back to the crate root for items.
Workspace policy is checked against the provider crate, not the alias.

The retry runs in the full cross-repo pass and in the mutation-frontier
pass, so a link survives an edit to the importing file. It is skipped
when no tracked repository has a Cargo.toml. Generic directory matching
and other languages are unchanged.

Limit: a link stays after the consumer removes the dependency until the
importing file is re-indexed.

Tests index two tracked repositories on memory and SQLite stores and
cover declared, renamed, member, lib-renamed and edited-consumer cases,
plus refusals for undeclared, ambiguous, excluded-member and
cross-workspace imports. The positive cases fail before this change.
@peterkc
peterkc force-pushed the ci/fix/study-cross-repo-bridges branch from 56c3635 to 8f31199 Compare October 30, 2026 16:16
zzet#806's whole-shadow retirement and save restub paths can delete imports
owned by unchanged consumers. Keep the exact pre-link stub on Cargo
imports, park those imports and their cross-repo calls before provider
eviction, and carry consumer files through the bounded cross-repo tail.

Retry declared consumers after IndexRepo, track and full_retrack. Keep
warmup's cross-repo-only files separate from provider derived plans.
Mirror the approved npm lifecycle shape without reparsing importers.

Cover both stores, both track orders, saves, full replacement, warm
full_retrack, untrack/retrack, unchanged repositories and linked calls.
Record the pre-link function or method target instead of deriving a stub
from the resolved symbol ID. Park only incoming calls to evicted targets,
using the existing view rather than re-reading SQLite edge copies.

Keep zzet#806's save carry/restub decisions and dataflow sites. Apply the
recorded call stub only when that existing path chooses to restub, and
pass forced file eviction's existing batch through the deletion core.

Compare imports and calls with a fresh cold index on both stores and
track orders, including associated functions, methods and forced eviction.
Use main's installed manifest-tree boundary for Cargo roots, workspace
members and nearest-manifest checks instead of reading another revision's
checkout. Keep metadata-only targets out of save-time import parking.

Retain IndexRepo's cross-repo consumer result and skip its runtime-track
resolver tail when the batch defers resolution. Cover both failures and
snapshot manifests, and make warm-retrack tests use the configured order.
Preserve Rust file additions on IndexResult and registered warm receipts.
Consume them in the existing scoped or full resolve after registration,
including provider-first warmup and multiple changed providers.

Restrict scoped recovery to marked imports into those providers. Keep the
native matcher and write only changed targets. Record additions installed
by the incremental fallback path too.
A Python `import pkg.mod` or `from pkg import mod` of a package whose
source is another tracked repository stayed external. Calls through such
imports already linked, but the import edges did not: directory matching
cannot map a dotted module to src/pkg/mod.py or pkg/__init__.py.

Map each tracked repository's Python distribution ([project].name or
[tool.poetry].name, PEP 503-normalized) to its top-level import
packages under the repository root or src/. An import links only when
the importing repository declares that distribution in its own
pyproject.toml ([project] dependencies and optional dependencies,
Poetry dependencies and groups) or requirements*.txt, and exactly one
eligible tracked repository provides the top-level package. The module
file is chosen with the existing Python module matching (.py and
__init__.py).

The import stays local or external when the importing repository has its
own files under that top-level name (including namespace folders without
__init__.py), for standard-library names, and for root tooling files
such as setup.py and conftest.py. Per-repository attribution keeps the
dotted import path on the edge so the retry can use it.

The retry runs in the full cross-repo pass, with light edge scans and
paged hydration, and in the mutation-frontier pass, so a link survives
an edit to the importing file. It does nothing with fewer than two
tracked repositories.

Limits: .pyi-only modules do not link, because stubs are not indexed. A
link stays after the dependency is removed from the manifest until the
importing file is re-indexed. Dotted modules do not match
cross-workspace module rules, so such imports stay external.

Tests index two tracked repositories on memory and SQLite stores. The
positive cases fail before this change.
The full-pass retry kept every tracked-import edge before processing
any page. With SQLite's projection scanner it now processes bounded
pages; other stores drain the light scan first, so no live cursor stays
open while the retry reads and writes the graph.

The consumer's local names now include both the literal top-level name
and the src-layout name. A root `src` package and a package under
`src/` each stay local, even when `src/__init__.py` exists.
Read manifests, requirements and package layout through the owning
indexer's manifest tree.

Carry added-file importer candidates in CrossRepoResolveFiles so deferred
and provider-first warmup can resolve after all repositories register.
Keep the existing matcher and avoid consumer-frontier scans on ordinary
saves. A file-only addition cannot trigger a whole-graph fallback.
Record successful new Python files on the fallback path, matching the
structural batch path. This preserves consumer retry when a refresh read
changes after the probe.

Cover the fallback with a deterministic transform on memory and SQLite,
then compare import and call bindings with a cold index.
Build import bridge evidence before resolving calls from the same provider
save.
Remove obsolete package provenance in every call-parking route and finish
the direct Python rebind handoff. Verify complete rebound edge payloads on
both stores.
Exclude root and src packages named test or tests at provider discovery and
at Python call resolution. Keep consumer-local bindings and normal modules.
pytest test paths and other non-exported packages are not covered yet.
Give import-authorized functions and path-qualified constructors the same
evidence as wildcard methods. Keep the exact-module rejection unchanged.
Reuse source file payloads and batch target ownership for cross-repo import
counts. Assert native work counts and unchanged-pass behavior on both
stores.
Compare complete Cargo and Python edge payloads, and cover rename and back
and untrack-only. Repair the provenance, terminal-stamp, cold-order and
purge-retry gaps this exposed. Fallback and synthesis run before the
tracked-provider bridge, as in a cold index, so bridge refusals still win.
After provider removal, consumers match a consumer-only cold index.
Name the seven bridge resolution metadata keys and exercise them in a small
mixed-language two-repository fixture.
A full pass restores every import without a budget, so it no longer counts
deferrals and can mark recovery complete. Keep the bounded deferral on
mutation passes only. Gate the Cargo and Python terminal reconcile on the
incoming refusal alone, not on a Go import deferral.
A row that keeps its unresolved target needs a live source edge, not a node
for the target. Real retargets still need a live concrete target. Both
stores now keep the same restub provenance.
Receipt and watcher callers pass the files they already resolved, and the
bridge step does only the remaining outgoing work. A Python save now runs
one incoming resolve instead of two, on both stores.
Unrelated non-Go saves no longer seed imports or retry module dependencies.
Go source saves and Go build-list inputs (go.mod, go.sum, go.work,
go.work.sum, vendor/modules.txt) still seed once per revision and retry.
Snapshots check size and mtime with the two-second racy rule and take the
stamp before the first stat. File inventory, roots, config, manifests and
glob directories invalidate them, and an unreadable directory marks the
snapshot unknown. Stable passes read no manifests.
When the manifest snapshots show no tracked Python or Cargo dependency,
added files no longer scan every import edge. An unknown snapshot still
scans. Gaining a dependency reopens recovery and matches a cold index;
workspaces with a declared bridge still scan per added file.
Read light inbound identities and load full edges only for foreign import
and call sites carrying a bridge marker.
Read the caller's imports from the bridge index and memoize each package's
imports for the pass. A later export edit on the same resolver still sees
the new target.
Count only persisted, unregistered graph repositories in an active batch.
Configured repositories that never register no longer keep the extra
import scans running.
The re-export memo was written by resolveEdge workers during a full pass,
which races and can crash the daemon. Fill it while building the reachable
repo index, so workers only read it, like the other per-pass caches.
Install cargoCrateLookup, which keeps the cheap root count, so the Cargo
gates skip Rust work again in workspaces with fewer than two Cargo roots
and cold output is unchanged there.
Pass the files the master resolver saw, not the union with affected
files, so affected Python and Rust referrers still get the pre-bridge
outgoing pass and match a cold index.
When a mutation pass defers Go import recovery without an incoming
refusal, request the existing full cross-repo fallback, so later Go saves
do not repeat the all-repo recheck until a restart.
A root package has no slash in its directory, so every root crate with a
dependency counted as a bridge. Path dependencies on its own workspace
members no longer do.
Run the Go module retry whenever re-queued batches are pending, without
reseeding, so a dropped reindex or failed untrack retry does not wait for
the next Go save or full pass.
Fix comments left stale by the snapshot refactor and state when a snapshot
is reused: stat stamps, the racy window, the file-set revision and the
config revision.
…e pass

A provider save above the recovery budget logs and skips, as before the
full-pass continuation, and no longer marks the pass refused or reopens
the revision. Only the revision-wide consumer recheck can request the one
full continuation. Consumers of a provider with more than 16,384
registered imports keep stale import targets until a full pass.
Replace the env-gated indexer test with an external resolver integration
test that shrinks the recovery budget through export_test.go and drives
the public indexer entry point. It fails on both stores when the full
continuation is removed.
Collect the distinct package IDs and read their edges with one
GetOutEdgesByNodeIDs call per full pass instead of one point read per
__init__.py.
Iterate provider repos in sorted order so a shared budget always skips the
same provider, and name the skipped repo in the warning: its consumers stay
stale until the next full pass.
Share the recheck kind list between production and the counting stores,
so a changed kind list fails the zero-recheck assertions instead of
passing without measuring anything.
@peterkc
peterkc force-pushed the ci/fix/study-cross-repo-bridges branch from 8f31199 to 4998f59 Compare October 30, 2026 16:45
@peterkc peterkc added the ci:full Run the complete CI test matrix for this pull request label Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:full Run the complete CI test matrix for this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant