Description
I may be missing a required input here, so this is partly a question.
Running index_repository with mode=cross-repo-intelligence and an explicit target_projects, where the consumer has an HTTP_CALLS edge whose url_path is byte-identical to a provider's served Route name (/v2/orders/{id} on both sides), returns projects_scanned: 1, total_cross_edges: 0. I could not get the pass to emit a single cross edge under any input I tried, including this identical-string case. On a larger multi-service codebase it also returned 0 across all categories (http/grpc/async/channel).
My actual question: what is the minimum a call and a route need to share to be linked? If the matcher needs more than a matching path (a method, a confidence value, a node property the extractor sets), I could not find it in the docs.
Repro (self-contained): https://gist.github.com/azuttre/21e5e85f7590261721e3af7aa079dbfb → issue-3-cross-repo-zero-edges.sh
Related note, possibly the cause: the route/call extractor did not produce Route or HTTP_CALLS nodes from the minimal gin, FastAPI, and Express services I tried. A @app.get(...) decorator was captured but no route. That is why the repro inserts the nodes directly, to give the matcher unambiguous input. If that minimal-extraction gap is expected (for example it needs resolvable dependencies), I would value a pointer.
Env: v0.8.1, macOS (arm64).
Activity
RithvikReddy0-0 commentedon Jun 20, 2026
Spent a while reproducing this from a source build. Short version: the matcher is doing what it's supposed to : the zero edges come from two separate things upstream of it, and the one that actually bites you ("0 across all categories on a real codebase") isn't the matcher at all.
1. Why the repro returns 0
The matcher never looks at a Route's
name. For eachHTTP_CALLSedge it pullsurl_path+methodfrom the edge props, rebuilds the Route QN as__route__<METHOD>__<url_path>, and looks that up:Your inserted Route has
qualified_name = 'route:/v2/orders/{id}', so the lookup misses even though thenamestrings are byte-identical. To match by hand the Route would need to be QN'd__route__GET__/v2/orders/{id}.2. The extractor is fine for providers
A real decorator service does produce routes. I indexed:
and got a
Routenode__route__GET__/v2/orders/{id}plus aHANDLESedge fromget_order. Thedef handler(): passfiles in issue-3 have no decorator and no call, so they produce nothing — which is correct, not a bug.3. The real cause: consumer HTTP calls get dropped unless the client lib is indexed
This is the one that matters. On a normal repo,
requests.get("http://order-service:8080/v2/orders/123")produces no edge at all notHTTP_CALLS, not even a plainCALLS.In
pass_calls.c::resolve_single_call, a call only becomes an edge if its callee resolves to a node that already exists in the graph (cbm_gbuf_find_by_qnreturns non-NULL).requestsis an external dep whose source isn't indexed, so the call is thrown out before it ever reaches HTTP classification.Confirmed it by dropping a local
requests/__init__.pystub into the repo theHTTP_CALLSedge shows up immediately. That's why a real multi-service codebase, where every HTTP client is a pip/npm dependency, returns 0 across http/grpc/async/channel.4. And even once the edge exists, a second mismatch
When an
HTTP_CALLSedge is created, itsurl_pathis the full URL (http://order-service:8080/v2/orders/123), but the provider Route is the bare templated path (/v2/orders/{id}). The matcher does an exact-string QN lookup — no host stripping, no path-param normalization so123vs{id}and the scheme/host/port both block the match.So the minimum to link two services today is pretty narrow: a consumer
HTTP_CALLSedge whoseurl_pathis byte-identical to the provider Route path, plus a provider Route QN'd__route__METHOD__pathwith aHANDLESedge. In practice that only lines up if the HTTP client is vendored into the consumer and both sides use identical literal paths.Happy to split (3) into its own issue it's the actual blocker for the real-world case and it's independent of the matcher. I can also take a crack at a fix if that's welcome.
azuttre commentedon Jun 20, 2026
Thanks, this is a thorough write-up. You're right on the QN: my inserted Route used
route:/v2/orders/{id}, not__route__GET__/v2/orders/{id}, so the lookup was never going to hit. That one's on me.3 and 4 are the useful part. On the real multi-service codebase I was testing the consumer side did produce
HTTP_CALLSedges, so what bit me was 4: the call'surl_pathcarried a different version prefix and param style than the provider route, and the exact QN lookup never matched. Both causes are real, just showing up on different repos.Yes, splitting 3 into its own issue makes sense, it's independent of the matcher and it's the one that silently returns 0 on a normal repo. A fix for either would be very welcome, and I'm happy to test whatever you land.
fix(cross-repo): emit HTTP_CALLS for unindexed client libs and normal…
RithvikReddy0-0 commentedon Jun 20, 2026
Hey @azuttre , so I worked on it, I opened the 536 which is covering the 3 root causes : 1, the Unindexed Client Lib Drops
2, URL normalization
3, reverse-direction matching
DeusData commentedon Jun 20, 2026
Thanks guys for the analysis. Will review ASAP
fix(calls): emit HTTP_CALLS for external clients that resolve to no QN (
fix(cross-repo): dedupe CROSS_* edges and document external self-pass (…
test(repro): fix harness include + #408 comment; add #571, #523, #546
fix(cross-repo): emit HTTP_CALLS for unindexed clients, normalize URL…
fix(issues): #521 YAML config-URL Route dedup, #523 sequential extern…
fix(lint): clear cppcheck errors gating make-test (NULL-target guard …
fix(test): resolve 18 make-test regressions from the marathon batch
fix(pipeline): emit HTTP_CALLS for external client calls masked by re…
9 remaining items
DeusData commentedon Jul 8, 2026
v0.9.0 includes project resolution and trace/cross-edge fixes that may affect this cross-repo repro. Could you retest on v0.9.0 with the same byte-identical route/call setup and confirm whether it still returns zero? Marking awaiting-reporter.
fix(pipeline): classify native fetch() as HTTP_CALLS, not local shadows
niebloomj commentedon Jul 28, 2026
Retesting on v0.9.0 (macOS arm64) as @DeusData requested. Cross-repo still returns 0 across all 8 indexed repos. Adding concrete data points for the three root causes @RithvikReddy0-0 identified — confirms each one and adds a new fourth observation.
Setup
mainbranch, freshmode=fullreindex immediately before the cross-repo passFrumFinanceCore(FastAPI lambdas) ↔FrumFinanceUI(axios client)FrumFinanceCore(FastAPI lambdas) ↔SlackApp(urllib calls)FrumFinanceCore(FastAPI lambdas) ↔SlackTriageApp(httpx, but actually only used for OpenRouter/Slack Web API; RightCapital goes through the Python SDK import, not HTTP)cli index_repository --repo-path <P> --mode cross-repo-intelligence --target-projects ["*"]Observations matching the three root causes
(1) External client libs get dropped — confirmed
FrumFinanceUIships with 8HTTP_CALLSedges in the graph, all of which come fromtests/e2e/acceptance/*.spec.ts(URL strings in test files). The real API client —src/api/budget.tsx,src/api/auth.ts, etc. — usesaxiosthroughsrc/api/axiosInstance.ts, and none of those calls produceHTTP_CALLSedges. The client-sideHTTP_CALLScount is 8/100s of expected. This matches root cause #3 exactly.(2) No
HANDLESedges on FastAPI handler functions — confirmed, fresh reindexEven after a forced reindex (touched
auth.pyto bust the incremental cache, ranmode=full, confirmedexpected_nodes=4332 / expected_edges=19232against actual4326 / 19109— i.e. extraction was re-run), FastAPI handler functions have noHANDLESedge to theirRoutenodes. Cypher against the live graph:The
Routenode/user/loginexists, the functionuser_login_handlerexists, but no edge between them. So the provider side of the cross-repo match is also broken, independently of the consumer-side lib-dropping. The handler→route wiring is the gap the #667 fix needs to close.The actual
Routenodes that DO haveHANDLESedges in our graph are coming from test fixtures (tests/advisor/test_network_utils.pycalling FastAPI'sTestClient("/")), not from the production FastAPI decorators inlambdas/budget_insights_lambda/api/main.pyor.../handlers/user/auth.py.(3) URL normalization not happening — N/A for us, but a related new finding
Our client URL strings in
tests/e2e/acceptance/*.spec.tshappen to be the same literal/user/budgets,/user/insightsas the providerRoutenode names (FastAPI doesn't use:paramstyle, it uses{param}, and the UI tests use literal concrete paths). So the exact-string QN lookup should work for the 8 edges we have — but it still returns 0, because (per your analysis) the lookup compares against the__route__METHOD__pathQN, and the routes created from string-literal URL callsites get QN'd__route__ANY__/user/budgetswhile provider-side routes are QN'd__route__ANY__/user/budgetstoo — so the QN does match for these 8, but the matcher isn't using HTTP_CALLS edges in its source set, or there's a second filter.(Checking the live graph: the FrumFinanceCore graph contains
Routenodes with name/user/loginbut theirqualified_nameis__route__ANY__/user/login, and the FrumFinanceUI graph containsRoutenodes with name/user/budgetswithqualified_name__route__ANY__/user/budgets. They have identical QN shape but live in separate project graphs and are not deduplicated/joined across projects, which is what the cross-repo matcher is supposed to do.)(4) New finding:
manage_adris exposed by the binary but missing from MCP tool catalog/Users/Jacob/.local/bin/codebase-memory-mcp 0.9.0 --helplists 14 tools:index_repository, search_graph, query_graph, trace_path, get_code_snippet, get_graph_schema, get_architecture, search_code, list_projects, delete_project, index_status, detect_changes, manage_adr, ingest_traces. Only the first 8 appear in the MCPtools/listresponse to clients.manage_adr(mode='update')(referenced in everyindex_repositoryadr_hint) andingest_traces(the contributor's mentioned workaround for missing edges — currently returns "Runtime edge creation from traces not yet implemented") are unreachable through normal MCP usage. Workaround:codebase-memory-mcp cli manage_adr ...from the shell. Filing this separately if useful; flagging here because the #667 verification workflow may want to callmanage_adrprogrammatically.Environment
codebase-memory-mcp 0.9.0(macOS arm64, ui variant, GitHub release archive install)fullreindexHANDLESedges on any FastAPI handler function in the lambdas layersrc/api/*.tsxHappy to dump the full
query_graphoutput for any specific node if helpful — the graph is queryable viacli query_graph '{"project": "...", "query": "..."}'.fix(extract): stop accepting regex literals and file paths as HTTP URLs
fix(cross-repo): a consumer-only service keeps its channel edges acro…
fix(st): keep typed-receiver calls identical in both venues
DeusData commentedon Sep 25, 2026
Thank you, @azuttre, for the careful repro, @RithvikReddy0-0 for the excellent root-cause breakdown, and @niebloomj for the v0.9.0 data! We retested current main against all of it:
requestsand similar) now produce HTTP_CALLS.http://order-service:8080/v2/orders/123toGET /v2/orders/{id}, stripping the host and normalizing the params.Two gaps remain. A Python f-string URL (
requests.get(f"http://…/{order_id}")) keeps itsf"…"wrapper, so it can never match. And a prefix given viainclude_router(..., prefix="/user")isn't composed into the route path. We'll track both as focused follow-ups. @RithvikReddy0-0, you'd be very welcome to take either one if you're interested. The axios-instance case is covered by fixes in review, andmanage_adris exposed in the MCP tool list on v0.11.0.fix(pipeline): compose axios.create baseURL into HTTP_CALLS (DeusData…
DeusData commentedon Oct 25, 2026
Thank you for the detailed reproductions and the later retest. The last maintainer update leaves f-string URLs and composed router prefixes as focused follow-ups, alongside the axios-instance work. I have no newly verified resolution for those remaining cases; no repeat of the existing evidence is needed. Sorry for the delay—this is waiting on maintainer follow-up, and I’ll follow up soon.
extract: fold prefixed and triple-quoted Python string URLs
DeusData commentedon Oct 28, 2026
Progress on this issue: #2774 by @RithvikReddy0-0 is merged as 1f934b6. Python string URLs written with a prefix (r"", b"", u"", an f"" with no field) or with triple quotes now fold to the bare URL, so calls like requests.get(f"http://svc/v1/items") can match their route. The issue stays open for the remaining cross-repo cases.