Skip to content

cross-repo-intelligence: 0 HTTP_CALLS edges — TS template-literal path param (${id}) never matched against Spring {id} route placeholder #2235

Description

@pourgholi

Version

codebase-memory-mcp 0.11.0

Platform

Linux (x64)

Install channel

GitHub release archive / install.sh / install.ps1

Binary variant

standard (linux-amd64-portable)

What happened, and what did you expect?

index_repository(mode="cross-repo-intelligence") returns 0 for every cross-edge category (cross_http_calls, cross_async_calls, cross_channel, cross_grpc_calls, cross_graphql_calls, cross_trpc_calls) across a 5-project Spring Boot + TypeScript workspace, even for a call/route pair I'd expect to be the easy case this feature is meant to handle.

I checked the existing related reports first — this isn't #1916 (axios-wrapper baseURL indirection: my caller has no wrapper instance, the full literal is at the call site), isn't #706 (constant/variable caller URL: mine is a literal template, not a Name/constant), and isn't #523's root cause #3 (HTTP client dropped because it's an unindexed external dependency: my http() helper is a local function in the same indexed project, confirmed present in the graph — see below). It looks closest to #523's root cause #4 (string-level Route-QN mismatch), but the specific mismatch here is narrower and, I think, worth tracking separately: a JS/TS template-literal path param (${id}) is never normalized to match a Spring path-variable placeholder ({id}), so even a "textbook" literal call site with no indirection at all still produces zero edges.

Reproduction

Backend (Spring Boot, @RestController):

// CustomerController.java
@RestController
@RequestMapping("/api/customers")
class CustomerController {
    @GetMapping("/{id}")
    Customer get(@PathVariable UUID id) { ... }
}

get_architecture(project="backend", aspects=["routes"]) confirms this is extracted correctly, full path composed with the class-level prefix:

GET /api/customers/{id}   -

Frontend (Orval-generated client calling a local http() helper — not axios, not a wrapper instance with baseURL):

// packages/api-client/src/generated/customer-controller/customer-controller.ts
export const get1 = (id: string, signal?: AbortSignal) => {
    return http<Customer>({url: `/api/customers/${id}`, method: 'GET', signal});
};
// packages/api-client/src/http.ts
export const http = <T,>(config) => { /* wraps fetch */ };

search_graph(project="frontend", query="fetch", file_pattern="*api-client*") confirms http is indexed as a first-class local Function node (frontend.packages.api-client.src.http.http, packages/api-client/src/http.ts:23-24) — so this isn't #523's "external dependency never resolves" case; both the caller (get1) and the callee (http) are in the same indexed graph, in the same project.

Commands run, in this order, all returning 0 cross edges:

index_repository(repo_path=".../objektmanager-backend", name="backend")   # nodes:6359 edges:28507, status: indexed
index_repository(repo_path=".../objektmanager-frontend", name="frontend") # nodes:3439 edges:11768, status: indexed
index_repository(repo_path=".../objektmanager-backend", mode="cross-repo-intelligence", target_projects=["*"])
  => {"cross_http_calls":0, ..., "total_cross_edges":0, "projects_scanned":4}
index_repository(repo_path=".../objektmanager-frontend", mode="cross-repo-intelligence", target_projects=["*"])
  => {"cross_http_calls":0, ..., "total_cross_edges":0, "projects_scanned":4}
index_repository(repo_path=".../objektmanager-frontend", mode="cross-repo-intelligence", target_projects=["backend"])
  => {"cross_http_calls":0, ..., "total_cross_edges":0, "projects_scanned":1}

index_status on both projects shows status: ready, parse_unusable_count: 0 — no coverage gap that would explain this by itself.

Expected

At least one HTTP_CALLS/cross-edge from get1 (frontend) to the GET /api/customers/{id} Route (backend), since the only difference between the caller's literal path and the provider's Route path is ${id} vs {id} — a mechanical, syntax-only difference (JS template-literal interpolation vs Spring's own path-variable placeholder syntax), not a semantic one.

Suggested root cause (unconfirmed — I don't have access to the extractor source)

Given #523's contributor comment describes the matcher rebuilding a Route QN as __route__<METHOD>__<url_path> and doing an exact string lookup with no path-param normalization, I'd guess the TS-side URL extractor either (a) doesn't resolve a template literal with an embedded expression to a "literal-enough" url_path at all (falls back the same way a Name/constant does, per #706), or (b) does resolve it, but preserves the raw ${id} substring instead of normalizing it to a wildcard/placeholder form comparable to {id}. Either way the fix likely needs to live on the caller-side URL extractor for TS/JS template literals specifically, independent of the matcher itself.

Logs

No cross_repo_intelligence log lines matched url pattern or similar in ~/.cache/codebase-memory-mcp/logs/{backend,frontend}-*.log for this run — happy to attach full logs if useful, redacted for path names.

Diagnostics trajectory (memory / performance / leak issues)


Project scale (if relevant)

5 projects indexed (backend: 6359 nodes/28507 edges, 20+ Spring routes; frontend: 3439 nodes/11768 edges, TS monorepo with an Orval-generated packages/api-client; 3 smaller non-code/infra projects not relevant to this repro).

Confirmations

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.ux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions