Skip to content

fix(cross-repo): normalize URLs, match templates, run both directions#810

Merged
DeusData merged 3 commits into
mainfrom
distill/536-cross-repo
Jul 4, 2026
Merged

fix(cross-repo): normalize URLs, match templates, run both directions#810
DeusData merged 3 commits into
mainfrom
distill/536-cross-repo

Conversation

@DeusData

@DeusData DeusData commented Jul 3, 2026

Copy link
Copy Markdown
Owner

fix(cross-repo): normalize URLs, match templates, run both directions

Distills the still-valid half of #536 (thanks @RithvikReddy0-0 — co-credited on the commit).
Refs #523.

Summary

cbm_cross_repo_match / match_http_routes had three matcher gaps that made
cross-repo-intelligence report 0 edges for perfectly matching call/route pairs:

  1. Full URLs never matched. url_path on HTTP_CALLS edges is stored raw from the
    call's first string argument, so it can be http://svc:8080/v2/orders.
    cbm_route_canon_path only canonicalizes placeholder syntax — it never strips
    scheme/authority (verified at src/pipeline/pass_route_nodes.c:59) — so the built
    route QN embedded the host and the exact lookup missed.
    → new cr_url_path() strips scheme://host[:port] first; a bare base URL maps to
    the root path / (consistent with url_path() in pass_route_nodes.c).
  2. Concrete paths never matched templated routes. /v2/orders/123 cannot
    exact-match __route__GET__/v2/orders/{}.
    → new cr_path_matches_template() + find_route_handler_fuzzy(): segment-wise
    template matching, method-gated (route method must equal the caller's or be ANY),
    run only for edges the exact lookup missed, and only accepting Route nodes that
    actually carry a HANDLES edge. Cost is O(calls × routes) per project pair
    (documented in the code; calls are capped at CR_MAX_EDGES).
  3. Matching only ran consumer→provider. A provider-side run found nothing (the
    provider has no outbound HTTP_CALLS) — and worse, destroyed existing links:
    delete_cross_edges wiped the provider's reverse edges at the start of the run and
    nothing recreated them.
    → the pass now also runs match_http_routes(tgt→src). The two directions scan
    disjoint HTTP_CALLS sets (a caller edge lives in exactly one DB), so no pair is
    double-counted.

Taken / dropped / corrected from #536

#536 piece Verdict Why
src/pipeline/pass_calls.c hunk (emit HTTP_CALLS for unindexed client libs) Dropped Superseded by beaa776 already on main — broader fix that also covers the parallel pipeline path.
cr_url_path() scheme/host stripping Taken (adjusted) Core of the fix. Adjusted to return / for a bare base URL (PR returned the unstripped URL, a silent never-match) — consistent with the existing url_path() helper in pass_route_nodes.c.
cr_path_matches_template() + find_route_handler_fuzzy() Taken (adjusted) Design kept as-is (incl. the handler-ful-match scan rationale). Adjustments: fuzzy matcher receives the canonicalized stripped path (handles client paths mixing placeholders and concrete segments); dropped the LIKE '__route__%' SQL prefilter (_ is a SQL wildcard, so it was a misleading no-op next to the label filter + strncmp prefix guard); magic numbers replaced with named enum constants.
Reverse-direction match_http_routes run Taken Fixes both the provider-side 0-edges symptom and the provider-side edge destruction.
Idempotent insert_cross_edge (pre-insert SELECT + inserted-flag counting) Dropped (documented instead) The edges table is UNIQUE(source_id, target_id, type) and cbm_store_insert_edge upserts on conflict — duplicate rows are impossible; the guard was a redundant query per insert. Its "rows actually added" count semantics would also make a provider-side re-run report http_edges=0 for an already-recorded link — the exact symptom #523 complains about. Counting stays "matches found" (stable across directions and re-runs); the convergence test pins row uniqueness.

Tests (reproduce-first, tests/repro/repro_issue523.c)

All four were RED on the unfixed tree (verified by reverting src/pipeline/pass_cross_repo.c and re-running) and are GREEN with the fix:

Test Scenario RED on unfixed code
repro_issue523_scheme_stripped_url_match client calls http://order-api.internal:8080/v2/orders, server route /v2/orders http_edges (0) not >= 1
repro_issue523_template_fuzzy_match client calls /v2/orders/123, server route /v2/orders/{order_id} http_edges (0) not >= 1
repro_issue523_reverse_direction_match provider-side cbm_cross_repo_match(server, [client]) http_edges (0) not >= 1
repro_issue523_idempotent_cross_edges consumer run → provider run → consumer run; every DB must hold exactly 1 CROSS_HTTP_CALLS row after each run server_2 == 0, expected 1 (provider-side run destroyed the link)

The pre-existing repro_issue523_crossrepo_http_calls_edge (pass_calls half, fixed by beaa776) stays green.

Verification

  • make -f Makefile.cbm cbm-Werror clean
  • make -f Makefile.cbm lint-ci — cppcheck + clang-format + NOLINT check pass
  • CBM_REPRO_ONLY=repro_issue523 ./build/c/test-repro-runner — 5 passed, 0 failed
  • full gating suite ./build/c/test-runner — 5765 passed, 0 failed

Refs #523

DeusData and others added 2 commits July 3, 2026 19:53
Distills the pass_cross_repo.c half of #536; the pass_calls.c half landed
separately as beaa776 (broader: covers the parallel path too).

match_http_routes could not match a stored HTTP_CALLS url_path that was a
full URL (scheme://host:port/path is stored raw from the call's first
string argument), never matched a concrete client path against a templated
route QN, and only ran consumer->provider, so a provider-side run found
nothing - and worse, destroyed previously recorded links: delete_cross_edges
wiped the provider's reverse edges and nothing recreated them.

- cr_url_path(): strip scheme://host[:port] before route-QN construction;
  a bare base URL maps to the root route path.
- cr_path_matches_template() + find_route_handler_fuzzy(): segment-wise
  fallback so /v2/orders/123 matches /v2/orders/{} (method-gated, only for
  edges the exact lookup missed; O(calls x routes) per project pair,
  bounded by CR_MAX_EDGES).
- Reverse-direction match_http_routes run so provider-side invocations
  find the consumer's HTTP_CALLS and re-create the wiped reverse edges.
  Row dedup needs no insert guard: the edges table upserts on its
  (source_id, target_id, type) UNIQUE key.

Four reproduce-first tests in tests/repro/repro_issue523.c (scheme-strip,
template fuzzy match, provider-side run, bidirectional convergence), all
red on the previous code, green with the fix.

Refs #523

Co-authored-by: RithvikReddy0-0 <rithvikreddymukkara@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The hardcoded-URL security audit flags http:// literals in src/; the comment
only illustrates the shape of stored url_path values.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData
DeusData enabled auto-merge July 3, 2026 22:38
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData
DeusData merged commit 4cd8d3e into main Jul 4, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant