Skip to content

HTTP client detection misses native fetch() — only matches hardcoded library allowlist (axios/node-fetch/ofetch/etc) #856

Description

@rockywang101

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions