Skip to content

path_between: directed call chains (#17, step 2) — re-land of #89 onto main - #90

Merged
gangtao merged 1 commit into
mainfrom
feat/call-path-traversal-main
Sep 21, 2026
Merged

gangtao merged 1 commit into
mainfrom
feat/call-path-traversal-main

Conversation

@gangtao

@gangtao gangtao commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Re-lands #89 onto main.

#89 was stacked on feat/ingest-kinds-and-names and got merged into that branch 29 seconds after #88 had been squash-merged to main, so its commit never reached main (main still has the old path_between). This PR is that same commit cherry-picked onto current main — the tree is byte-identical to the head that was reviewed in #89 (git diff origin/feat/call-path-traversal HEAD is empty).

See #89 for the full description, measurements and testing. Summary: bidirectional BFS with a visited budget (no arbitrary per-hop cut); mode="calls" = directed call chain, either direction, listed caller-first; mode="related" never routes through symbol/file connectors; mode="auto" says which it found; a miss returns the reason plus callees_of_a / callers_of_b. ⚠️ path_between returns an object instead of a list/null.

Tests: the full suite passed on this exact tree in #89 (326 passed, 10 skipped, 1 pre-existing unrelated failure). Re-run here: the infra-free subset only (parser, MCP/agent tool surfaces, version) — the local test database is down at the moment.

After merging, the stale branches feat/ingest-kinds-and-names and feat/call-path-traversal can be deleted.

🤖 Generated with Claude Code

The old path_between walked UNDIRECTED over EVERY relation and cut each hop to
sorted(frontier)[:200]. On proton-enterprise that (a) hid a depth-4 path entirely
(the arbitrary cut visits ~9% of the graph) and (b) when uncapped returned
shared-include junk -- HTTPHandler.cpp -imports-> Context <-imports- NativeLog.cpp
-- through hubs like String (degree 5,226). Neither is a call path.

Now: a bidirectional BFS with a total-visited budget (no per-hop cut).
mode='calls' follows only calls/indirect_call, directed, trying A->B then B->A,
always listing the chain caller-first with 'direction' saying which way it runs.
mode='related' is undirected over all relations but never routes THROUGH a
connector node (kind symbol/file) -- they may be endpoints, never bridges, and
the two search sides meeting AT one is not a path. mode='auto' (default) tries
calls then related and says which it found. Returns a dict; when nothing is
found it explains why (depth / budget / no connection) and returns the direct
callees of A and callers of B, because the extracted C++ call graph is
incomplete and the agent needs a next step, not 'null'.

Measured on the real graph: execute -> buildChainImpl found in 0.01s; asked
backwards, reported as b_to_a; the #17 question (HTTP processQuery -> NativeLog
produce) returns an honest 'no call chain' with executeQuery and
NativeLog::doProcessRequest as next hops. Agent prompt now tells the model to
bridge a broken chain with neighbors + read_source instead of stopping.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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