Kotlin/Java: Retrofit client interfaces are minted as server `Route` nodes instead of outbound `HTTP_CALLS`
维护者通常 2 天内回复
还没有人认领这个 Issue。
评估
调研方向
Start by reading the Kotlin and Java HTTP indexing paths that create Route nodes and HTTP_CALLS edges, then compare their handling of Retrofit annotations with the existing JAX-RS and RestTemplate behavior described here. Reproduce with the supplied OrderApi.kt and Java interface examples, checking both graph edge types and route paths. Done when Retrofit methods produce the expected outbound calls and paths, with no client HANDLES routes or cross-repository matches landing on the client.
由索引模型根据 Issue 内容生成。
描述
Version
codebase-memory-mcp 0.12.1
Platform
Linux (x64)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
ui
What happened, and what did you expect?
A Retrofit service interface (@GET/@POST/... from retrofit2.http, in Kotlin or Java) declares the HTTP calls
a client makes, but it is indexed as if the client served them: each annotated method becomes a Route
node of the client project with a HANDLES edge from the interface method. Three consequences:
- Outbound calls lost. The interface methods get no
HTTP_CALLSedge, socross-repo-intelligencereports
cross_http_calls: 0for a client whose whole HTTP surface is Retrofit, which is the usual shape of an
Android app. - Other callers get linked to the client. A path written with a leading slash (
@GET("/v1/orders/{id}"),
which Retrofit treats as absolute: "Endpoint values which contain a leading/are absolute",
Retrofit.java:581)
yields aRouteidentical to the server's real one.cross-repo-intelligencefrom any other project that
calls the same endpoint then emits aCROSS_HTTP_CALLSpair into the client as well as into the server, as if
the client's interface method handled the request. - Paths collapse onto
/. Any path that is not a string literal with a leading slash becomes/, so all
such methods collide on__route__GET__//__route__POST__/:- the idiomatic relative path (
@POST("v1/orders")), resolved at runtime against thebaseUrl
(Retrofit.java:560); - a Kotlin
const val, alone (@GET(ORDERS)) or in a string template (@GET("$ORDERS/{id}/status")), even
when the constant itself starts with/. Retrofit annotation arguments must be compile-time constants, so
this is a common way to share a path prefix across the methods of one interface.
- the idiomatic relative path (
Expected: see "Result vs expected" in the Reproduction section.
Reproduction
1. Code. Three dummy repos, created as /tmp/cbm-kotlin-retrofit-client, /tmp/cbm-orders-server and
/tmp/cbm-billing-caller.
Client repo /tmp/cbm-kotlin-retrofit-client, under src/main/kotlin/com/acme/client/:
// OrderApi.kt (Retrofit, Kotlin coroutines)
package com.acme.client
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path
private const val ORDERS = "/v1/orders"
interface OrderApi {
@GET("/v1/orders/{id}")
suspend fun getOrder(@Path("id") id: String): String
@POST("v1/orders")
suspend fun createOrder(@Body body: String): String
@GET(ORDERS)
suspend fun listOrders(): String
@GET("$ORDERS/{id}/status")
suspend fun getOrderStatus(@Path("id") id: String): String
}
Server repo /tmp/cbm-orders-server, under src/main/java/com/acme/server/ (JAX-RS; indexes correctly):
// OrderResource.java
package com.acme.server;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
@Path("/v1/orders")
public class OrderResource {
@GET public String list() { return "[]"; }
@GET @Path("/{id}") public String get(@PathParam("id") String id) { return id; }
@GET @Path("/{id}/status") public String status(@PathParam("id") String id) { return id; }
@POST public String create(String body) { return body; }
}
Another caller of the same server, /tmp/cbm-billing-caller, under src/main/java/com/acme/billing/ (an inline
RestTemplate, a shape that already produces HTTP_CALLS):
// BillingJob.java
package com.acme.billing;
import org.springframework.web.client.RestTemplate;
public class BillingJob {
public String order(String id) {
return new RestTemplate().getForObject("/v1/orders/{id}", String.class, id);
}
}
2. Commands. The project ids below are what the indexer derives from the /tmp/... paths.
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-kotlin-retrofit-client","mode":"moderate"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-orders-server","mode":"moderate"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-billing-caller","mode":"moderate"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-kotlin-retrofit-client","query":"MATCH (f)-[e:HANDLES]->(r:Route) RETURN f.file_path, f.name, r.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-kotlin-retrofit-client","query":"MATCH (f)-[e:HTTP_CALLS]->(r) RETURN f.name, r.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-orders-server","query":"MATCH (r:Route) RETURN r.qualified_name"}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-kotlin-retrofit-client","mode":"cross-repo-intelligence","target_projects":["tmp-cbm-orders-server"]}'
codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-billing-caller","mode":"cross-repo-intelligence","target_projects":["tmp-cbm-kotlin-retrofit-client","tmp-cbm-orders-server"]}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-kotlin-retrofit-client","query":"MATCH (h)-[e:CROSS_HTTP_CALLS]->(r) RETURN h.file_path, h.name, r.qualified_name"}'
codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-orders-server","query":"MATCH (h)-[e:CROSS_HTTP_CALLS]->(r) RETURN h.file_path, h.name, r.qualified_name"}'
3. Result vs expected. CLI output, trimmed to the rows.
Client HANDLES edges (expected: 0 rows; only the leading-slash literal keeps its path, the relative path and
both const val forms collapse to /):
rows: 4 (cols: f.file_path f.name r.qualified_name)
src/main/kotlin/com/acme/client/OrderApi.kt getOrder __route__GET__/v1/orders/{}
src/main/kotlin/com/acme/client/OrderApi.kt createOrder __route__POST__/
src/main/kotlin/com/acme/client/OrderApi.kt listOrders __route__GET__/
src/main/kotlin/com/acme/client/OrderApi.kt getOrderStatus __route__GET__/
Client HTTP_CALLS edges:
rows: 0 (cols: f.name r.qualified_name)
Expected 4 rows:
getOrder __route__GET__/v1/orders/{}
createOrder __route__POST__/v1/orders
listOrders __route__GET__/v1/orders
getOrderStatus __route__GET__/v1/orders/{}/status
Server Route nodes (correct):
rows: 4 (cols: r.qualified_name)
__route__GET__/v1/orders
__route__GET__/v1/orders/{}
__route__GET__/v1/orders/{}/status
__route__POST__/v1/orders
cross-repo-intelligence from the client: "cross_http_calls":0. Expected 4.
cross-repo-intelligence from the billing caller: "cross_http_calls":2 for its single call. Expected 1. The
reverse edges show the second one landing on the client's interface method:
# tmp-cbm-kotlin-retrofit-client (expected: 0 rows)
rows: 1 (cols: h.file_path h.name r.qualified_name)
src/main/kotlin/com/acme/client/OrderApi.kt getOrder __route__GET__/v1/orders/{}
# tmp-cbm-orders-server (correct)
rows: 1 (cols: h.file_path h.name r.qualified_name)
src/main/java/com/acme/server/OrderResource.java get __route__GET__/v1/orders/{}
The same holds for a Java Retrofit interface: @GET("v1/orders/{id}") and @POST("v1/orders") on a Java
interface give HANDLES to __route__GET__/ and __route__POST__/ and no HTTP_CALLS.
Related: #2668 (Java outbound calls through injected clients, format strings and request builders yield no
HTTP_CALLS; same "outbound call lost" family, different mechanism), #1248 (false Routes minted from
non-registration string literals).
Logs
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
Impact on a real codebase. On a production Kotlin Android app (29 Retrofit interfaces, 85 annotated
methods; proprietary, so only counts here):
- 85
HANDLESedges onto 67 clientRoutenodes, 0HTTP_CALLS; - 16 methods (relative paths and
const valtemplates) collapse onto__route__GET__/and
__route__POST__/; - of the 65 other distinct paths, 55 match a
HANDLES-backedRouteof the backend services the app talks to,
so classifying them as outbound calls would give the app 55 correct cross-repo links instead of 0 (the
remaining 10 are static files and third-party APIs); - 15
CROSS_HTTP_CALLSfrom call sites in 6 other repositories of the same fleet land on the app's interface
methods.
Confirmations
- I searched existing issues and this is not a duplicate.
- My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.
- 主要语言
- C
- 星标
- 45.8k
- 派生
- 3.8k
- 平均合并
- 3 天 6 小时
- 30 天内合并 PR
- 201
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
DeusData/codebase-memory-mcp 的其他 Issue
-
Generated Pi extension (cbmem.ts) breaks Gemini/Antigravity: Type.Union of Type.Literal serializes to anyOf/const可能已有人在做 @divakantpandey 于 1 天前认领。 未关闭bug editor/integration
难度 2/5 1-3 小时 新手友好度 72/100
DeusData/codebase-memory-mcp#2787 · 1 条评论 ·
维护者通常 2 天内回复
-
editor/integration parsing/quality
难度 2/5 1-3 小时 新手友好度 68/100
DeusData/codebase-memory-mcp#2286 ·
维护者通常 2 天内回复
-
install writes an unsupported `args` key into the Claude Code SubagentStart hook, so it never runs未关闭bug editor/integration priority/high stability/performance ux/behavior
难度 2/5 1-3 小时 新手友好度 72/100
DeusData/codebase-memory-mcp#2239 · 1 条评论 ·
维护者通常 2 天内回复
-
bug priority/high ux/behavior
难度 2/5 1-3 小时 新手友好度 72/100
DeusData/codebase-memory-mcp#2232 · 2 条评论 ·
维护者通常 2 天内回复
-
documentation editor/integration parsing/quality priority/normal
难度 2/5 1-3 小时 新手友好度 85/100
DeusData/codebase-memory-mcp#2169 ·
维护者通常 2 天内回复
查看 DeusData/codebase-memory-mcp 的全部 Issue
相似的 Issue
-
documentation
难度 1/5 1-3 小时 新手友好度 91/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 83/100
维护者通常 1 天内回复
-
enhancement ui
难度 1/5 1 小时以内 新手友好度 72/100
ChupathingyCE/chupathingyce#485 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 65/100
维护者通常 1 天内回复
-
难度 1/5 1 小时以内 新手友好度 82/100
eclipse-paho/paho.mqtt.c#1727 ·
维护者通常 6 天内回复