Version
dev build from source at 4da8f877 (tag v0.10.8 lineage). I am 19 commits behind origin/main; none of those 19 touch internal/cbm/service_patterns.c, src/pipeline/pass_cross_repo.c, or any Swift front-end file, and my own local commits do not touch them either. So this should reproduce on stock main.
Platform
macOS (Apple Silicon) — macOS 26.6.2, arm64
Install channel
Built from source
Binary variant
standard
What happened, and what did you expect?
A Swift client that calls an HTTP endpoint produces no HTTP_CALLS edge and no client-side Route node, so mode=cross-repo-intelligence can never link it to the server that serves that path. A TypeScript client making the byte-identical call links correctly.
Swift is not missing from the pattern table. internal/cbm/service_patterns.c lines 109-112 already carry:
/* Swift */
{"Alamofire", CBM_SVC_HTTP, NULL},
{"Moya", CBM_SVC_HTTP, NULL},
{"URLSession", CBM_SVC_HTTP, NULL},
The gap is one step earlier: the Swift front end never emits the client-side Route node + HTTP_CALLS edge carrying a url_path that the cross-repo matcher joins on.
I expected the Swift client to behave like the TypeScript one — an HTTP_CALLS edge with url_path=/api/v1/widgets, and a CROSS_HTTP_CALLS edge naming the Go handler.
Note on #523, which asks "what is the minimum a call and a route need to share to be linked?" — the TypeScript half of this repro answers that, and shows the matcher itself is working. This report is the opposite failure: the matcher is fine, one language front end never feeds it. Not a duplicate of #523, #678, #706 (those are matcher/extractor bugs where the call side does produce an edge), nor of #551 (SwiftPM manifest resolution for package-graph edges, a different pass).
Reproduction
Three tiny repos, all declaring the same path /api/v1/widgets. The only variable is the client language. Script attached below; it writes the fixtures and prints the five MCP calls to make.
Results:
| Repo |
Language |
Route nodes |
HTTP_CALLS |
CROSS_HTTP_CALLS to server |
srv-go |
Go + chi |
2 |
— |
— |
cli-ts |
TypeScript + axios |
2 |
2 |
2 |
cli-swift |
Swift + URLSession |
0 |
0 |
0 |
TypeScript, working — MATCH ()-[r:CROSS_HTTP_CALLS]->() RETURN ...:
url_path target_project target_file target_function transport
/api/v1/widgets xtest-srv-go main.go listWidgets GET
/api/v1/widgets xtest-srv-go main.go createWidget POST
Swift, same path: cross_http_calls: 0, total_cross_edges: 0.
Graph schema for the Swift fixture shows no Route label and no HTTP_CALLS edge type. Its only edge for the URLSession call is a bare USAGE — no CALLS edge is emitted at all.
repro-swift-http.sh
#!/usr/bin/env bash
# Reproduce: a Swift client produces no HTTP_CALLS, so cross-repo-intelligence
# finds no edges. A TypeScript client with the identical path produces both.
# Builds three tiny repos, then index each and run cross-repo-intelligence.
set -euo pipefail
B="${1:-/tmp/xrepo}"
rm -rf "$B"; mkdir -p "$B"/srv-go "$B"/cli-ts "$B"/cli-swift
cat > "$B/srv-go/go.mod" <<'EOF'
module example.com/srv
go 1.22
EOF
cat > "$B/srv-go/main.go" <<'EOF'
package main
import "github.com/go-chi/chi/v5"
func main() {
r := chi.NewRouter()
r.Get("/api/v1/widgets", listWidgets)
r.Post("/api/v1/widgets", createWidget)
http.ListenAndServe(":8080", r)
}
func listWidgets(w http.ResponseWriter, r *http.Request) {}
func createWidget(w http.ResponseWriter, r *http.Request) {}
EOF
cat > "$B/cli-ts/package.json" <<'EOF'
{ "name": "cli-ts", "version": "1.0.0", "dependencies": { "axios": "^1.6.0" } }
EOF
cat > "$B/cli-ts/client.ts" <<'EOF'
import axios from "axios";
export async function listWidgets() {
return axios.get("/api/v1/widgets");
}
export async function createWidget(body: unknown) {
return axios.post("/api/v1/widgets", body);
}
EOF
cat > "$B/cli-swift/Package.swift" <<'EOF'
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "CliSwift",
targets: [.target(name: "CliSwift", path: "Sources/CliSwift")]
)
EOF
mkdir -p "$B/cli-swift/Sources/CliSwift"
cat > "$B/cli-swift/Sources/CliSwift/Client.swift" <<'EOF'
import Foundation
final class Client {
func listWidgets() async throws -> Data {
let url = URL(string: "https://example.com/api/v1/widgets")!
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
func createWidget(body: Data) async throws -> Data {
var request = URLRequest(url: URL(string: "https://example.com/api/v1/widgets")!)
request.httpMethod = "POST"
let (data, _) = try await URLSession.shared.upload(for: request, from: body)
return data
}
}
EOF
for d in srv-go cli-ts cli-swift; do
(cd "$B/$d" && git init -q . && git add -A \
&& git -c user.email=t@t -c user.name=t commit -qm init)
done
echo "Fixtures built in $B"
echo
echo "Now, through the MCP server:"
echo " index_repository repo_path=$B/srv-go name=xtest-srv-go mode=full"
echo " index_repository repo_path=$B/cli-ts name=xtest-cli-ts mode=full"
echo " index_repository repo_path=$B/cli-swift name=xtest-cli-swift mode=full"
echo " index_repository repo_path=$B/cli-ts name=xtest-cli-ts mode=cross-repo-intelligence target_projects=[\"xtest-srv-go\"]"
echo " index_repository repo_path=$B/cli-swift name=xtest-cli-swift mode=cross-repo-intelligence target_projects=[\"xtest-srv-go\"]"
On a real project
Same shape at scale, on a 462-file / 64k-line Swift app talking to a Go backend:
|
Go + TS backend repo |
Swift client repo |
Route nodes |
332 |
label absent |
HTTP_CALLS edges |
215 |
edge type absent |
Method nodes |
2,877 |
3,766 |
CALLS edges |
20,650 |
12,017 |
Swift parsing itself is healthy — 3,766 methods, 12,017 call edges. Only the HTTP layer is missing. On the backend side the 215 HTTP_CALLS include its TypeScript frontend (frontend/lib/api/classes/items.ts alone contributes 20), so TS client extraction works in a real tree too.
In the real Swift repo the failure takes a slightly different route to the same place. A CALLS edge for the URLSession call does exist, but resolves onto a local property:
callee: URLSession.shared.data
strategy: suffix_match confidence: 0.21
resolved: <project>.HomeboxKit.Sources.HomeboxUI.PickedFile.data
file: HomeboxKit/Sources/HomeboxFeatures/Chores/ChoresDetailViewModel.swift:105
Because cbm_service_pattern_* matches the library identifier in the resolved qualified name, and the resolved name is a local PickedFile.data, the check cannot fire. The Swift graph also has no Package label at all, so no framework identifier can ever appear in a resolved name — the Go/TS project has 215 Package nodes with an external flag.
That suffix_match at 0.21 may be worth a look on its own: Swift calls into system frameworks are being resolved onto same-named local members, which affects more than the HTTP case.
Project scale (if relevant)
Repro fixtures: 6 files. Real project: 462 Swift files / 64,101 lines against a 1,485-file Go+TS backend.
Version
devbuild from source at4da8f877(tagv0.10.8lineage). I am 19 commits behindorigin/main; none of those 19 touchinternal/cbm/service_patterns.c,src/pipeline/pass_cross_repo.c, or any Swift front-end file, and my own local commits do not touch them either. So this should reproduce on stockmain.Platform
macOS (Apple Silicon) — macOS 26.6.2, arm64
Install channel
Built from source
Binary variant
standard
What happened, and what did you expect?
A Swift client that calls an HTTP endpoint produces no
HTTP_CALLSedge and no client-sideRoutenode, somode=cross-repo-intelligencecan never link it to the server that serves that path. A TypeScript client making the byte-identical call links correctly.Swift is not missing from the pattern table.
internal/cbm/service_patterns.clines 109-112 already carry:The gap is one step earlier: the Swift front end never emits the client-side
Routenode +HTTP_CALLSedge carrying aurl_paththat the cross-repo matcher joins on.I expected the Swift client to behave like the TypeScript one — an
HTTP_CALLSedge withurl_path=/api/v1/widgets, and aCROSS_HTTP_CALLSedge naming the Go handler.Note on #523, which asks "what is the minimum a call and a route need to share to be linked?" — the TypeScript half of this repro answers that, and shows the matcher itself is working. This report is the opposite failure: the matcher is fine, one language front end never feeds it. Not a duplicate of #523, #678, #706 (those are matcher/extractor bugs where the call side does produce an edge), nor of #551 (SwiftPM manifest resolution for package-graph edges, a different pass).
Reproduction
Three tiny repos, all declaring the same path
/api/v1/widgets. The only variable is the client language. Script attached below; it writes the fixtures and prints the five MCP calls to make.Results:
RoutenodesHTTP_CALLSCROSS_HTTP_CALLSto serversrv-gocli-tscli-swiftTypeScript, working —
MATCH ()-[r:CROSS_HTTP_CALLS]->() RETURN ...:Swift, same path:
cross_http_calls: 0, total_cross_edges: 0.Graph schema for the Swift fixture shows no
Routelabel and noHTTP_CALLSedge type. Its only edge for the URLSession call is a bareUSAGE— noCALLSedge is emitted at all.repro-swift-http.sh
On a real project
Same shape at scale, on a 462-file / 64k-line Swift app talking to a Go backend:
RoutenodesHTTP_CALLSedgesMethodnodesCALLSedgesSwift parsing itself is healthy — 3,766 methods, 12,017 call edges. Only the HTTP layer is missing. On the backend side the 215
HTTP_CALLSinclude its TypeScript frontend (frontend/lib/api/classes/items.tsalone contributes 20), so TS client extraction works in a real tree too.In the real Swift repo the failure takes a slightly different route to the same place. A
CALLSedge for the URLSession call does exist, but resolves onto a local property:Because
cbm_service_pattern_*matches the library identifier in the resolved qualified name, and the resolved name is a localPickedFile.data, the check cannot fire. The Swift graph also has noPackagelabel at all, so no framework identifier can ever appear in a resolved name — the Go/TS project has 215Packagenodes with anexternalflag.That
suffix_matchat 0.21 may be worth a look on its own: Swift calls into system frameworks are being resolved onto same-named local members, which affects more than the HTTP case.Project scale (if relevant)
Repro fixtures: 6 files. Real project: 462 Swift files / 64,101 lines against a 1,485-file Go+TS backend.