Skip to content

Phase 3 Workstream A: cross-file edge resolution#3

Open
gavdevs wants to merge 12 commits into
mainfrom
phase-3-workstream-a
Open

Phase 3 Workstream A: cross-file edge resolution#3
gavdevs wants to merge 12 commits into
mainfrom
phase-3-workstream-a

Conversation

@gavdevs
Copy link
Copy Markdown
Owner

@gavdevs gavdevs commented May 21, 2026

Summary

Cross-file CALLS / USES_TYPE / IMPLEMENTS edges now land in the graph, unblocking mycel callers, mycel uses, and mycel implements. Implements the Workstream A plan (docs/superpowers/plans/2026-05-11-phase-3-workstream-a-cross-file-edges.md) end-to-end.

What changed

  • Edge schema: Edge gains optional from_line so tree-sitter can hand the LSP refinement layer a call-site coordinate.
  • Tree-sitter extractors (TS + Rust): capture call-site row on CALLS / USES_TYPE / IMPLEMENTS emissions.
  • Graph helper: new GraphClient::symbol_containing(file_path, line) -> Option<String> maps a resolved location back to a Symbol qname.
  • Bridge: new resolve_refs_for_file op calls request_definition per site and returns (from_path, from_line, to_path, to_line, kind) tuples. The bridge now keeps files persistently open across requests and prewarms the LS with every same-language source file — tsserver only resolves through imports when the target file is open simultaneously.
  • Pipeline: collects RefSites from tree-sitter edges (skipping already-resolved same-file ones), seeds the column by locating the bare callee token on the source line (col=0 returns nothing from tsserver on indented call sites), calls resolve_refs, maps responses to Symbol qnames via symbol_containing, and appends resolved edges with EdgeSource::Lsp.
  • CLAUDE.md: drops the "callers/uses/implements broken" entries and the "cross-file CALLS drop silently" bullet.

Test coverage

  • End-to-end integration test (crates/mycel-index/tests/cross_file_calls.rs) — indexes a TS project with a cross-file call into a fresh FalkorDB and asserts the CALLS edge lands and query_callers returns the cross-file caller. Passes.
  • LSP smoke tests fixed: they were always-broken because they anchored on current_dir() but cargo test runs from the package manifest dir. Now anchored on CARGO_MANIFEST_DIR.

Test plan

  • cargo build --workspace clean
  • cargo clippy --workspace --all-targets -- -D warnings clean
  • cargo test --workspace — 82/82 pass (no LSP)
  • MYCEL_TEST_LSP=1 cargo test --workspace — 85/85 pass (incl. live multilspy + tsserver)
  • Manual mycel callers content_hash against this repo (skipped locally — Ollama not running here; the integration test covers the same contract)

Out of scope (deferred)

  • Cross-file resolution for languages without multilspy (Python, Go) — TS + Rust only.
  • LSP-resolved edges from outside the indexed surface (stdlib, node_modules) — dropped today; future work could record them as external Symbols.
  • Deleting MultilspyResolver::refine — still marked #[deprecated]; delete after a sweep confirms no callers.

🤖 Generated with Claude Code

gavdevs added 12 commits May 11, 2026 22:54
Locks the post-Workstream-A behavior: copies the TS fixtures into a
tempdir, runs the indexer pipeline (extract -> resolve_refs -> graph
upsert) per file with deferred edge batching, then asserts
`query_callers("simple_function.ts::add")` returns the cross-file
caller from `imports_and_exports.ts`.

Gated on MYCEL_TEST_LSP=1 to keep multilspy / tsserver / FalkorDB out of
the default `cargo test --workspace` path. Re-uses the existing
`imports_and_exports.ts` fixture (already imports `add` from
`./simple_function` and calls it) rather than adding a redundant
`cross_file_caller.ts`.

Adds async-trait + tempfile as dev-dependencies on mycel-index for the
StubEmbedder and tempdir setup.
Two bugs were preventing Workstream A's cross-file CALLS / USES_TYPE /
IMPLEMENTS edges from reaching the graph:

1. Bridge closed files between requests. tsserver only resolves through
   imports when the target file is open simultaneously with the source.
   The `with server.open_file(path):` form closed each file before the
   next request, so request_definition stopped at the import binding in
   the requesting file. Fix: maintain an ExitStack of open files per
   (repo, language), and prewarm with every same-language source file
   in the repo when the LS first spins up.

2. Pipeline always sent col=0 to LSP. tsserver's request_definition
   returns nothing when the cursor lands on whitespace, so col=0 for
   indented call sites resolved to empty. Fix: locate the bare callee
   token on the source line and seed its 0-indexed column. Also skip
   edges whose target already contains `::` (same-file resolutions
   produced earlier in the pipeline).

The smoke tests under crates/mycel-lsp were anchored on
`current_dir()` but `cargo test` runs from the package manifest dir, so
`scripts/multilspy_bridge.py` and the TS fixtures were never findable.
Fix: anchor on `CARGO_MANIFEST_DIR` and walk up to the workspace root,
matching the pattern already used in cross_file_calls.rs.

After these fixes the cross-file integration test passes against a live
multilspy + tsserver, and all 85 workspace tests pass with
MYCEL_TEST_LSP=1.
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.

1 participant