Skip to content

feat(indexing): include symlinked reference repositories in parent graphs - #818

Open
atif-databraid wants to merge 4 commits into
trailhq:mainfrom
atif-databraid:atif_symlink
Open

atif-databraid wants to merge 4 commits into
trailhq:mainfrom
atif-databraid:atif_symlink

Conversation

@atif-databraid

Copy link
Copy Markdown

Summary

A parent project's graph currently omits repositories mounted through directory symlinks, and Git-ignored reference repositories cannot be selected without changing ignore rules. Extend --follow-nested-repos to follow repository links, including linked worktrees, into one graph using their mounted paths and each child's Git ignore rules.

  • Add repeatable, persisted --include-repo <path> to include selected repository mounts alongside normal project source, including mounts ignored by the parent. Retain the restricted --include-ignored-repos --only-dir form.
  • Preserve saved directory restrictions across plain builds; add --all-dirs to clear them. Keep build, concept indexing, checks, and automatic refresh aligned.
  • Preserve the independent submodule gate for explicitly selected gitlinks. Track physical repository targets during the existing walk and invalidate freshness when a mount changes targets, even if filenames, sizes, and timestamps match. Legacy fingerprints retain their filters and receive one identity-aware rebuild when nested repositories are enabled.
  • Keep cycle detection based on active physical checkout paths while preserving logical mount paths for graph IDs. Broken links, file links, and links to ordinary directories remain excluded.

Validation

  • 116 targeted tests passed across ingestion, nested repositories, submodules, directory/extension filtering, refresh, incremental builds, worktree seeding, and path normalization.
  • Regression tests reproduced both the explicit-submodule bypass and stale refresh after symlink retargeting before the fixes; all pass afterward. Retarget coverage includes visible and explicitly included ignored mounts, plus legacy fingerprint migration and stable subsequent refreshes.
  • tsc -p tsconfig.json --noEmit and git diff --check passed.

@trailhq-graft

trailhq-graft Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

🌱 graft blast radius

5 areas changed → 5 areas can be affected. 18 dependent symbols, depth 2.
Tests: no test reaches Build Configuration, Context Discovery, File System Ingestion; 1 area updated its tests.
Tag: @anirudhkumar-nanonets — 10 of 10 areas · @shhdwi — 6 of 10 areas · @qoole — Context Discovery

flowchart TB
  A0(("Workspace Federation<br/>8 symbols"))
  A1(("Engine Orchestration<br/>4 symbols"))
  A2(("Pull Request Review<br/>4 symbols"))
  A3(("MCP Tool Integration<br/>1 symbol"))
  A4(("Check Context<br/>1 symbol"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0,A1,A2,A3,A4 reached;
Loading
Can be affected Symbols Nearest hop Reached from
Workspace Federation 8 src/graph/check.ts:L59-L159 checkGraph — calls, depth 1 Graph Construction, Build Configuration
Engine Orchestration 4 src/engine.ts:L104-L115 graph — calls, depth 1 Context Discovery, Graph Construction +1
Pull Request Review 4 src/app/review.ts:L45-L99 reviewPullRequest — calls, depth 1 Graph Construction, Build Configuration
MCP Tool Integration 1 src/mcp/tools.ts:L233-L262 callTool — calls, depth 2 Graph Construction
Check Context 1 src/context/check.ts:L39-L112 checkContext — calls, depth 1 Context Discovery, Build Configuration
Who knows this code — 4 people across 10 areas
Area Who knows it
Graph Construction · changed @anirudhkumar-nanonets — 19 commits, last 3mo ago · @shhdwi — 11 commits, last 14d ago
Build Configuration · changed @anirudhkumar-nanonets — 13 commits, last 9d ago
Context Discovery · changed @qoole — 4 commits, last 2d ago · @anirudhkumar-nanonets — 4 commits, last 3mo ago
CLI Entry Point · changed @anirudhkumar-nanonets — 71 commits, last 3d ago · @shhdwi — 51 commits, last 14d ago
File System Ingestion · changed @Frankie-Xu — 2 commits, last 2d ago · @anirudhkumar-nanonets — 3 commits, last 3mo ago
Workspace Federation · affected @anirudhkumar-nanonets — 17 commits, last 9d ago · @shhdwi — 11 commits, last 14d ago
Engine Orchestration · affected @anirudhkumar-nanonets — 17 commits, last 29d ago
Pull Request Review · affected @anirudhkumar-nanonets — 11 commits, last 27d ago · @shhdwi — 2 commits, last 14d ago
…2 further areas

Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no @ has no GitHub handle in its commit email — tag them by hand, or add a .mailmap entry. A suggestion from history, not a CODEOWNERS rule.

All 18 dependent symbols, grouped by area

Workspace Federation — 8 symbols in 5 files

  • src/graph/check.ts:L59-L159 — checkGraph (calls, depth 1)
    90: const sourceFiles = listSourceFiles(root, outDir, undefined, onlyDirs, committed.meta?.extensions);
  • src/graph/refresh-run.ts:L18-L21 — main (calls, depth 1)
    20: await buildGraph(dir, { contextDir, graphOnly: true, onlyDirs, extensions });
  • src/graph/refresh.ts:L202-L225 — rebuild (calls, depth 1)
    205: await buildGraph(args.dir, {
  • src/graph/refresh.ts:L271-L347 — ensureFreshGraph (calls, depth 1)
    299: const drift = probeDrift(dir, outDir);
  • src/graph/refresh-run.ts:L1-L33 — refresh-run.ts (calls, depth 2)
    9: import { buildGraph } from "./build.js";
  • src/graph/refresh.ts:L355-L381 — ensureFreshChildren (calls, depth 2)
  • src/graph/workspace-cli.ts:L65-L108 — buildChild (calls, depth 2)
    68: const childConfigPatch: BuildConfig = {};
  • src/graph/workspace.ts:L631-L656 — federateCheck (calls, depth 2)
    652: for (const child of wg.missing) lines.push(`${child}/: not built (run ${cmd("graft build")})`);

Engine Orchestration — 4 symbols in 1 file

  • src/engine.ts:L104-L115 — graph (calls, depth 1)
    105: return buildGraph(dir, {
  • src/engine.ts:L72-L86 — init (calls, depth 2)
  • src/engine.ts:L89-L91 — check (calls, depth 2)
  • src/engine.ts:L95-L97 — checkGraph (calls, depth 2)

Pull Request Review — 4 symbols in 4 files

  • src/app/review.ts:L45-L99 — reviewPullRequest (calls, depth 1)
    55: await buildGraph(checkout.dir);
  • src/app/review-process.ts:L178-L182 — childReviewer (references, depth 2)
  • src/app/review-worker.ts:L67-L87 — run (calls, depth 2)
  • src/app/server.ts:L31-L37 — AppSeams (references, depth 2)

MCP Tool Integration — 1 symbol in 1 file

  • src/mcp/tools.ts:L233-L262 — callTool (calls, depth 2)

Check Context — 1 symbol in 1 file

  • src/context/check.ts:L39-L112 — checkContext (calls, depth 1)
    64: for (const file of listContextFiles(root, outDir, exts)) {
Test signal per changed area — 1 ✓ · 3 ✗ · 1 –

Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.

  • ✓ Graph Construction — 3 of 5 reached · 4 test files changed here: test/context-only-dir.test.ts, test/graph-follow-nested-repos.test.ts, test/graph-only-dir.test.ts, test/ingest-fs.test.ts
    • not reached: writeFingerprint, listSourceFiles
  • ✗ Build Configuration — 0 of 1 reached · no test file reaches it
    • not reached: readIncludeIgnoredRepos
  • ✗ Context Discovery — 0 of 2 reached · no test file reaches it
    • not reached: resolveOnlyDirs, listContextFiles
  • – CLI Entry Point — no function, method or class changed here
  • ✗ File System Ingestion — 0 of 1 reached · no test file reaches it
    • not reached: gitVisibleFiles
57 test suites also reference this code

70 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.

  • test/ask-index.test.ts
  • test/ask.test.ts
  • test/claude-hooks.test.ts
  • test/claude-prompt-private.test.ts
  • test/container-extract.test.ts
  • test/context-batch-stability.test.ts
  • test/context-checkpoint.test.ts
  • test/context-synth-cache-compat.test.ts
  • test/context-synth-cache.test.ts
  • test/context-synth-clamp.test.ts
  • test/context-synth-concurrency.test.ts
  • test/context.test.ts
  • test/covers.test.ts
  • test/depth-parity.ts
  • test/generic-extract.test.ts
  • test/graph-bash.test.ts
  • test/graph-elixir.test.ts
  • test/graph-extensions.test.ts
  • test/graph-follow-submodules.test.ts
  • test/graph-go.test.ts
  • …37 more

⚠️ 2 changed files not in the graph (.trail/learnings/2026-11-11-explicit-repository-mounts-need-boundary-checks-atif.md, README.md) — no parser claims the extension, or the index predates the file.

graft blast · origin/main...HEAD · depth 2 · 14 changed files

Open the interactive graph → — click an area to see its dependent symbols at file:line.

github-actions Bot added a commit that referenced this pull request Nov 11, 2026

This branch has not been deployed

No deployments
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