Summary
cbm_service_pattern_match() in internal/cbm/service_patterns.c classifies a
call as an HTTP client call (HTTP_CALLS edge) only when the resolved
qualified name contains a substring from a hardcoded allowlist
(http_libraries[], service_patterns.c ~L30-70): axios, node-fetch,
undici, ofetch, requests, httpx, etc.
The native/global Fetch API (fetch(url, opts) used with no import
statement, as in any browser or modern Node runtime) is not in this list.
Since it has no import, its resolved QN never contains any library
substring, so cbm_service_pattern_match() returns CBM_SVC_NONE and no
HTTP_CALLS edge is ever emitted — even when the call's first argument is a
literal path that byte-matches a real backend Route node.
Repro
Vue frontend (frontend/src/api.js):
export async function drawLottery(drawId) {
const res = await fetch('/lottery/draw', {
method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },
body: JSON.stringify({ draw_id: drawId }),
})
...
}
FastAPI backend (backend/app/draw.py):
@router.post("/lottery/draw")
def draw(body: DrawRequest, ...):
...
trace_path(function_name="drawLottery", mode="cross_service") → no link found.
MATCH (a)-[r]->(b:Route {qualified_name:'__route__POST__/lottery/draw'}) → 3 inbound edges, all backend-side (CALLS from the module, CALLS from a test, HANDLES from the handler itself). Zero edges from the frontend caller.
- Project-wide: 8 of 9 frontend API functions in
api.js call bare fetch() directly and get zero HTTP_CALLS edges. cross-repo-intelligence / trace_path(mode=cross_service) can never link them to their backend routes.
Secondary oddity (found while investigating, not fully root-caused)
Two functions (requestOtp, verifyOtp) that call a local wrapper
(postJson(path, body) → itself calls bare fetch) do get an HTTP_CALLS
edge, despite postJson not resolving to anything in http_libraries[],
route_reg_libraries[], or matching method_suffixes[]/route_reg_suffixes[]
(checked all three tables). Whatever mechanism creates these edges also emits
a duplicate Route node with method ANY (__route__ANY__/auth/otp)
alongside the real FastAPI-registered one (__route__POST__/auth/otp), and
the edge lands on the ANY node — which has no HANDLES edge from the real
handler. So even the "working" case points at an orphan node, not the real
route.
Suggested fix
Add the bare Fetch API as a recognized "library" for HTTP classification —
e.g., treat an unresolved/global fetch identifier (no import binding) as an
implicit HTTP client call when its first argument is a URL/path-shaped string
literal, the same way emit_http_async_edge already gates on
first_string_arg[0] == '/' || strstr(url, "://"). This is likely a common
false-negative for any modern frontend codebase that doesn't wrap fetch in
axios/ofetch/etc.
Environment
- codebase-memory-mcp 0.8.1 (linux-amd64-portable)
- Reproduced on a Vue 3 + FastAPI monorepo,
index_repository(mode=full)
Summary
cbm_service_pattern_match()ininternal/cbm/service_patterns.cclassifies acall as an HTTP client call (
HTTP_CALLSedge) only when the resolvedqualified name contains a substring from a hardcoded allowlist
(
http_libraries[], service_patterns.c ~L30-70):axios,node-fetch,undici,ofetch,requests,httpx, etc.The native/global Fetch API (
fetch(url, opts)used with no importstatement, as in any browser or modern Node runtime) is not in this list.
Since it has no import, its resolved QN never contains any library
substring, so
cbm_service_pattern_match()returnsCBM_SVC_NONEand noHTTP_CALLSedge is ever emitted — even when the call's first argument is aliteral path that byte-matches a real backend
Routenode.Repro
Vue frontend (
frontend/src/api.js):FastAPI backend (
backend/app/draw.py):trace_path(function_name="drawLottery", mode="cross_service")→ no link found.MATCH (a)-[r]->(b:Route {qualified_name:'__route__POST__/lottery/draw'})→ 3 inbound edges, all backend-side (CALLSfrom the module,CALLSfrom a test,HANDLESfrom the handler itself). Zero edges from the frontend caller.api.jscall barefetch()directly and get zeroHTTP_CALLSedges.cross-repo-intelligence/trace_path(mode=cross_service)can never link them to their backend routes.Secondary oddity (found while investigating, not fully root-caused)
Two functions (
requestOtp,verifyOtp) that call a local wrapper(
postJson(path, body)→ itself calls barefetch) do get anHTTP_CALLSedge, despite
postJsonnot resolving to anything inhttp_libraries[],route_reg_libraries[], or matchingmethod_suffixes[]/route_reg_suffixes[](checked all three tables). Whatever mechanism creates these edges also emits
a duplicate
Routenode with methodANY(__route__ANY__/auth/otp)alongside the real FastAPI-registered one (
__route__POST__/auth/otp), andthe edge lands on the
ANYnode — which has noHANDLESedge from the realhandler. So even the "working" case points at an orphan node, not the real
route.
Suggested fix
Add the bare Fetch API as a recognized "library" for HTTP classification —
e.g., treat an unresolved/global
fetchidentifier (no import binding) as animplicit HTTP client call when its first argument is a URL/path-shaped string
literal, the same way
emit_http_async_edgealready gates onfirst_string_arg[0] == '/' || strstr(url, "://"). This is likely a commonfalse-negative for any modern frontend codebase that doesn't wrap
fetchinaxios/ofetch/etc.
Environment
index_repository(mode=full)