fix(extractors): resolve 3 silent contract mis-resolution bugs (#793)#817
Conversation
Addresses Codex adversarial review findings for extractor contract resolution on the new group extractor surface. F1 (manifest-extractor): resolveSymbol passed the full "METHOD::path" contract string through normalizeRoutePath, producing "/GET::/api/orders" which never matches Route.name. Adds parseHttpContract() helper that strips the METHOD:: prefix before path normalization. Contract ID construction (buildContractId) is unchanged. F2 (http-route-extractor): graph-assisted backfill used path-only detections.find(), so multi-verb same-URL files attached the wrong verb/handler to provider rows and inferred the wrong verb on FETCHES consumer edges. Now requires path+method match when method is known, and skips backfill when method is unknown and multiple detections tie on path. F3 (grpc-extractor): resolveProtoConflict seeded bestScore=-1 and only replaced on strict >, so all-zero-score ties silently selected candidates[0]. Now computes all scores, counts ties at the top score, and returns null on ambiguity (caller skips contract emission and warns with service name + candidate paths). All three fixes are test-first; 73 tests pass across the three suites. No schema changes, no new dependencies, contract ID wire format (http::METHOD::path, grpc::pkg.Service/Method, http::*::path) preserved.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@ivkond Would you be able to review these changes? |
CI Report✅ All checks passed Pipeline Status
Test Results
✅ All 6214 tests passed 97 test(s) skipped — expand for details
Code CoverageTests
📋 View full run · Generated by CI |
There was a problem hiding this comment.
Pull request overview
Fixes three extractor-edge-case bugs that caused silent contract mis-resolution in the group graph (manifest HTTP METHOD::path parsing, HTTP multi-verb same-path backfill, and gRPC proto conflict resolution), with targeted unit coverage to prevent regressions.
Changes:
- Add
parseHttpContract()and stripMETHOD::before normalizing/looking up HTTP routes inManifestExtractor. - Disambiguate graph-assisted HTTP backfill by requiring method+path matches when method is known, and refusing to guess when ambiguous.
- Make gRPC proto conflict resolution return
nullon ambiguous ties (with a warning) and skip emitting contracts in that case.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| gitnexus/src/core/group/extractors/manifest-extractor.ts | Adds helper to parse METHOD::path and fixes HTTP route lookup normalization. |
| gitnexus/src/core/group/extractors/http-route-extractor.ts | Fixes graph-assisted provider/consumer backfill to avoid .find() path-only mis-attribution in multi-verb cases. |
| gitnexus/src/core/group/extractors/grpc-extractor.ts | Refuses ambiguous proto conflict resolution and prevents emitting contracts on ambiguity. |
| gitnexus/test/unit/group/manifest-extractor.test.ts | Adds regression/edge-case coverage for explicit-method HTTP manifest contracts. |
| gitnexus/test/unit/group/http-route-multi-verb.test.ts | New suite covering multi-verb same-path backfill behavior (provider + consumer). |
| gitnexus/test/unit/group/grpc-extractor.test.ts | Adds tie/ambiguity tests for proto resolution and extraction behavior when ambiguous. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@claude is this pr ready for production? Is this following clean code principles? Are there any performance bottlenecks? Is the code structured in a way that will unlock easy contributions in the future? |
|
Claude finished @magyargergo's task in 2m 8s —— View job PR ReviewTasks:
Verdict: Not quite ready — one unresolved bug + CI failure needs addressingThe fixes for F1 and F3 are solid and the test coverage is well-designed. F2 has a partial regression that needs one more change before this is safe to merge. CI FailureThe CI failure is not a typecheck failure (the CI report comment above was slightly misleading — typecheck actually passed). The real failure is a Prettier formatting issue in two files unrelated to this PR: These are pre-existing unformatted files from a different PR. This PR shouldn't be blocked by them, but the CI Gate will reject the merge until they're fixed (either here or separately). The author should coordinate with whoever owns those files or fix the formatting as a separate commit. Bug: F2 Fix Is Incomplete (Significant)Copilot's first comment identifies a real regression that the PR author should address.
// handlerName is null when match is undefined (ambiguous multi-verb case)
if (match) {
if (!method) method = match.method;
handlerName = match.name;
}
// ...
const picked = pickSymbolUid(syms, handlerName); // ← called with nullWhen The fix is straightforward: skip the symbol enrichment entirely when the match was ambiguous, or use a sentinel that Bug:
|
| Area | Status |
|---|---|
| Production readiness | |
| Clean code | ✅ Strong — good naming, comments, and structure |
| Performance | ✅ No new bottlenecks introduced |
| Contribution-friendliness | ✅ Good — plugin extension point is documented, tests are clear |
Must fix before merging:
- The ambiguous-match case in
extractProvidersGraphstill passesnulltopickSymbolUid, which silently picks the first symbol in the file (Copilot comment Add support for Ollama as a local inference backend #1).
Should fix before merging:
2. buildContractId casing inconsistency for lowercase METHOD:: prefixes (Copilot comment #2).
3. Prettier failures in gitnexus-web need to be resolved (can be a separate PR/commit).
…tract id casing Copilot + Claude review on PR #817 flagged two follow-up bugs on top of the F1/F2/F3 fixes: 1. http-route-extractor: ambiguous multi-verb case left handlerName null but still ran the CONTAINS DB query. pickSymbolUid(syms, null) then silently picked pool[0] — reintroducing handler mis-attribution via a different route than the .find() bug F2 fixed. Now gates symbol enrichment on an ambiguousCandidates flag so the file-basename fallback wins instead. 2. manifest-extractor: buildContractId passed raw user casing through for the explicit-method form, so get::/api/orders and GET::/api/orders produced different contract ids even though parseHttpContract upper-cases during lookup. Now reuses parseHttpContract + normalizeRoutePath to canonicalize both method and path, so logically equivalent manifest inputs share a contract id (and share a manifestSymbolUid fallback). Adds one regression test per bug: lowercase vs uppercase manifest contract ids must match, and ambiguous multi-verb with CONTAINS rows must not silently attach a real handler or call the CONTAINS query at all. 75 tests pass across the three extractor suites.
…yanpatwari#793) (abhigyanpatwari#817) * fix(extractors): resolve 3 silent contract mis-resolution bugs (abhigyanpatwari#793) Addresses Codex adversarial review findings for extractor contract resolution on the new group extractor surface. F1 (manifest-extractor): resolveSymbol passed the full "METHOD::path" contract string through normalizeRoutePath, producing "/GET::/api/orders" which never matches Route.name. Adds parseHttpContract() helper that strips the METHOD:: prefix before path normalization. Contract ID construction (buildContractId) is unchanged. F2 (http-route-extractor): graph-assisted backfill used path-only detections.find(), so multi-verb same-URL files attached the wrong verb/handler to provider rows and inferred the wrong verb on FETCHES consumer edges. Now requires path+method match when method is known, and skips backfill when method is unknown and multiple detections tie on path. F3 (grpc-extractor): resolveProtoConflict seeded bestScore=-1 and only replaced on strict >, so all-zero-score ties silently selected candidates[0]. Now computes all scores, counts ties at the top score, and returns null on ambiguity (caller skips contract emission and warns with service name + candidate paths). All three fixes are test-first; 73 tests pass across the three suites. No schema changes, no new dependencies, contract ID wire format (http::METHOD::path, grpc::pkg.Service/Method, http::*::path) preserved. * fix(extractors): address PR abhigyanpatwari#817 review — ambiguous symbol pick + contract id casing Copilot + Claude review on PR abhigyanpatwari#817 flagged two follow-up bugs on top of the F1/F2/F3 fixes: 1. http-route-extractor: ambiguous multi-verb case left handlerName null but still ran the CONTAINS DB query. pickSymbolUid(syms, null) then silently picked pool[0] — reintroducing handler mis-attribution via a different route than the .find() bug F2 fixed. Now gates symbol enrichment on an ambiguousCandidates flag so the file-basename fallback wins instead. 2. manifest-extractor: buildContractId passed raw user casing through for the explicit-method form, so get::/api/orders and GET::/api/orders produced different contract ids even though parseHttpContract upper-cases during lookup. Now reuses parseHttpContract + normalizeRoutePath to canonicalize both method and path, so logically equivalent manifest inputs share a contract id (and share a manifestSymbolUid fallback). Adds one regression test per bug: lowercase vs uppercase manifest contract ids must match, and ambiguous multi-verb with CONTAINS rows must not silently attach a real handler or call the CONTAINS query at all. 75 tests pass across the three extractor suites. * chore: prettier formatting
Closes #793
Addresses three high-severity findings from the Codex adversarial review of the new group extractor surface. All three bugs cause silent contract mis-resolution — no exceptions, just wrong contract IDs baked into the graph that downstream cross-impact bridge queries then join through.
Summary
manifest-extractor.ts:resolveSymbolpassed the fullMETHOD::pathcontract string throughnormalizeRoutePath, producing/GET::/api/orderswhich can never matchRoute.name. Every explicit-method manifest link silently fell back to a synthetic UID. Fix: newparseHttpContract()helper strips theMETHOD::prefix before path normalization.buildContractIdis unchanged.http-route-extractor.ts: graph-assisted backfill (both provider and consumer paths) used path-onlydetections.find(), so multi-verb same-URL files attached the wrong verb/handler to provider rows and inferred the wrong verb onFETCHESconsumer edges. Fix: require path+method match when method is known; skip backfill when method is unknown and multiple detections share the same path.grpc-extractor.ts:resolveProtoConflictseededbestScore = -1and only replaced on strict>, so all-zero-score ties silently selectedcandidates[0]. Fix: compute all scores, count ties at the top score, returnnullon ambiguity. Caller skips contract emission and warns with service name + candidate proto paths.Test plan
gitnexus/test/unit/group/manifest-extractor.test.ts— explicit-method manifest links now resolve to real Route nodesgitnexus/test/unit/group/http-route-multi-verb.test.ts(new) — multi-verb same-URL backfill picks the right verb or refusesgitnexus/test/unit/group/grpc-extractor.test.ts— tie/ambiguous proto resolution refuses rather than picking arbitrarily