Skip to content

cross-repo-intelligence: CROSS_HTTP_CALLS resolves by URL path alone, emitting false cross-service edges when two indexed projects expose the same path #1459

Open

Description

@junk151516

cross-repo-intelligence resolves an outbound HTTP call to a CROSS_HTTP_CALLS edge by matching the URL path string against routes exposed by other indexed projects, without preferring the caller's own project. When the calling repo defines the same path itself — which it usually does, since that is what its own frontends call — the tool emits a cross-service edge that corresponds to no real cross-service call.

The result is reported as total_cross_edges: <N>, with nothing in the output distinguishing "this call leaves the service" from "another indexed project happens to expose the same path".

Split out of #1133 at @HungChu's suggestion; that issue is about the --target-projects flag parsing to zero targets and the non-deterministic worker crash, which are separate problems. This one is a correctness bug in the output of the runs that succeed.

Environment

  • v0.9.0, ui variant, Windows amd64, pinned binary (SHA-256 verified)
  • Source project: 31,287 nodes / 176,218 edges (Python / FastAPI)
  • Target project: 13,462 nodes (the source project is an in-progress migration of the target)

Repro

echo '{"repo_path":"<abs path to source repo>",
       "mode":"cross-repo-intelligence",
       "target_projects":["<target project name>"]}' \
  | codebase-memory-mcp cli index_repository

Then audit what it produced:

MATCH (a:Function)-[r:CROSS_HTTP_CALLS]->(b) RETURN a.qualified_name, r.url_path, b.qualified_name

For each url_path, grep the source repo for a route definition on that same path. Every path that the source repo defines itself is a false edge.

What we measured

Output was stable across the 9 successful runs of a 25-invocation matrix (total_cross_edges: 117, identical every time; the graph was not inflated by repetition). Querying the CROSS_HTTP_CALLS edges originating in the source project gave 40, which we audited:

CROSS_HTTP_CALLS edges originating in the source project 40
obvious noise (httpbin.org/ip) 3
path collisions 37, across 20 distinct routes
routes hand-audited against the source repo 7
of those, defined by the source repo itself 7 / 7
verified genuine cross-service calls 0

Worked example — the most frequent destination, /api/proveedores:

  • The source repo defines it itself: compra/router.py:133, APIRouter(prefix="/api/proveedores").
  • The callers the tool attributes to it are that repo's own frontends (frontend-app, reportes, recepcion-pos, admin) issuing fetch against their own API.
  • The repo's only configured pointer at the other service, LEGACY_API_BASE_URL, has no consumers at all — its own CLAUDE.md states this, and grep confirms it.

So the ground truth is zero HTTP calls from this repo to the target, and the tool reported 117 cross edges.

Why this is worse than a wrong number

We caught it only because a CLAUDE.md in the repo asserts that no HTTP client to the legacy service exists, and that contradicted the graph. Without that contradiction sitting in arm's reach, nobody audits a field named total_cross_edges — it reads as an architectural fact, not as a guess. There is no confidence, no candidates, no warning in the output; a false edge is presented exactly like a true one.

This is the same failure shape as the projects_scanned: 0 / status: success case in #1133: the tool is not wrong loudly, it is wrong in the register of a correct answer.

The precondition is ordinary, not exotic

Our pair is close to a worst case — the two projects share routes by construction, since one is the migration of the other — so it would be fair to ask whether this only bites unusual setups. It does not. The precondition is just two indexed projects exposing the same path.

@HungChu's fleet is the better example precisely because there is nothing unusual about it: four independently-developed NestJS services in one store. An earlier version of this section described that fleet as "every business controller serves /api/v1/<resource>, with an overlapping resource vocabulary" — that was wrong, and the corrected inventory they posted below in this thread is a stronger example, not a weaker one. Versioning there is per-controller with defaultVersion unset, so 26 of 32 controllers carry no version segment at all. The version segment was never what creates the collision; sharing a full path is:

path services declaring it how it resolves
GET /health all 4 @Controller('health') in each, and prefix-excluded in each ⇒ byte-identical /health in four indexed projects
GET / 2 also prefix-excluded in both
/api/projects 2 @Controller('projects'), unversioned in both
/api/aifunction 2 @Controller('aifunction'), unversioned in both

GET /health is the one worth putting in the acceptance criteria. It carries no assumptions about the fleet's domain: every service in every fleet exposes a health endpoint, and the idiomatic NestJS way to keep it off a versioned prefix is exactly that exclude, which makes the paths identical rather than merely similar. Any two services in one store collide there. /api/projects and /api/aifunction are the business-resource case — two services with no shared history that happen to expose a resource of the same name.

⚠️ Those four are predicted collisions, read statically from the decorators — not measured edges. #1428 means those routes produce no Route nodes, so that fleet reports total_cross_edges: 0 today and there is nothing in it to audit. The 7/7 hand-audit above remains the only measured evidence in either fleet. Stating this plainly at @HungChu's request, so that nobody reproduces their side, finds zero edges, and concludes the example was inflated.

The honest summary of the pair: one fleet where the bug is measured (FastAPI, 37 of 40 edges false, 7/7 audited routes locally defined), one where the preconditions are verifiable in source but masked by a separate extraction gap (NestJS, 4 collision paths including /health across all four services). That pair is what makes the ordering hazard below concrete.

Ordering hazard with #1428 — please read this before scheduling either fix

This is @HungChu's observation and I think it is the most consequential thing in the #1133 thread.

Right now our two fleets are the two states of this bug at the same moment:

If #1428 (or any other framework's route extraction) is fixed before route-ownership resolution, every affected fleet flips straight from the first state to the second, with no intermediate state in which anyone would notice. Zero edges at least looks like nothing happened. A few hundred plausible-looking edges read as an architectural fact and get believed.

Two consequences for acceptance criteria:

  1. Route-ownership resolution should land before or together with any new framework's route extraction, not after.
  2. This is not a NestJS-specific concern. Any improvement to route extraction, for any framework, performs the same flip. It is a precondition for the route-extraction roadmap as a whole, not a dependency of one issue.

Proposed fixes

(1) Prefer the caller's own project when resolving. Emit a cross-repo edge only when the path is not defined locally in the calling project. This alone removes 37 of our 40 edges and all 7 of the audited false ones, and it is the behaviour a reader already assumes from the field name.

(2) Surface ambiguity on the edge, for the genuinely ambiguous case where two projects define a path and the caller defines neither. CALLS edges already carry confidence / candidates / strategy, so this is plumbing existing fields through a new edge type rather than new infrastructure. Worth having independently of (1).

A third, cheap and orthogonal: since a path-only match is a heuristic, the summary field could say so — total_cross_edges reads as a count of facts. Even unverified_cross_edges, or a per-edge match: "path-only", would move it from fact to candidate without any resolution work.

Note on the 3 httpbin.org/ip edges

Distinct from the collisions and much smaller: those come from test/example code and matched on an absolute external URL. Not the point of this issue, but worth knowing they are in the 40 if anyone reproduces the count.

Activity

  1. added
    cypherCypher query language parser/executor bugs
    parsing/qualityGraph extraction bugs, false positives, missing edges
    stability/performanceServer crashes, OOM, hangs, high CPU/memory
    ux/behaviorDisplay bugs, docs, adoption UX
    windowsWindows-specific issues
    on Aug 5, 2026
  2. HungChu commented on Aug 6, 2026

    @HungChu

    Thanks for splitting this out, and for the offer to adjust how our fleet is described — I need to take you up on it, because my characterisation was wrong and you inherited the error from my comment in #1133. The good news is that the corrected version is a stronger example, not a weaker one.

    Correction: our fleet is not uniformly /api/v1/<resource>

    I wrote "four NestJS services behind a convention where every business controller serves /api/v1/<resource>". I went and counted instead of trusting my own summary:

    service @Controller total versioned unversioned
    A (main API) 21 3 18
    B (functions) 5 0 5
    C (ingest) 2 1 1
    D (orchestrator) 4 2 2
    total 32 6 26

    All four call enableVersioning({ type: VersioningType.URI }) without defaultVersion, so versioning is per-controller: a controller declaring version: '1' serves /api/v1/<path>, one declaring nothing serves /api/<path>. Both shapes coexist in the same app. So 26 of 32 controllers have no version segment at all — "every business controller serves /api/v1/" is simply not true of us.

    Why the corrected version is a better example

    The version segment was never what creates the collision — sharing a full path is. And once I looked at actual paths rather than my mental model, the collisions are more banal than what I originally claimed:

    path services declaring it how it resolves
    GET /health all 4 @Controller('health') in each, and all four exclude it from the global prefix (exclude: [{ method: GET, path: 'health' }]) ⇒ byte-identical /health in four indexed projects
    GET / 2 (A, B) also prefix-excluded in both ⇒ identical /
    /api/projects 2 (A, B) @Controller('projects'), unversioned in both ⇒ identical full path
    /api/aifunction 2 (B, D) @Controller('aifunction'), unversioned in both ⇒ identical full path

    /health is the one I would put in the acceptance criteria. It is not an overlapping-domain artefact or a migration artefact — every service in every fleet exposes a health endpoint, and the idiomatic NestJS way to keep it off the versioned prefix is exactly the exclude above, which makes the paths identical rather than merely similar. Any two services in one store collide there. That is a stronger claim than the "overlapping resource vocabulary" I originally offered, and it needs no assumptions about the fleet's domain.

    /api/projects and /api/aifunction are the business-resource cases: two independently-developed services that happen to expose a resource of the same name, no shared history, no migration relationship. That is the "ordinary" scenario your issue needs, and it is verifiable from decorators alone.

    One thing to state precisely, so the issue does not overclaim

    These are predicted collisions, read statically from the decorators — not measured edges. We cannot measure them: #1428 means our NestJS routes produce no Route nodes, so total_cross_edges is 0 and there is nothing to audit. Your 7/7 hand-audit is the only measured evidence in either fleet; ours is a forward-looking prediction of what lands the moment extraction works.

    I would rather the issue say that plainly than have someone reproduce our side, find zero edges, and conclude the example was inflated. If it helps, the honest framing is: one fleet where the bug is measured (FastAPI, 37/40 false), one where the preconditions are verifiable in source but masked by a separate extraction gap (NestJS, 4 collision paths incl. /health across all four services). The pair is what makes the ordering hazard concrete — which is the argument, and it survives the correction intact.

    Happy to paste the exact controller inventory if you want it in the issue body; I have kept the service names out on purpose, but the counts and the four collision paths are all real and re-derivable from any NestJS fleet with a health controller.

  3. sorcrr-dev commented on Aug 23, 2026

    @sorcrr-dev

    We have been evaluating a generic extension to the resolver described here for API-gateway deployments. This is a design question only; no implementation branch has been published.

    The local prototype first applies the correction proposed in this issue: prefer a caller-local route and never emit a cross-repository edge merely because another project exposes the same method/path. It also fails closed when multiple non-local projects remain plausible.

    For gateways, however, local-route preference does not recover the true provider when the public route differs from the provider route or when the caller uses an environment alias or a configured client wrapper. The proposed additional boundary is an explicit, opt-in, versioned HTTP binding artifact supplied to indexing with a SHA-256 fence. Each binding can carry:

    • public host, method, and path;
    • provider method and path after gateway translation;
    • exact target project;
    • deployment/config revision;
    • optional configured caller aliases/wrappers.

    A generic enrichment pass would run after call extraction and before route construction/cross-repository matching. It would enrich or recover HTTP_CALLS while preserving the original business caller, then record resolution provenance and confidence. pass_cross_repo would use target_project and provider method/path when present, otherwise retain current behavior. Ambiguous multi-project matches would remain unbound, and the existing CROSS_HTTP_CALLS edge type would remain unchanged. There would be no project-specific behavior when the option is absent.

    Diagnostics would distinguish missing binding, unresolved dynamic path, missing target project, missing provider route/HANDLES, ambiguous target, and stale binding revision. The acceptance set includes literal and aliased gateway URLs, template parameters, configured wrappers, direct provider URLs, method/path rewrites, query/trailing-slash normalization, duplicate routes across projects, missing handlers, and stale revisions.

    Before opening a separate feature issue or publishing a PR series, would maintainers prefer this opt-in deployment-binding contract to be tracked here as part of the resolver correction, or in a linked focused feature issue? Also, should ambiguous target-project evidence always fail closed, or should that policy be configurable?

    Related extraction gaps remain separate: #706, #1147, #1428, and #1611. The deployment artifact would not claim to replace generic constant folding, framework route extraction, or provider HANDLES construction.

  4. junk151516 commented on Aug 23, 2026

    @junk151516
    ContributorAuthor

    @sorcrr-dev — I'm the reporter here, not a maintainer, so treat the scheduling answer as an author's preference rather than a decision. On your two questions below — though this project's own release notes answer both of them better than I can. I've also re-measured the bug on the current release while I was at it, since the numbers in the body are from v0.9.0.

    1. Track it separately, and let it cite this issue as a prerequisite

    Your prototype already orders it that way — it "first applies the correction proposed in this issue," then adds the binding pass. I'd keep that ordering visible in the issue graph too, for a reason specific to this thread.

    The argument for scheduling route-ownership resolution soon is the ordering hazard in the body: any framework's route extraction landing first flips an affected fleet from silently-zero to silently-wrong, with no intermediate state in which anyone would notice. That argument only holds while the resolver correction stays small enough to schedule ahead of the next extraction improvement. A versioned artifact format, a SHA-256 fence, gateway translation semantics, staleness diagnostics and an eleven-case acceptance set is not that — however well-scoped it is on its own terms.

    They are also different in kind. Fix (1) here is a correctness floor: do not assert ownership you cannot establish. Your binding artifact is a capability ceiling: recover ownership in the case where source alone genuinely cannot establish it, because a gateway rewrote the path between caller and provider. The floor should not wait on the ceiling, and the ceiling reads better as its own issue with its own acceptance set.

    2. Fail closed, always — and this project already decided that, twice

    I was going to argue this from first principles. I don't need to: both answers are already shipped behaviour in v0.10.x.

    On failing closed. From the v0.10.5 notes, on Go routes built by string concatenation:

    the literal half is now recovered, and a path assembled from a variable is still left unresolved rather than fabricated.

    That is exactly the policy your question asks about, already applied one layer down, in this same domain, by this same project. Extraction refuses to invent a path it cannot establish. It would be strange for resolution to then invent an owner it cannot establish — and stranger still for that to be a config key when the extraction-layer equivalent is simply how it behaves.

    On what to do instead of a toggle. v0.10.0 shipped CALL_REFERENCE precisely so that, in the release's own words, "CALLS stops absorbing guesses," together with include_evidence to expose "the resolution provenance behind" an edge. That is fix (2) of this issue, already built, for a different edge type. Plumbing the same treatment through CROSS_HTTP_CALLS is following an established pattern, not adding infrastructure.

    So my answer to "always fail closed, or configurable" is: always, and the thing a toggle is for — "I accept the risk, show me the candidates" — is already served by the CALL_REFERENCE / include_evidence shape.

    The reason I'd push back hard on the configurable variant specifically: the setting does not survive into the store. Six weeks later someone runs

    MATCH (a:Function)-[r:CROSS_HTTP_CALLS]->(b) RETURN a.qualified_name, r.url_path, b.qualified_name

    and the edges written under "guess anyway" are indistinguishable from the ones written under "fail closed". A configuration option that changes the truth-value of persisted data and leaves no trace on that data is worse than today's uniform wrongness, which at least can be uniformly distrusted once known. Better to move the decision to query time, where the consumer taking the risk can see the ambiguity, than to write time, where the indexer takes it on everyone's behalf and silently.

    If something must be configurable, I'd put the knob on diagnostic verbosity, never on whether an unproven edge gets written.

    3. One note on the design itself

    Your diagnostics list "stale binding revision", which is right, but the behaviour on a stale binding needs stating alongside it: it should fail closed, not fall back to path matching.

    A declared, versioned, SHA-256-fenced binding reads as ground truth to anything downstream — considerably more authoritative than a path match. A stale one that silently degraded into the current heuristic would emit a wrong edge wearing better credentials than any of the wrong edges this issue is about. Same disease, better disguise.

    4. On the prototype

    Thanks for reporting it. "Prefer a caller-local route" is the same correction as fix (1), and an independent implementation of it behaving sanely is useful evidence that the fix is cheap.

    If you can share before/after cross-edge totals from your own store — even just the two numbers — that would be the second measured data point in this thread. Right now the 7/7 hand-audit in the body is the only one, and as the body notes, @HungChu's fleet cannot supply another while #1428 masks it.

    5. Re-measured on v0.10.8 — still present, and the audit is now exhaustive rather than sampled

    I re-ran the original repro against the current release (v0.10.8, the latest as of today) on the same FastAPI pair. The bug is unchanged.

    v0.9.0 (5 Aug, in the body) v0.10.8 (23 Aug)
    total_cross_edges 117 135
    edges originating in the source project 40 43
    distinct url_path values among them 20 25
    absolute-external noise (httpbin.org, example.com) 3 3

    The source repo grew from ~31k to ~52k nodes between the two runs, so the totals are not directly comparable — but the shape is identical.

    This time I audited every path carrying more than one edge, rather than sampling seven. That is 9 paths and 27 of the 43 edges, and 9 of 9 are defined by the source project itself:

    url_path edges defined in the calling repo at
    /api/clientes-externos 6 modules/cliente/router.py:35,49
    /api/proveedores 6 modules/compra/router.py:135 — APIRouter(prefix="/api/proveedores")
    /api/tasks + /api/tasks:qs 5 modules/tasks/router.py:32
    /productos-generales/{listar,clasificar,reclasificar,clasificacion-stats} 8 routers/productos_generales.py:49 — APIRouter(prefix="/api/productos-generales")
    /api/facturas 2 modules/compra/router.py:3164

    The remaining 13 edges are single-edge paths I did not audit; several are plainly third-party APIs (/oauth/token, and two DIAN portal endpoints), so I am not claiming they are false. The claim is narrower and firmer than the body's: 27 of 43 edges resolve to a path the calling repo defines itself, verified against the route definition, with no sampling.

    Two details from this run that are not in the issue body:

    The callers are all inside the calling project. Grouped by sub-project, the 43 edges originate in backend (14), frontend-app (12), reportes (11), recepcion-pos (4), workers (1) and admin (1) — that is, the service's own four frontends calling their own API, plus its own backend and workers. Not one originates anywhere else.

    The match is method-agnostic. Every target node is synthetic and carries ANY as the method:

    caller: …kumo-app.frontend-app.src.lib.services.api.proveedores.crear
    target: __route__ANY__/api/proveedores
    

    So the resolution is not merely path-only, it is path-only with the HTTP method discarded. A POST /api/proveedores caller binds to a route node that does not claim to be a POST route. If method were carried through, it would not fix the collision — GET /health collides on both — but it is worth knowing that the matching key is even weaker than "method and path".

    On #1133's flaky worker crash, one honest note: this run succeeded on the first attempt, in 17.0 s. That is a single sample against the 9-successes-in-25-invocations matrix in the body, taken on a different release and a repo that has since grown 68%. I am not reporting it as fixed — one run cannot show that — only that I did not have to retry to get these numbers.

    6. The ordering hazard is no longer a prediction — it started two weeks ago

    This is the part I'd ask maintainers to weigh above anything else in this comment, including my answers above.

    When this issue was filed on 5 August, the hazard was stated in the future tense: if route extraction improves before route-ownership resolution, affected fleets flip from silently-zero to silently-wrong. Route extraction has since improved at least twice, in shipped releases:

    release date change
    v0.10.0 10 Aug JS/TS template-literal URLs flatten to {} placeholders "so route rendezvous works"
    v0.10.5 15 Aug Go routes built by string concatenation now resolve (base + "/orders")

    Both are good changes and I'm glad they landed. But they are the flip: a Go fleet whose handlers were registered by concatenation had no usable route paths before v0.10.5 and has them now, which is precisely the transition from "no collisions are possible" to "collisions land and are reported as total_cross_edges". /health assembled as base + "/health" is not an exotic construction.

    Across those same two weeks this issue received no maintainer comment and carries no milestone, and #1428 has not been moved since 5 August. I don't read that as neglect — the release cadence here is remarkable and the 0.10.x notes are full of careful work. But the sequencing this issue asked for is the one thing that cannot be recovered after the fact: once the edges are in people's stores they look like architectural facts, and nobody audits a field named total_cross_edges.

    @DeusData maintainers — the ask is narrow. Fix (1) is "prefer the caller's own project", it removes all 27 of the audited edges in section 5, and its acceptance criterion can be a single path (GET /health defined in two indexed projects, caller in one of them, expect no cross edge). Everything else in this thread, including the deployment-binding contract above, can queue behind it.

    The pair stays indexed on this machine; I'm happy to re-run the same audit against main or any RC and post the delta, if that helps whoever picks this up.

  5. sorcrr-dev commented on Aug 24, 2026

    @sorcrr-dev

    @junk151516 thank you — this was useful, and we adopted the two boundaries you recommended.

    We have now completed the internal prototype and a full seven-repository rebuild. This remains unpublished local work, not a proposed upstream branch, but it gives us a second implementation/data point.

    What we implemented

    We kept the two changes separate in the implementation history:

    1. Correctness floor: resolve all candidates before writing; prefer a caller-local Route; honor an exact target_project; include the HTTP method; require the provider Route and its HANDLES edge; and emit no edge when more than one non-local project remains plausible.
    2. Gateway capability layer: an opt-in, SHA-256-fenced binding artifact carries public and provider method/path, exact target project, revision, aliases/wrappers, provenance, and confidence. A stale binding fails closed rather than falling back to heuristic path matching.

    HTTP_CALLS remains intact. CROSS_HTTP_CALLS is additive and copies the binding evidence, including target_project, provider_handler, public/provider paths, via, source/config revisions, provenance, and confidence. Missing target project, provider Route, HANDLES, dynamic path, and ambiguity are diagnostics rather than guessed edges.

    The focused acceptance set covers duplicate routes in two projects, method/path rewrites, literal and aliased gateway URLs, templates, query/trailing-slash normalization, direct provider URLs, wrappers, missing handlers, stale revisions, and a real caller-to-provider-handler golden path. Final focused ASan/UBSan result was 236 passed with six platform skips; the optimized build/link also passed. Independent review found and closed two additional issues before acceptance: file-wide this.* alias ownership crossing classes, and a qualified-name length check that could otherwise read past a shorter string.

    Measured result

    After a full rebuild of the seven pinned projects followed by one cross-repo pass per source, the store contains:

    • 196 CROSS_HTTP_CALLS edges;
    • two other cross-channel edges;
    • zero ambiguous-target edges;
    • zero unresolved-dynamic-path cases at the cross-resolution stage;
    • three missing-target-project diagnostics;
    • 2,327 missing-provider-Route and 25 missing-HANDLES diagnostics, all retained as non-edge evidence.

    Those diagnostic totals are scan-level counters, not production failures; the important property is that they did not become cross edges.

    I cannot give you an honest comparable pre/post fleet total: the accepted rebuild also materially broadened NestJS route and HTTP-call extraction, and we did not preserve the old canonical stores before replacing them. Quoting the old total beside 196 would conflate resolver correctness with new extraction coverage. The bounded collision regression is comparable: the old behavior could bind a caller to each project exposing the same route; the new behavior produces the exact declared target or zero edges, never the collision candidates.

    Findings and open questions

    • Your proposed CALL_REFERENCE/include_evidence analogy still looks right. Our prototype exposes stable diagnostic counters but does not yet persist the rejected candidate set. A reference/evidence surface would be the useful next step; a “guess anyway” write toggle would not.
    • In the current two-store representation, a forward CROSS_HTTP_CALLS edge terminates at a local Route projection and carries the remote target_project, provider_handler, and provider file as properties. Consumers must read those properties rather than infer the business destination from the target node alone. It would be helpful to know whether upstream considers that representation intentional or would prefer a first-class remote-handler/reference shape.
    • Staleness needs a first-class reason in ordinary status/index output, not just a log line, because a fenced artifact must never silently lose authority and degrade to heuristic matching.
    • We agree the small caller-local/fail-closed resolver correction should land independently of any gateway-binding feature. If maintainers want the latter discussed further, we can open a separate focused issue that cites cross-repo-intelligence: CROSS_HTTP_CALLS resolves by URL path alone, emitting false cross-service edges when two indexed projects expose the same path #1459 as its prerequisite and share the sanitized artifact contract and acceptance matrix there.

    We also updated our agent guidance accordingly: graphs are materialized navigation views bound to exact roots, heads, generations, binary, and manifest; source and runtime remain authoritative, and cross-repo stores are replenished by fully indexing all pinned projects before running cross-repo resolution.

  6. added
    bugSomething isn't working
    maintainer-notesInternal observations and improvement notes
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    and removed
    cypherCypher query language parser/executor bugs
    windowsWindows-specific issues
    on Aug 24, 2026
  7. DeusData commented on Aug 24, 2026

    @DeusData
    Owner

    Thank you for the current-release remeasurement, the exhaustive caller-local audit, and the concrete acceptance case. The report establishes a high-impact correctness problem: path-only cross-project matching can persist an architectural claim that the caller project itself disproves.

    The small caller-local and fail-closed correction, the persisted evidence shape, and the proposed opt-in gateway binding are related but materially different design decisions. We need more time to review those boundaries before choosing or inviting an implementation. I have marked the correctness issue high priority and routed the design questions for maintainer review. Thank you for keeping the measured evidence distinct from predicted collisions and for offering a reproducible retest.

  8. DeusData commented on Sep 25, 2026

    @DeusData
    Owner

    Thank you @junk151516 for splitting this out so carefully and for the measured audit, and @HungChu for correcting the fleet inventory in public; the /health case makes the precondition plain.

    The correctness floor you proposed as fix (1) is up as #2319: the cross-repo pass now checks the caller's own project first. If the caller's project handles the route the call resolves to, no CROSS_HTTP_CALLS edge is created, in either run direction. "Handles" uses the same exact-method → ANY → template lookup as the target side. That matters because a method-less fetch('/api/users') attaches to a different Route node than the local app.get handler, and a check on that node alone would have missed your exact case. Calls with no local handler still cross as before.

    The rest of this issue stays open: surfacing ambiguity or provenance on the edge (your fix 2) and the opt-in gateway binding @sorcrr-dev described. #2319 will land before the NestJS route extraction (#2320), as requested.

  9. added a commit that references this issue on Sep 30, 2026
  10. DeusData commented on Sep 30, 2026

    @DeusData
    Owner

    Thank you again, @junk151516! #2319 is now merged to main as 2bed1c8 and covers part of this issue. We're keeping the issue open for the remaining work and will post here as it lands.

  11. NeoGeoSNK commented on Oct 22, 2026

    @NeoGeoSNK

    A sanitized current-release example of the false-edge behavior described here:

    • Environment: codebase-memory-mcp 0.12.1, Linux x86_64 / WSL2; separately indexed TypeScript/Electron client and Java/Spring API projects.
    • The client graph contains an HTTP_CALLS entry from a .spec.ts module marked is_test=true. Its recorded callee is a test assertion checking a mocked Axios call to https://<host>/version-info; the test stubs Axios, so this is not an outbound request to the API project.
    • A second entry comes from a CI workflow's curl readiness probe to the client's own loopback dev server (GET / at 127.0.0.1:<dev-port>).
    • The API-side graph nevertheless contains two CROSS_HTTP_CALLS records for these sources: the test URL is linked to a generic GET /{id} route, and the local dev-server probe is linked to GET /. The client-side graph has no corresponding records.

    These are test/CI artifacts, not runtime client-to-API calls. The observed cross edges show that the path match still accepts unrelated candidates despite their non-production provenance and different host context. A sanitized Spring route-prefix example is also reported in #734.

  12. DeusData commented on Oct 25, 2026

    @DeusData
    Owner

    Thank you for the new 0.12.1 example distinguishing mocked test calls and loopback CI probes from runtime API traffic. That evidence needs maintainer follow-through beyond the earlier caller-local correction. Sorry for the delay; this is waiting on maintainer follow-up, and I’ll follow up soon.

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 workingmaintainer-notesInternal observations and improvement notesparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.stability/performanceServer crashes, OOM, hangs, high CPU/memoryux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions