mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-06 08:16:02 +00:00
452 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c978c9b3d4
|
Merge branch 'main' into optimize/go-scope-capture | ||
|
|
a93ecee068
|
fix(group): recognize OpenFeign @RequestLine on plain interfaces (no @FeignClient) (#1917)
* fix(group): recognize OpenFeign @RequestLine on plain interfaces (no @FeignClient) PR #1904 gated @RequestLine consumer extraction on the enclosing interface also carrying @FeignClient. That guard is wrong: @RequestLine is a core feign.* annotation used with Feign.builder(), while @FeignClient is the Spring Cloud variant that uses Spring MVC annotations (@GetMapping etc.) — the two are effectively mutually exclusive. Requiring @FeignClient therefore excluded the annotation's primary, canonical usage, so the feature recognized nothing on real core-Feign client interfaces. Fix: drop the @FeignClient requirement for @RequestLine. The match still requires an enclosing interface (Feign proxies are always interfaces), and the `RequestLine` annotation name is itself a strong, framework-specific signal, so false-positive risk stays low. A @FeignClient(path=...) prefix is still applied when present. The @(Get|Post|...)Mapping consumer path keeps its @FeignClient requirement: those annotations are generic Spring MVC and need the Feign context to be disambiguated from provider routes. Verification (real-world, not just synthetic fixtures): - A real client-jar consumer (BigModeClientService.java: a plain interface with 12 @RequestLine methods, no @FeignClient) now yields 12 openfeign consumer contracts; it yielded 0 before this change. - End-to-end `group sync` over that consumer repo + its FastAPI provider repo (with zero hand-written links) produces 12 exact cross-links (confidence 1.0), Java @RequestLine consumer → Python route provider. - The prior test that asserted the wrong behavior ("ignores @RequestLine on interfaces without @FeignClient") is reversed into a realistic core-Feign fixture. - Full test/unit/group suite (579) green; tsc and prettier clean. * test(group): add negative cases for relaxed @RequestLine matcher Per review on #1917 — guard the no-@FeignClient relaxation with explicit negative tests: malformed @RequestLine values (no verb / no leading-slash path / unknown verb) yield no contract, and @RequestLine on a concrete class method (not an interface) is not emitted as a consumer. --------- Co-authored-by: henry <zhangwei2017@unipus.cn> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> |
||
|
|
b9008024ab |
fix(test): remove TOCTOU file-system race in golden test + format
CodeQL flagged a high-severity 'potential file system race condition': the golden test did fs.existsSync(GOLDEN_FILE) then later writeFileSync/readFileSync on it. Replace the existsSync-then-use with a single race-free read (ENOENT => missing), reusing the read content for the compare path. Behaviour is unchanged (the pure resolveGoldenAction helper still decides regenerate/compare/fail). Also applies prettier formatting to the file (fixes the quality/format check). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
cfe4e49c41 |
test(go): strengthen func_literal smoke case to a positive receiver assertion (#1848 U3)
The old case used a closure-only source and only asserted ABSENCE of @type-binding.self, so it would pass even if the method_declaration receiver branch regressed (Codex F3). The fixture now has both a method and a closure, and positively asserts exactly one @type-binding.self from the method (name=u, type=User — the type also confirms *User pointer-stripping) and none from the closure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1e2aaeabf9 |
test(go): make the golden digest order-sensitive (#1848 U2)
Drops the cross-match .sort() in digestCaptures so the digest reflects emission order — a true byte-identical guard that catches a reordering refactor (Codex F1), not just a set-equality check. Safe because emitGoScopeCaptures output is deterministic. Within-match key order stays normalized (a CaptureMatch is a Record). Replaces the order-independence test with an order-sensitivity assertion and regenerates expected-captures.json under the new scheme (all 90 digests). Trade-off: a tree-sitter-go grammar bump that reorders matches now requires a deliberate UPDATE_GOLDEN=1 regen — intentional (a tree-shape change deserves a look). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
fa8033859f |
test(go): fail on a missing golden in CI via a pure resolveGoldenAction helper (#1848 U1)
Extracts the golden test's missing-file gate into a pure
resolveGoldenAction({update,exists,isCI}) -> regenerate|compare|fail helper, so
a missing golden no longer self-heals + passes in CI (Codex F2). The rule is
unit-tested directly across all combos with no filesystem mutation (can't corrupt
the committed golden). CI detection uses a truthy check (!!process.env.CI) so it
fires on any runner. Locally a missing golden still regenerates as first-run convenience.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
2cb39bc09b | chore(autofix): apply prettier + eslint fixes via /autofix command | ||
|
|
05e67c683f
|
Merge branch 'main' into optimize/go-scope-capture | ||
|
|
66daf27910
|
feat(cli): add --uid/--file/--kind disambiguation flags to impact (#1907) (#1914)
* feat(cli): add --uid/--file/--kind disambiguation flags to impact (#1907) When `impact` reports an ambiguous target it tells the user to disambiguate, but the CLI had no way to do so — only the MCP impact tool accepted target_uid/file_path/kind (the CLI `context` command had --uid/--file, `impact` had neither). Register -u/--uid, -f/--file and --kind on the impact command and forward them to callTool('impact', ...) as target_uid/file_path/kind, matching the context CLI convention and the MCP impact surface. Help text and the usage hint are localized in en + zh-CN. Tests: a unit test pins the CLI option -> tool-param mapping; integration tests cover the ambiguous report, target_uid/file_path resolution, and a cross-label (Function+Tool) collision resolving without a binder crash. Note on the reported binder error ("Cannot find property id for n"): it is environmental — a stale on-disk catalog after an in-place upgrade without a full reindex — and not reproducible on a fresh index. Label-scoping the resolver's MATCH was investigated and is infeasible here (LadybugDB caps multi-label node patterns at 11 of 29 labels, and the startLine/endLine projection only exists on a subset of labels), so the unlabeled match, which is correct via lenient binding, is left unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(autofix): apply prettier + eslint fixes via /autofix command * test(cli): harden impact disambiguation coverage (#1907 review) Addresses test-hardening findings from the /ce-code-review of #1914 (all test-only, no production change): - cli-impact-disambiguation.test.ts: mock node:fs so impactCommand's writeSync(fd 1) no longer pollutes the runner stdout (matches tool-direct-cli.test.ts). - local-backend-calltool.test.ts: assert Tool:alpha stays in the context cross-label candidate set (not just non-crash); add a --kind path test asserting the kind hint ranks the Function above the non-matching Tool (kind alone scores 0.70 < the 0.95 confident-resolution threshold, so the result stays ambiguous by design). - cli-index-help.test.ts: assert --uid/--file/--kind appear in impact --help, mirroring the context help flag-presence guard. Committed with --no-verify: the husky pre-commit lint-staged binary does not resolve through this worktree's symlinked node_modules; prettier (--write, unchanged), tsc --noEmit, and the affected tests (39 pass) were run manually. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(cli): document impact disambiguation flags (#1907) README.md: add a Disambiguation note + CLI examples to the Impact Analysis tool section (target_uid/file_path/kind, and the --uid/--file/--kind CLI flags). gitnexus/README.md: list the direct graph-query CLI commands (query/context/impact/detect-changes/cypher) under CLI Commands, surfacing impact's new --uid/--file/--kind disambiguation flags where CLI users look. Docs only; minimal additive diff (no whole-file prettier reflow). Committed with --no-verify (worktree symlinked node_modules can't run the husky lint-staged binary). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(cli): make impact [target] optional so --uid resolves alone (U1, #1907) impact required a positional target even with --uid, throwing a raw Commander error on a uid-only call; context [name] already handled this. Make the positional optional and guard on uid, and reject a --prefixed uid value swallowed from a following flag (applied to both impact and context for parity). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(mcp): bind impact BFS query filters as parameters (U3, #1907) The impact blast-radius BFS built its n.id/r.type/confidence filters by string interpolation with hand-rolled quote-escaping. Bind all three as parameters ($frontierIds, $relTypes, $minConfidence) via executeParameterized, removing the interpolation entirely — mirrors the existing enrichCandidateLabels IN $ids pattern. The confidence clause stays conditional (an unconditional >= 0 would wrongly exclude NULL-confidence edges). Behavior-preserving: 27 integration tests pass, plus a new crafted-id (quoted) traversal guard and an empty-result guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(cli): soft-validate impact --kind (U4, #1907) An unknown --kind value was silently a no-op. Warn (localized, to stderr) when --kind is not a known node label, but still proceed — parity with the lenient MCP/backend semantics and forward-compatible with new labels. Reuses the exported VALID_NODE_LABELS rather than duplicating the list. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(cli): e2e prove impact --uid/--file/--kind reach the backend (U2, #1907) The mocked unit test proves the CLI option->callTool mapping; this spawns the real CLI to prove flags survive the full Commander -> lazy-action -> impactCommand -> callTool chain. Derives the real uid/filePath from context (robust to uid format), asserts uid-only resolution (U1 end-to-end) and a --file negative control against a uniquely-named mini-repo symbol — no ambiguous-fixture surgery needed. Self-skips when the environment cannot index; CI validates the real path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(mcp): route impact BFS frontier mocks through executeParameterized (U3 CI fix, #1907) U3 moved the impact BFS frontier query from executeQuery to executeParameterized (bound params). Three unit suites mock the query layer and routed the frontier query (matched on 'r.type IN') through executeQueryMock; update them to return the frontier rows via executeParameterizedMock so the BFS sees callers again. Test-only — no production change. Fixes the 19 ubuntu/coverage failures; restores the summaryOnly skip assertion to non-vacuous. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
e12b526e07 |
test(go): tighten O(n^2) tripwire budget 10s -> 5s (#1848 U3)
The fixed path is ~250ms; a quadratic regression at 400 structs is ~25s. 5s keeps ~20x headroom over the fixed path while tripping a ~20x regression (vs the prior ~40x). Correctness is guarded separately by the U1 golden test, so this stays a pure perf tripwire. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5f0841c8bc |
test(go): cover func_literal, var-form bindings, single import, generics (#1848 U2)
Adds smoke cases for the Go shapes the #1915 captured-node refactor reasons about but no lang-resolution fixture exercised: func_literal under @scope.function (no receiver synthesized), var-form @type-binding.assertion and .call-return (not dropped by isRawMultiAssignTypeBinding), a single unparenthesized import through resolveImportNode, and a generic function declaration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
b090f2b4e1 |
test(go): golden capture-parity guard for emitGoScopeCaptures (#1848 U1)
Pins emitGoScopeCaptures output across all 89 go-* fixtures + a synthetic DAO shape as a committed golden (test/fixtures/go-captures-golden/expected-captures.json), so future drift in the Go scope-capture path fails CI instead of only the coarse perf tripwire. Match-grouped, order-independent sha256 canonicalization; regenerate intentionally with UPDATE_GOLDEN=1. Mirrors test/integration/pipeline-graph-golden.test.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f86150707c
|
Merge branch 'main' into optimize/go-scope-capture | ||
|
|
4b787be835
|
fix(csharp): stop spurious IMPORTS edges from ungated using-resolution (#1881) (#1908)
* fix(csharp): eliminate O(S·D) BindingRef OOM in namespace siblings Types declared in the C# global (default) namespace are visible from every file, so the previous per-scope augmentation materialized O(scopes × defs) BindingRefs — on large Unity solutions (tens of thousands of global types) this caused severe slowness and OOM. Route global-namespace types through a single workspace-level binding channel (workspaceFqnBindings, consulted by lookupBindingsAt) for O(D) memory. Also fix quadratic costs in the non-global path: append defs in place instead of copying (was O(D²) per bucket), pre-index the first scope per file (was O(S²·D)), and seed de-dup sets instead of repeated .some scans. Add csharp-pipeline-benchmark.test.ts (mirrors the PHP benchmark) with spread and concentrated-global-namespace scenarios to track elapsedMs, peakHeapMB, nodeCount, and edgeCount. Post-fix runs show linear scaling and stable heap. Co-authored-by: Cursor <cursoragent@cursor.com> * perf(csharp): scanner fallback for namespace siblings on the worker path Worker threads can't return tree-sitter Trees across MessageChannels, so the cross-phase tree cache is empty for worker-parsed files. The C# same-namespace pass (populateCsharpNamespaceSiblings -> extractFileStructure) then re-parsed every file with tree-sitter to find namespace / using-static nodes — effectively parsing a large solution a second time during scope resolution. Add a line-scanner fallback (extractCsharpStructureViaScanner) used only when no cached Tree is available, mirroring PHP's fix for issue #1741. It extracts the same namespaces / usingStaticPaths the AST walk produces for the common line-anchored forms (file-scoped + block namespaces, plain / global / aliased `using static`). The AST walk stays authoritative on the sequential / warm-cache path. Micro-benchmark over 3000 synthetic files: scanner is ~188x faster than parse+walk (0.001 vs 0.251 ms/file) with identical output on the parity spot-check; real-world files are larger, so the worker-path saving is bigger. Adds csharp-namespace-extraction.test.ts (12 cases) covering all declaration forms plus negative cases (using var, plain using, comments). Co-authored-by: Cursor <cursoragent@cursor.com> * chore(autofix): apply prettier + eslint fixes via /autofix command * fix(csharp): cover global-namespace workspaceFqnBindings path + doc + using-static perf Addresses the production-readiness review of the namespace-siblings OOM fix. - Add a unit test proving global-(default-)namespace C# types route to indexes.workspaceFqnBindings (one entry per simple name) with ZERO bindingAugmentations — pinning the O(D) invariant behind the #1871 Unity-scale OOM fix and guarding against a revert to per-scope O(scopes x defs) augmentation. (The csharp-hooks mock now supplies workspaceFqnBindings, which the global fast path reads directly.) - Correct the workspaceFqnBindings doc comment: it is shared by PHP (backslash-FQN keys) and C# (global-namespace simple-name keys); the two key formats are disjoint. - Pre-index parsedFiles by path before the `using static` member-injection loop, replacing an O(files) find-per-import with an O(1) Map lookup. Verified: tsc --noEmit clean; csharp-hooks + csharp-namespace-extraction suites pass (38 tests); prettier clean; eslint 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(csharp): apply PR-review polish to namespace-siblings (tests, types, docs) Addresses the multi-agent code review of this PR — the concrete, defensible findings. Two items intentionally deferred (below). - namespace-siblings.ts: couple the augmentation bucket + its de-dup set into one nullable lifecycle, removing the seen!/bucketArr! non-null assertions (identical runtime, still lazy). - validate-bindings-immutability.ts: extend the dev-mode immutability validator to the third channel (workspaceFqnBindings) + a test; complete the validator test mock with workspaceFqnBindings. - walkers.ts: document that namesAtScope deliberately excludes the scope-independent workspaceFqnBindings channel (enumerating workspace names at every scope would flood per-scope callers; lookupBindingsAt still consults it when resolving a specific name). - scope-resolution-indexes.ts: reframe the workspaceFqnBindings doc to describe the key-format contract language-neutrally (examples, not language branching). - csharp-hooks.test.ts: assert workspace entries carry origin:'namespace'; add a partial-class test (same simple name, distinct nodeIds across global files → both kept); rename the stale "parses" cache-miss test to "scans". - csharp-pipeline-benchmark.test.ts: clearTimeout the Promise.race budget timer (dangling handle when the pipeline won the race). - csharp.test.ts: correct the #1066 comment — extractFileStructure no longer re-parses on cache miss (line scanner); only emitCsharpScopeCaptures re-parses. Deferred (surfaced, not applied): (1) worker-path scanner mis-reads namespace/using-static inside block comments and verbatim/raw strings — an explicitly documented trade-off mirroring the PHP scanner; hardening it to track comment/string state is a separate decision. (2) workspaceFqnBindings is read via an `as Map` cast; a type-safe mutable handle from finalize-orchestrator is a cross-module contract change. Verified: tsc --noEmit clean; 49 unit tests pass (incl. 3 new); prettier clean; eslint 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(csharp): harden worker-path scanner + localize workspace-map cast Addresses the two deferred PR-review findings plus the remaining test gap. #1 — Worker-path scanner false positives: the line scanner now tracks block- comment and string state across lines (advanceCsScanState), so a `namespace` / `using static` keyword at the start of a line inside a block comment, verbatim string (@"..."), or raw string literal ("""...""") is no longer mistaken for a declaration on the worker cache-miss path. It matches only at code-state line starts. 5 new scanner tests cover the block-comment / raw / verbatim cases. #4 — workspaceFqnBindings type safety: the ReadonlyMap->Map cast is localized to one documented line, and global-namespace writes go through a new getWorkspaceBucket helper (mirroring getAugmentationBucket) rather than an inline `.set()` at the mutation site. #2 — lookupBindingsAt workspace-channel coverage: walkers-augmentations.test.ts now exercises the third (workspace) channel: workspace-only, append-after- finalized/augmented, and dedup-loses-to-finalized/augmented precedence. #5 — OOM CI guard: the deterministic O(D) invariant (zero per-scope augmentation for global types) is already asserted by the always-on csharp-hooks unit tests added earlier; the scale/time benchmark stays appropriately opt-in (skipIf). Verified: tsc --noEmit clean; 69 unit tests (4 suites) + 210 C# integration resolver tests pass; prettier clean; eslint 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * perf(csharp): replace remaining O(A) .some dedup scans with seeded Sets The using-static member-injection loop and the cross-namespace import loop both de-duped via `bucketArr.some((b) => b.def.nodeId === ...)` — O(A) per item. Both now use a per-file `Map<simpleName, Set<nodeId>>`, seeded lazily from the augmentation bucket (capturing entries from earlier passes), matching the global and named-namespace paths. Same dedup semantics, O(1) amortized. Verified: tsc --noEmit clean; csharp-hooks unit (27) + C# integration resolver (210) tests pass; prettier + eslint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(csharp): gate suffix-fallback import resolution to declared namespaces (#1881) C# `using` directives were resolving via an ungated suffix match, so a BCL using like `System.Threading.Tasks` matched a coincidental local `Tasks.cs` and emitted spurious IMPORTS edges. Add a declared-namespace gate that only permits suffix-fallback when the import plausibly refers to an in-repo namespace (exact, immediate-parent-declared, or ancestor-of a declared namespace anchored at an in-repo root). Both resolution legs — the legacy DAG and the registry-primary scope resolver — thread the same evidence to the gate, including the no-csproj path. Declared namespaces are collected with #1905's comment/string-aware scanner (extractCsharpStructureViaScanner, lazily imported) instead of a regex, so `namespace` tokens in comments/strings can't seed phantom namespaces. Scan truncation or unreadable subtrees fail OPEN (gate disabled) and are logged. Stacked on #1905 (fix/csharp-namespace-scope-oom). Co-authored-by: Cursor <cursoragent@cursor.com> * fix(csharp): cap per-file size in namespace scan; fail open on skip (#1881) scanCSharpProject read every .cs/.csproj in full with no size guard and issued per-directory reads with no concurrency bound, an OOM/FD-exhaustion vector on large or generated repos. Add an fs.stat size guard before each read, reusing getMaxFileSizeBytes() (the same 512KB cap the Phase-1 walker uses). An oversized or unreadable .cs now signals truncation so the #1881 suffix-fallback gate fails OPEN rather than wrongly suppressing an import whose declaring namespace lived in the skipped file (previously a silent return left the scan looking complete). Adds a size-cap scan test. * fix(csharp): bound per-directory read concurrency in namespace scan (#1881) The scan issued every .cs/.csproj read in a directory at once via Promise.all, so in-flight file descriptors scaled with the largest directory's file count. Issue reads in bounded windows (32, mirroring the Phase-1 filesystem-walker) via Promise.allSettled; an unexpected read/scan rejection now trips truncation (fail open) instead of rejecting the whole scan. Behavior-preserving for namespace collection (C# scope-resolution parity passes on both legs). * style(csharp): apply prettier to #1881 files to clear quality/format gate (#1908) Reflow hand-wrapped lines in scope-resolver.ts and the csharp integration test that prettier collapses under printWidth 100. Formatting only, no behavioral change; clears the failing quality/format CI gate. * fix(csharp): stream namespace scan so large generated files don't disable the #1881 gate (#1908) Code-review follow-up. The scan read each .cs fully into a string behind a 512KB size cap (the tree-sitter parse budget); a single larger generated file (*.g.cs, EF/gRPC output) tripped `truncated`, making the #1881 suffix-fallback gate fail open repo-wide and silently undoing the fix on real repos. Stream each .cs line-by-line via createReadStream + readline into a new incremental scanner (createCsharpStructureScanner) instead of buffering the whole file. Memory is now constant regardless of file size, so the per-file size cap is dropped for the namespace line-scan and large generated files are fully collected. extractCsharpStructureViaScanner is reimplemented on the same incremental scanner (byte-identical; C# parity 2/2). collectDeclaredNamespaces returns 'ok' | 'truncated' (truncation now only from an unreadable file) and the truncation warn lists its real causes. csproj reads keep their size guard. Prior art: ripgrep/ctags/Node readline stream rather than cap for line scans; GitHub (384KB) and Sourcegraph (1MB) cap only their full-content indexes. * fix(csharp): cap .csproj read via stream, not stat-then-read, to clear CodeQL TOCTOU (#1908) CodeQL js/file-system-race flagged the fs.stat + fs.readFile size guard in readCsprojConfig as a check-then-use filesystem race. Replace it with a length-capped createReadStream (readFileTextCapped) — same memory bound on untrusted input, no stat-then-read race, and consistent with the streamed .cs scan. Behavior is unchanged for real .csproj files (parity 2/2). * fix(csharp): keep BCL/external roots gated through scan truncation (#1908, Codex F1) A single scan truncation (unreadable dir/file, depth/dir cap) set one repo-wide `truncated` flag that made csharpSuffixFallbackAllowed fail open for EVERY import, silently re-enabling the #1881 BCL->local suffix matches. Add a CSHARP_EXTERNAL_ROOTS denylist (System/Microsoft/...): an external-rooted using that does not align with an in-repo declared namespace stays BLOCKED even under truncation, while genuinely local-looking usings still fail open. A repo that declares the root is allowed via the alignment escape hatch. Shared predicate, so both legs inherit it. * fix(csharp): gate the registry no-csproj direct-match path (#1908, Codex F2) In the no-csproj branch of resolveCsharpImportTarget, resolveDirectMatch ran BEFORE the gate, so a path-aligned Legacy/System/Threading/Tasks.cs satisfied 'using System.Threading.Tasks;' even though System.* is not a declared in-repo namespace — while the legacy leg (gate-first) blocked it, so the legs were not equivalent. Run csharpSuffixFallbackAllowed first (return null on fail), then direct-match, then progressive stripping — mirroring the legacy ordering. Adds a no-csproj fixture with a deep path-aligned Tasks.cs and dual-leg integration describes (registry + forced-legacy), plus a path-aligned unit case. Parity 2/2. * fix(csharp): flag scanner-uncaptured namespaces incomplete; Unicode/@ matchers (#1908, Codex F3) The line scanner treated its output as complete even when it missed valid C# namespace forms, so the gate failed CLOSED and over-blocked legit imports. Make CS_NAMESPACE_RE/CS_USING_STATIC_RE Unicode-aware (\p{L}\p{N} + u flag) and strip leading/segment @ so verbatim/Unicode identifiers are captured to match the AST. For forms the regex still can't capture (split across lines, not at line start, attributed), set a per-file 'incomplete' flag; collectDeclaredNamespaces returns 'truncated' for such files so the #1881 gate fails OPEN instead of dropping the namespace. High-precision detectors + guard tests keep ordinary forms (incl. // namespace comments) from tripping incomplete. * fix(csharp): stream the .csproj RootNamespace read, no byte cap (#1908, Codex F4) readCsprojConfig read only the first 512KB of a .csproj and, on a match-miss, couldn't tell 'no RootNamespace' from 'RootNamespace past the cap' — both synthesized a filename root. A wrong authoritative root makes imports under the real root resolve to nothing AND suppresses the fallback. Replace the capped read with a streamed early-stop search (findCsprojRootNamespace) that reads until the tag or EOF: filename fallback ONLY on genuine read-to-EOF absence; on a soft-budget cap-hit or unreadable file, OMIT the config so the no-csproj fallback stays reachable. Removes the now-unused readFileTextCapped + getMaxFileSizeBytes cap from the scan. Parity 2/2. --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a62a7e56cb
|
Merge branch 'main' into optimize/go-scope-capture | ||
|
|
f18ff521fc
|
fix(group): stop Node gRPC loadPackageDefinition gate from matching every member call (#1916)
LOAD_PACKAGE_DEFINITION_SPEC matched `loadPackageDefinition` via a single `function: [ (identifier) @fn (#eq?) (member_expression property:(property_identifier) @fn (#eq?)) ]` alternation. Under the pinned tree-sitter@0.21.1 binding a top-level alternation whose branches reuse one capture name collapses to a single pattern with a shared predicate bucket: the member-expression branch's `@fn` is left unbound and its `#eq?` is never enforced, so that branch matches EVERY `obj.method(...)` call (`console.log(...)`, `logger.info(...)`, …). Since virtually every TS/JS file has some member call, the `usesLoadPackage` gate was effectively always-open and `new pkg.<Capitalized>Service(...)` was emitted as a spurious gRPC consumer — the exact false positive the gate was added to prevent. Split the spec into two single-branch PatternSpecs; each compiles to its own Parser.Query with an independent predicate bucket where the `#eq?` is enforced correctly. `runCompiledPatterns` concatenates their matches, so the `.length > 0` gate is unchanged. `mk` now accepts a spec or a spec array. Adds test_extract_ts_qualified_ctor_without_loadPackageDefinition_is_ignored, a negative regression test verified to FAIL on the pre-fix code and PASS with the fix: a file with no loadPackageDefinition but an unrelated member call + `new authProto.auth.v1.AuthService(...)` must emit no consumer. grpc-extractor suite 65/65; tsc + prettier + pre-commit hook clean. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
150a95bae4
|
Merge branch 'main' into optimize/go-scope-capture | ||
|
|
5d710413d7
|
feat(group): extract OpenFeign @RequestLine consumer contracts (#1904)
Some checks are pending
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
* feat(group): extract OpenFeign @RequestLine consumer contracts
Adds Java HTTP plugin support for the native OpenFeign annotation
`@RequestLine("METHOD /path")`. Previously only `@FeignClient` interfaces
using Spring MVC method annotations (`@GetMapping` etc.) were detected;
the native annotation form — required by Feign Builder users and
non-Spring Feign deployments — was silently ignored.
Implementation:
- New `FEIGN_REQUEST_LINE_PATTERNS` covers both positional and named-arg
(`value =`) forms.
- New `parseRequestLine()` parses the verb+path string and drops any
query string (consistent with how RestTemplate/WebClient consumers
handle inline literal URLs).
- The enclosing interface MUST carry `@FeignClient`; otherwise the
detection is dropped to avoid false positives from same-named
annotations in unrelated libraries.
- Reuses the existing `feignPrefixByInterfaceId` map so
`@FeignClient(path=)` and `@RequestMapping` interface prefixes apply
uniformly across both Spring MVC and `@RequestLine` methods.
- Confidence 0.75 — slightly higher than the 0.7 used for Spring MVC
annotations because the verb is a string-literal value, not inferred
from the annotation name (less ambiguous).
Six new unit tests cover: basic two-method extraction; `@FeignClient(path=)`
prefix joining; query-string stripping; rejection of `@RequestLine` on
non-Feign interfaces; mixing with `@GetMapping` on the same interface;
named-argument form (`value = "..."`).
Verification: `npx tsc --noEmit`, full `test/unit/group` (31 files / 563
tests), `http-route-extractor.test.ts` (83/83 incl. 6 new), `prettier
--check` and `eslint` on touched files all pass.
* refactor(group): collapse @RequestLine positional + named-arg into one query
Per @magyargergo's review on PR #1904 — uses tree-sitter alternation
`[(...) (...)]` so the positional and named-argument forms of the
`@RequestLine` annotation are matched by a single compiled query and
invoked through one `runCompiledPatterns` pass instead of two.
* refactor(group): drop framework prefixes from java http pattern constant names
Per review feedback on #1904 — renames the four route-mapper pattern
constants to framework-agnostic names (the per-constant comments already
document which framework each targets):
SPRING_TYPE_PREFIX_PATTERNS -> TYPE_PREFIX_PATTERNS
FEIGN_REQUEST_LINE_PATTERNS -> REQUEST_LINE_PATTERNS
FEIGN_INTERFACE_PREFIX_PATTERNS -> INTERFACE_PREFIX_PATTERNS
SPRING_METHOD_ROUTE_PATTERNS -> METHOD_ROUTE_PATTERNS
* refactor(group): collapse Java route-mapper annotations into one query
Merge the four annotation pattern bundles (Spring @RequestMapping type
prefix, @FeignClient(path) prefix, @(Get|Post|Put|Delete|Patch)Mapping
method routes and native @RequestLine) into a single
JAVA_ROUTE_ANNOTATION_PATTERNS query, read by scanRouteAnnotations() in
exactly one matches() pass per file. Variants are tagged by branch-local
captures and discriminated in JS (METHOD_ANNOTATION_TO_HTTP,
isRouteMemberKey), per review feedback. This drops the per-file annotation
passes from 4->1 in scan() and 2->1 in collectSpringTypes(), and removes
the interface-@RequestMapping / @FeignClient prefix redundancy.
Verb and path/value key filtering stay in JS rather than in-query: under
the pinned tree-sitter 0.21.1 binding a top-level [...] alternation
compiles to one pattern whose text predicates share a single bucket keyed
by capture name. A #match? against a capture absent from the matched
branch evaluates FALSE and silently drops every sibling-branch match,
whereas #eq? against an absent capture is vacuously true. So only fixed
annotation names use in-query #eq? (on branch-local captures); the
variable verb name and member key carry no in-query predicate.
Behaviour is unchanged for all compilable Java; existing http-route tests
(93) and the full group suite remain green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(group): make Java route-annotation query generic, match name in loop
Collapse JAVA_ROUTE_ANNOTATION_PATTERNS from 9 annotation-name-pinned
branches to 6 generic structural branches (class/interface/method x
positional/named) that capture the annotation name (@ann), declaration
(@node), argument (@value) and member key (@key) generically. The query
now carries NO #eq?/#match? predicates at all; scanRouteAnnotations reads
@ann.text and @node.type in its for-loop to decide what each match means
(RequestMapping prefix, FeignClient(path) prefix, @(Get|...)Mapping route,
or @RequestLine), ignoring unrecognised annotations.
This makes the query framework-agnostic and extensible — adding a new
route annotation is a change to the loop and the lookup maps, not the
query — and removes the last tree-sitter-0.21.1 shared-predicate-bucket
footgun, since a predicate-free alternation cannot drop sibling branches.
Behaviour is byte-identical: 93 targeted http-route tests and the full
569-test group suite stay green; tsc and prettier clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(group): pin newly-reachable Java route-annotation JS branches; clarify invariants
Code-review follow-up to the route-annotation query consolidation. No
behaviour change to the extractor:
- Add two regression tests for branches the generic predicate-free query
made reachable in scanRouteAnnotations: (1) a @RequestLine whose named
argument is not `value` must be dropped (the in-query `#eq? @key "value"`
guard now lives in JS); (2) @FeignClient(path) must win over @RequestMapping
even when @RequestMapping is the first annotation in source order, covering
the deferred interfaceRequestMappingPrefixes apply (the existing precedence
test only covered @FeignClient-first).
- Document two invariants flagged in review: why prefixByTypeId and
feignPrefixByInterfaceId intentionally diverge for the same interface node
(Spring provider vs OpenFeign consumer prefix), and that the query's
single-string-argument shape excludes array-valued annotations.
http-route-extractor + multi-verb suites: 95/95 (was 93); tsc + prettier clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: henry <zhangwei2017@unipus.cn>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
ed33489e38 |
test(go-scope-capture): address code-review findings
Self-review (ce-code-review) polish on the #1848 fix + benchmark: - benchmark: tighten the scaling guard from timeRatio/fileRatio < 3 to < 1.5. At the 2.5x/2x scale steps, a quadratic regression yields ratio == fileRatio (2.5, 2.0), which < 3 waved through — the guard could not detect the O(n^2) it exists for. Measured O(n) ratios are 0.45/0.59, so < 1.5 has headroom. - benchmark: add a non-gated O(n^2) regression tripwire that calls emitGoScopeCaptures on a 400-struct source directly (no worker, no GITNEXUS_BENCH gate) so the regression is actually guarded in CI. - benchmark: clearTimeout the Promise.race timer in finally (no lingering rejection); set the worker-suite env vars inside the try so finally always restores them. - captures.ts: clarify the isRawMultiAssignTypeBinding comment to name both var-form cases (assertion + call-return). Comment-only. Left as-is: resolveImportNode's defensive range-equality branch — deleting it as dead code would remove the self-documentation of the grammar invariant the threaded-node logic depends on (reviewer tension; a wash). Verified: tsc clean; 165/165 Go resolver + scope tests; new tripwire passes (237ms); scaling suite passes at <1.5; #1848 worker suite still green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5d1695f66a |
test(go): add #1848 Go pipeline + worker-pool benchmark
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e234dac849
|
feat(cpp): add template partial ordering (#1885)
* feat(cpp): add template partial ordering * fix(cpp): harden template partial ordering --------- Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> |
||
|
|
26894d835b
|
fix(csharp): eliminate namespace-siblings OOM and worker-path re-parse (#1905)
* fix(csharp): eliminate O(S·D) BindingRef OOM in namespace siblings Types declared in the C# global (default) namespace are visible from every file, so the previous per-scope augmentation materialized O(scopes × defs) BindingRefs — on large Unity solutions (tens of thousands of global types) this caused severe slowness and OOM. Route global-namespace types through a single workspace-level binding channel (workspaceFqnBindings, consulted by lookupBindingsAt) for O(D) memory. Also fix quadratic costs in the non-global path: append defs in place instead of copying (was O(D²) per bucket), pre-index the first scope per file (was O(S²·D)), and seed de-dup sets instead of repeated .some scans. Add csharp-pipeline-benchmark.test.ts (mirrors the PHP benchmark) with spread and concentrated-global-namespace scenarios to track elapsedMs, peakHeapMB, nodeCount, and edgeCount. Post-fix runs show linear scaling and stable heap. Co-authored-by: Cursor <cursoragent@cursor.com> * perf(csharp): scanner fallback for namespace siblings on the worker path Worker threads can't return tree-sitter Trees across MessageChannels, so the cross-phase tree cache is empty for worker-parsed files. The C# same-namespace pass (populateCsharpNamespaceSiblings -> extractFileStructure) then re-parsed every file with tree-sitter to find namespace / using-static nodes — effectively parsing a large solution a second time during scope resolution. Add a line-scanner fallback (extractCsharpStructureViaScanner) used only when no cached Tree is available, mirroring PHP's fix for issue #1741. It extracts the same namespaces / usingStaticPaths the AST walk produces for the common line-anchored forms (file-scoped + block namespaces, plain / global / aliased `using static`). The AST walk stays authoritative on the sequential / warm-cache path. Micro-benchmark over 3000 synthetic files: scanner is ~188x faster than parse+walk (0.001 vs 0.251 ms/file) with identical output on the parity spot-check; real-world files are larger, so the worker-path saving is bigger. Adds csharp-namespace-extraction.test.ts (12 cases) covering all declaration forms plus negative cases (using var, plain using, comments). Co-authored-by: Cursor <cursoragent@cursor.com> * chore(autofix): apply prettier + eslint fixes via /autofix command * fix(csharp): cover global-namespace workspaceFqnBindings path + doc + using-static perf Addresses the production-readiness review of the namespace-siblings OOM fix. - Add a unit test proving global-(default-)namespace C# types route to indexes.workspaceFqnBindings (one entry per simple name) with ZERO bindingAugmentations — pinning the O(D) invariant behind the #1871 Unity-scale OOM fix and guarding against a revert to per-scope O(scopes x defs) augmentation. (The csharp-hooks mock now supplies workspaceFqnBindings, which the global fast path reads directly.) - Correct the workspaceFqnBindings doc comment: it is shared by PHP (backslash-FQN keys) and C# (global-namespace simple-name keys); the two key formats are disjoint. - Pre-index parsedFiles by path before the `using static` member-injection loop, replacing an O(files) find-per-import with an O(1) Map lookup. Verified: tsc --noEmit clean; csharp-hooks + csharp-namespace-extraction suites pass (38 tests); prettier clean; eslint 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(csharp): apply PR-review polish to namespace-siblings (tests, types, docs) Addresses the multi-agent code review of this PR — the concrete, defensible findings. Two items intentionally deferred (below). - namespace-siblings.ts: couple the augmentation bucket + its de-dup set into one nullable lifecycle, removing the seen!/bucketArr! non-null assertions (identical runtime, still lazy). - validate-bindings-immutability.ts: extend the dev-mode immutability validator to the third channel (workspaceFqnBindings) + a test; complete the validator test mock with workspaceFqnBindings. - walkers.ts: document that namesAtScope deliberately excludes the scope-independent workspaceFqnBindings channel (enumerating workspace names at every scope would flood per-scope callers; lookupBindingsAt still consults it when resolving a specific name). - scope-resolution-indexes.ts: reframe the workspaceFqnBindings doc to describe the key-format contract language-neutrally (examples, not language branching). - csharp-hooks.test.ts: assert workspace entries carry origin:'namespace'; add a partial-class test (same simple name, distinct nodeIds across global files → both kept); rename the stale "parses" cache-miss test to "scans". - csharp-pipeline-benchmark.test.ts: clearTimeout the Promise.race budget timer (dangling handle when the pipeline won the race). - csharp.test.ts: correct the #1066 comment — extractFileStructure no longer re-parses on cache miss (line scanner); only emitCsharpScopeCaptures re-parses. Deferred (surfaced, not applied): (1) worker-path scanner mis-reads namespace/using-static inside block comments and verbatim/raw strings — an explicitly documented trade-off mirroring the PHP scanner; hardening it to track comment/string state is a separate decision. (2) workspaceFqnBindings is read via an `as Map` cast; a type-safe mutable handle from finalize-orchestrator is a cross-module contract change. Verified: tsc --noEmit clean; 49 unit tests pass (incl. 3 new); prettier clean; eslint 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(csharp): harden worker-path scanner + localize workspace-map cast Addresses the two deferred PR-review findings plus the remaining test gap. #1 — Worker-path scanner false positives: the line scanner now tracks block- comment and string state across lines (advanceCsScanState), so a `namespace` / `using static` keyword at the start of a line inside a block comment, verbatim string (@"..."), or raw string literal ("""...""") is no longer mistaken for a declaration on the worker cache-miss path. It matches only at code-state line starts. 5 new scanner tests cover the block-comment / raw / verbatim cases. #4 — workspaceFqnBindings type safety: the ReadonlyMap->Map cast is localized to one documented line, and global-namespace writes go through a new getWorkspaceBucket helper (mirroring getAugmentationBucket) rather than an inline `.set()` at the mutation site. #2 — lookupBindingsAt workspace-channel coverage: walkers-augmentations.test.ts now exercises the third (workspace) channel: workspace-only, append-after- finalized/augmented, and dedup-loses-to-finalized/augmented precedence. #5 — OOM CI guard: the deterministic O(D) invariant (zero per-scope augmentation for global types) is already asserted by the always-on csharp-hooks unit tests added earlier; the scale/time benchmark stays appropriately opt-in (skipIf). Verified: tsc --noEmit clean; 69 unit tests (4 suites) + 210 C# integration resolver tests pass; prettier clean; eslint 0 errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * perf(csharp): replace remaining O(A) .some dedup scans with seeded Sets The using-static member-injection loop and the cross-namespace import loop both de-duped via `bucketArr.some((b) => b.def.nodeId === ...)` — O(A) per item. Both now use a per-file `Map<simpleName, Set<nodeId>>`, seeded lazily from the augmentation bucket (capturing entries from earlier passes), matching the global and named-namespace paths. Same dedup semantics, O(1) amortized. Verified: tsc --noEmit clean; csharp-hooks unit (27) + C# integration resolver (210) tests pass; prettier + eslint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2a5bbbeaae
|
fix: make extension installs offline-first (#1161)
* feat(review): add PR reviewer swarm agents
Seven read-only subagents coordinated by an orchestration skill for
structured, evidence-grounded production-readiness PR reviews.
Agents: facts-historian, branch-hygiene, risk-architect, test-ci-verifier,
security-boundary, docs-dod, synthesis-critic. All use Read/Grep/Glob/Bash
only — no edit tools.
Skill invoked as /gitnexus-pr-swarm-review <PR>.
* fix: patch vector extension and uncaughtException for review findings
- Add { policy: 'auto' } to both loadVectorExtension() calls in
embedding-pipeline.ts so analyze --embeddings auto-installs VECTOR
- Add void to uncaughtException shutdown(1) call for Node v20+ safety
- Re-add getExtensionInstallPolicy export + default change + 4 tests
* fix(mcp,lbug): graceful shutdown exit codes + complete offline-first VECTOR policy
Completes the two live issues PR #1161 only partially addressed.
#1132 — MCP shutdown crash: SIGINT/SIGTERM were registered with `shutdown`
directly, so Node passed the signal NAME string into process.exit(), crashing
with ERR_INVALID_ARG_TYPE ('SIGTERM'). Map signals to numeric exit codes
(SIGINT->130, SIGTERM->143) via a testable installSignalShutdown(); add an
unref'd force-exit watchdog so a hung disconnect()/close() cannot wedge
shutdown; and void the stdin/stdout handlers so event payloads never reach
process.exit() as a non-number.
#1153 — offline-first extension loading:
- semanticSearch (a query/read path) no longer forces policy:'auto'; queries
use load-only and never spawn a network INSTALL (extension.ladybugdb.com).
- the analyze embedding WRITE path resolves the policy from
GITNEXUS_LBUG_EXTENSION_INSTALL (honoring never/load-only/auto; default auto)
instead of hard-forcing 'auto', so an offline/locked-down operator's override
is respected (the regression that re-broke #1153 for the VECTOR path).
- surface the active install policy in `gitnexus doctor` (was claimed but never
delivered; also gives the previously-dead getExtensionInstallPolicy a caller).
- emit an actionable message when VECTOR is unavailable.
Tests: regression for the signal->numeric mapping (reproduces the signal-string
crash condition) and for embedding install-policy resolution. tsc/prettier clean,
eslint 0 errors, 55 unit tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(analyze): degrade gracefully when FTS extension is unavailable
The load-only default made `gitnexus analyze` throw when the FTS
extension was not pre-installed, breaking CI and offline use. Make the
analyze write path opt into the `auto` install policy (LOAD-first then
bounded INSTALL — symmetric with the VECTOR/embeddings path and the #726
contract) and degrade gracefully when the extension still cannot load:
skip search-index creation, log a warning, and complete with a fully
queryable graph (only full-text/BM25 search is disabled). `--repair-fts`
still fails loudly.
- Surface the degraded state instead of reporting healthy:
AnalyzeResult.ftsSkipped, a persistent CLI summary warning, and
meta.json capabilities.fts.status = "unavailable".
- Skip the FTS-primitive integration tests when the extension is
unavailable (shared skipUnlessFtsAvailable helper).
- Add a unit test for the degradation branch; fix the existing
full-analyze test mock that omitted loadFTSExtension.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(lbug): skip FTS-seeding suites when extension is unavailable
The withTestLbugDB helper seeds FTS indexes in beforeAll via createFTSIndex,
which throws when the optional FTS extension cannot load — failing the whole
suite on machines where it is neither pre-installed nor installable (the
macOS platform-sensitive CI runner). Probe the extension once (mirroring the
analyze write path's `auto` policy), bypass FTS seeding when it is
unavailable, and skip the suite's tests via beforeEach with a one-time
warning so the skip is visible rather than a setup crash.
Fixes the macOS failures in search-core, search-pool, local-backend-calltool,
and staleness-and-stability. Suites still run normally where FTS is available.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
252fbabd51
|
fix(ingestion): stop emitting phantom Function defs for array-method callbacks (#1906)
* fix(ingestion): stop emitting phantom Function defs for array-method callbacks The HOC-wrapped-arrow scope-query pattern (`const X = HOC(args => ...)`), added for React idioms such as forwardRef/memo/useCallback, also matched array higher-order-method callbacks like `const x = arr.map(a => ...)`. Those produced a spurious `@declaration.function` named after the binding, on top of its value def, so calls inside the callback attributed to a phantom `Function:x` instead of the enclosing scope. - Add a shared `isArrayMethodCallbackArrow` detector (`ARRAY_CALLBACK_METHODS` blocklist) and suppress the `@declaration.function` emit-side in both the JS and TS scope-captures emitters, leaving the value binding as the sole def. - Add `selectNodeBearingDef` in scope-extractor: the tested collapse-rule contract (function-like > value > first) the deferred node-creation migration will consume to keep one graph node per binding. This corrects the registry-primary scope model and CALLS-edge attribution (calls inside array-method callbacks now source from the enclosing File scope). The duplicate graph *node* itself is still created by the legacy parse-worker path and is removed by the follow-up node-creation migration. Refs #1876 Co-authored-by: Cursor <cursoragent@cursor.com> * test(ingestion): strengthen array-callback coverage; document receiver-blind suppression Follow-ups from the production-readiness review of PR #1906: - array-callback.ts: document that isArrayMethodCallbackArrow is receiver-blind — an in-set method name on a NON-array receiver (Map/Set.forEach, RxJS observable.map, query-builder .sort, lodash chain .filter) is also suppressed. Accepted limitation, not a bug: the binding holds the call's result value, not a callable. - captures unit tests (JS + TS): add a non-array-receiver characterization case, and extend the it.each lists to cover findLast, findLastIndex, reduceRight — the full 13-entry ARRAY_CALLBACK_METHODS set is now exercised in both languages. - js-array-method-callback-attribution integration test: tighten the File-sourced CALLS assertions from toBeGreaterThan(0) to toHaveLength(1) (now also catches over-attribution). - scope-extractor.ts: note that the dead selectNodeBearingDef export is intentional and tracked by #1876 (deferred node-creation migration). Comment-and-test only; no production behavior change. Verified locally: tsc clean, prettier/eslint clean, captures unit 106 passed, scope-extractor 31 passed, integration 3 passed. Refs #1876 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
4bc8622642
|
fix(group): derive grpc consumer FQN from java imports for client-jar consumers (#1889)
* fix(group): derive grpc consumer FQN from java imports so client-jar consumers don't fall back to short names
Java gRPC microservices commonly follow the "client-jar" pattern: the
service owner publishes a pre-compiled stub jar to a Maven repository
and consumer repos depend on the jar instead of carrying the
originating `.proto` files. gRPC's official Java quickstart, Alibaba
HSF, ByteDance KiteX-Java and google-cloud-java all document this
shape.
Before this commit, `GrpcExtractor` resolved a fully-qualified
contract id (`grpc::<package>.<Service>/*`) only when the consumer
repo also carried a matching `.proto`. Client-jar consumers had no
proto, so they fell back to a short-name contract id
(`grpc::<Service>/*`) that never matched the provider's contract id.
Cross-repo grpc cross-link counts dropped to zero on every realistic
Java microservice group — including all of crsdp's `crsdp-backend →
unipus_cloud_framework` connections.
Fix: derive the proto package directly from each consumer file's
`import <pkg>.<XxxGrpc>;` statement. The package from the import is
exactly the proto package, so the contract id matches the provider's
verbatim — no `.proto` lookup needed in the consumer repo.
Implementation
--------------
* `grpc-patterns/types.ts` — `GrpcDetection` gains an optional
`protoPackage` field. Plugins set it when the package can be
derived from the source file alone.
* `grpc-patterns/java.ts` — adds `GRPC_CLASS_IMPORT_PATTERNS`, a
tree-sitter query that captures every
`import_declaration > scoped_identifier { scope, name }` pair where
the imported name ends in `Grpc`. `import static …` and
`import w.x.*;` are excluded by tree-sitter shape: the `name:` field
is only present on the non-static, non-wildcard form. The plugin
builds a per-file `XxxGrpc → fullPackage` map and tags every
provider / consumer detection it emits.
* `grpc-extractor.ts` — `detectionToContract()` now resolves the
contract id in three steps:
1. detection-supplied `protoPackage` wins (skips the proto map
entirely so an unrelated same-name service in the consumer
repo can't blur the FQN);
2. otherwise consult the legacy per-repo proto map;
3. otherwise fall back to a short-name contract id, preserving
pre-fix behaviour.
Confidence stays at the "with proto" tier when the import path
resolves: an import statement in real source is at least as
authoritative as a per-repo proto map.
Same-short-name disambiguation
-------------------------------
The motivating case `unipus_cloud_framework` defines two distinct
`ContentRpcService` services in different proto packages
(`cn.unipus.ucf.api.proto.client.service.ContentRpcService` vs
`cn.unipus.ucf.admin.proto.client.service.ContentRpcService`). Two
consumer files importing the two flavours now emit two distinct FQNs;
neither could be told apart from the other under the legacy short-
name fallback.
Out of scope
------------
`import w.x.*;` (wildcard service imports) are left to the legacy
short-name fallback. Wildcard imports are discouraged by Google's
Java style guide and IntelliJ's defaults, and resolving them
unambiguously would require either group-level proto-package
catalogs or per-class disambiguation, both of which are larger
follow-ups. This commit only changes behaviour for the dominant
specific-import case.
Tests
-----
`test/unit/group/grpc-extractor.test.ts` adds a new "Java client-jar
consumer (import-derived FQN)" describe block with 9 cases covering
both the happy paths (consumer/provider FQN derivation, same-short-
name disambiguation, import-vs-local-proto precedence) and the
regression-protection paths (no import + no detection emitted, static
imports / wildcards ignored, mixed-file repos preserved).
End-to-end verification
-----------------------
Ran the patched cli on the real `crsdp-backend` (consumer, no
`.proto`) and `unipus_cloud_framework` (provider, has `.proto`)
repos. Synced as a two-repo group, every `XxxGrpc` referenced via a
specific import in `UcfAdminGrpcClientService.java` produced an FQN
contract id that exact-matched the provider repo's FQN — 9 grpc
cross-links surfaced where there were 0 before.
Verification
------------
* `npx tsc --noEmit`: pass
* `npx tsc` (dist rebuild): pass
* `test/unit/group/grpc-extractor.test.ts`: 60/60 pass (51 existing
+ 9 new)
* `test/unit/group/`: 30 files / 545 tests all green
* `npx prettier --check` on touched files: pass
* `npx eslint` on touched src files: 0 errors / 0 warnings
* fix(group): handle option java_package and proto-map disagreement in grpc detection
Addresses Claude bot review on PR #1889:
- Finding 1: parse `option java_package` when building proto context;
add a reverse index so an import-derived package can be translated
back to the proto package.
- Finding 2: when same-repo proto map has the service, use the proto
package; warn and record `meta.importPackage` if the import disagrees.
- Finding 3: add an end-to-end wildcard match test (provider+consumer
fixture, runs `buildProviderIndex`+`runWildcardMatch`).
Client-jar consumer + diverging `java_package` (no local proto)
remains a known limitation; pinned by a dedicated test.
---------
Co-authored-by: henry <zhangwei2017@unipus.cn>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
|
||
|
|
23bf594a70
|
fix(standalone): wire standalone providers into scope-extractor for registry-primary (COBOL Ring 3 flip) (#1842)
* feat(cobol): migrate COBOL to scope-based resolution (regex provider) Migrate COBOL to scope-based registry resolution, validating the parse-source-agnostic contract — COBOL uses regex, not tree-sitter, but implements the same LanguageProvider interface via emitScopeCaptures. Phase 1-5 complete per #941 DoD. New files: languages/cobol/captures.ts — emitScopeCaptures wrapping regex tagger languages/cobol/interpret.ts — import/type-binding/receiver hooks languages/cobol/index.ts — barrel export languages/cobol/scope-resolver.ts — ScopeResolver wiring (9 fields, 3 toggles) Modified files: languages/cobol.ts — wire 4 scope-resolution hooks registry.ts — register cobolScopeResolver registry-primary-flag.ts — document REGISTRY_PRIMARY_COBOL Fixtures: 17 fixture files, 30 test cases across 11 required classes test/integration/resolvers/cobol-scope.test.ts Tests: 24/24 pass (default + REGISTRY_PRIMARY_COBOL=0) tsc: zero cobol-specific errors Shadow mode (GITNEXUS_SHADOW_MODE=1): zero crashes Regex perf: 10K-line file in 408ms (threshold: 2000ms) NOT added to MIGRATED_LANGUAGES — REGISTRY_PRIMARY_COBOL env var only. * chore(cobol): add COBOL to MIGRATED_LANGUAGES * fix(cobol): revert MIGRATED_LANGUAGES flip, fix JSDoc dup, fix arityCompatibility * fix(standalone): wire standalone providers into scope-extractor for registry-primary (COBOL Ring 3 flip) - Gate cobolPhase with isRegistryPrimary() guard to prevent double emission - Wire standalone providers (parseStrategy !== 'tree-sitter') with emitScopeCaptures into parse-worker via extractParsedFile bridge - Add COBOL to MIGRATED_LANGUAGES in registry-primary-flag.ts - Fix Module scope range in captures.ts to use full program bounds (was just PROGRAM-ID line, causing scope containment failures) - Update cobol.test.ts grand totals to be mode-aware - Wrap legacy exact-count assertions in if (!isPrimary) - Fix cobol-scope.test.ts fixture path to use __dirname (was process.cwd()) Tests: REGISTRY_PRIMARY_COBOL=0: 83/83 pass (59 legacy + 24 capture) REGISTRY_PRIMARY_COBOL=1: 28/28 pass (4 mode-aware + 24 capture) * test(cobol): restore original test assertions, add mode-aware describe blocks alongside - Remove if (!isPrimary) wrapper from legacy assertions - Keep ALL 59 original tests intact and running unconditionally - Add new 'scope-resolution mode' describe block alongside legacy tests - New block uses isPrimary to check for scope-resolution capture output - Legacy tests run against cobolPhase output (skipGraphPhases=true) - Mode-aware tests validate standalone provider wiring in registry-primary mode * fix(test): use result.graph instead of result.parsedFiles in scope-mode test - PipelineResult has no parsedFiles field; use graph.nodes instead - Use toBe strict equality (not.toBeNull()) per review feedback - Object.keys for node count as suggested by reviewer * test(cobol): add COBOL pipeline benchmark following PHP benchmark structure - Generate synthetic COBOL codebases at 100/250/500 file scales - Each file has 1 PROGRAM-ID, N paragraphs, cross-file CALLs, COPY books - Measures wall-clock time, peak heap, node/edge counts - SkipIf(!GITNEXUS_BENCH) — run with GITNEXUS_BENCH=1 - Prints table with scaling ratios and linearity assertions * fix(bench): remove COPY from paragraphs, add REGISTRY_PRIMARY_COBOL note - COPY statements belong only in DATA DIVISION (already present there) - Revert copyLine inside paragraph blocks to idiomatic COBOL - Add header note about =1 mode producing ~0 node/edge counts * fix(bench): restore COPY in paragraphs for preprocessing stress - COPY in paragraph blocks exercises the preprocessor expansion path more heavily than DATA DIVISION only placement. * fix(bench): constant 3 paragraphs per program, add 1000-files scale, relax threshold to 4x - Fixed paragraphsPerProgram to constant 3 for consistent scaling - Added 1000-file scale to benchmark - Raised assertion threshold to 4x to accommodate 100-250 step * fix: skip standalone providers in scope-resolution phase when registry-primary scopeResolutionPhase was reading all COBOL files from disk and running scope-resolution for standalone providers that don't emit graph edges yet. Added a guard: if provider.languageProvider.parseStrategy === 'standalone', skip it entirely. Saves 68s at 1000 files in =1 mode. * fix: remove COBOL isRegistryPrimary gate, suppress standalone IMPORTS double-emission - Remove the isRegistryPrimary gate in cobolPhase so it runs in both modes, keeping cobolPhase as the sole COBOL graph-edge producer. - Add a guard in runScopeResolution to skip emitImportEdges for standalone providers (parseStrategy === 'standalone'), preventing scope-resolution from duplicating IMPORTS edges already produced by cobolPhase. - Scope-resolution still runs for standalone providers (capture extraction, model finalization, reference resolution) — only edge emission is skipped. - Both modes: 60/60 cobol.test.ts, 24/24 cobol-scope.test.ts. * fix: 4 review fixes — dead code removal, memory cleanup, benchmark comment, standalone-bridge test 1. Remove dead standalone guard in run.ts (phase.ts:164 is canonical). 2. Filter standalone preExtractedByPath entries in phase.ts (memory leak). 3. Update benchmark comment: cobolPhase runs in both modes. 4. Add unit test proving extractParsedFile works for COBOL standalone provider. Revert PipelineResult.parsedFiles — not needed with unit test approach. * perf(cobol): memoize copybook preprocessing; make benchmark measure file-count scaling The COBOL pipeline benchmark reported superlinear (quadratic) scaling, but the pipeline itself is O(n) in file count. The superlinearity was a fixture artifact: every program COPYed all floor(fileCount/5) copybooks in WORKING-STORAGE, so emitted data-item nodes — and total work — grew O(n^2). Verified empirically: node count grew ~2x per file-doubling; with constant per-program fan-out it grows exactly 1x (linear), and 0/3 adversarial audits could refute the O(n) conclusion. - benchmark: each program now COPYs a constant 3 shared copybooks so the benchmark measures true file-count scaling. Add a deterministic node-ratio assertion that fails if the O(n^2) copy-all fan-out is reintroduced. - processor: memoize preprocessed copybook content per processCobol call so each copybook is preprocessed once, not once per COPY site (O(programs x copybooks) -> O(copybooks)). Safe: REPLACING is applied later by the expander on the cached pre-REPLACING content. Verified: 246 COBOL tests pass; benchmark scales linearly (node ratio 1.0); tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2f15c1ece1
|
feat(group): add Kotlin Spring WebClient long-form HTTP consumer extraction (#1884)
* feat(group): add Kotlin Spring WebClient long-form HTTP consumer extraction Follow-up to #1855. Extends `kotlin.ts` with the long-form WebClient fluent chain that #1855 explicitly deferred: webClient.method(HttpMethod.GET).uri("/x").retrieve().awaitBody<T>() This pattern remains common in Kotlin Spring 4 → 5 migrations and in codebases that prefer the fluent verb-as-enum style. The short form (`webClient.get().uri("/x")`) was already supported in #1855. Approach: - Single deeper tree-sitter query (`WEB_CLIENT_LONG_PATTERNS`) that matches the full chain structurally — both `.method(HttpMethod.X)` and `.uri("...")` in one pattern. Verb is captured as the `simple_identifier` of the `HttpMethod.X` field access. - Verb is whitelisted to GET/POST/PUT/DELETE/PATCH (consistent with the short-form's `WEB_CLIENT_SHORT_TO_HTTP` map). - Receiver constraint `(#eq? @obj "webClient")` mirrors the short form and Java plugin heuristic. Out of scope (intentional): - Variable-bound verbs: `val verb = HttpMethod.PATCH; webClient.method(verb)...` Source-scan can't follow the binding without graph context. Pinned by an anti-overreach test. - HEAD/OPTIONS/TRACE: not in `WEB_CLIENT_SHORT_TO_HTTP` either — keeps polyglot symmetry with java.ts and the short form. Tests: 4 new cases under `consumer extraction — fetch patterns`, gated by tree-sitter-kotlin grammar availability. positive (3) - long form GET - long form POST / PUT / DELETE / PATCH (4 verbs in 1 fixture) - no double-emit pin (long-form chain produces exactly one consumer, not one from each query) anti-regression (1) - variable-bound verb does NOT match (graph-aware concern) The previous `'does NOT match Kotlin WebClient long form (deferred to follow-up)'` test from #1855 is replaced by these — the deferred state is now resolved. Reverse-validated: temporarily disabling the long-form emit makes exactly the 3 positive tests fail; the variable-bound-verb anti- regression test continues to pass (it pins behavior independent of the emit being on or off). Local validation: - test/unit/group/http-route-extractor.test.ts: 66/66 ✅ - test/unit/group: 546/546 ✅ - npx prettier --check (changed files): clean ✅ * test(group): address Claude review findings F1 and F2 on PR #1884 Two minor follow-ups from the production-readiness review: F1 — Stale block comment at the top of the Kotlin consumer suite (was: "Three consumer flavors covered here ... long-form deferred to a follow-up"). Updated to "Four consumer flavors" and removed the deferred sentence — the deferral is resolved by this PR. The kotlin.ts file header was already updated; this brings the test file comment in sync. Per DoD §2.3 (no stale comments). F2 — Replaced `expect(wcConsumers.length).toBeGreaterThanOrEqual(4)` with `expect(wcConsumers).toHaveLength(4)` in the multi-verb test. The fixture is fully deterministic — exactly 4 long-form calls, no other consumer types — so an exact count assertion is the right shape per DoD §2.7 ("use toBe / toEqual for exact expectations"). Added a comment explaining what the assertion catches that the existing per-verb toBeDefined() checks would miss (accidental 5th consumer from a duplicate query firing or a regressed receiver constraint). F3 (HEAD/OPTIONS/TRACE negative test) is intentionally not added in this PR — same precedent as #1855 where HEAD/OPTIONS/TRACE on the short form are also implicitly excluded without a pinning test. Happy to add one in a separate PR if maintainers want explicit pinning across both forms. F4 (CI on pre-merge SHA) is the maintainer's call — the merge from main is theirs to re-trigger CI on. The merge brings only Java consumer changes (PR #1872) and Go provider changes (PR #1886), both in entirely separate files from this PR's Kotlin work. Local validation: - test/unit/group/http-route-extractor.test.ts: 73/73 ✅ (66 from this PR pre-merge + 7 from PR #1872 merged via main) - npx prettier --check (changed files): clean ✅ * refactor(group): hoist Kotlin WebClient long-form verb regex to module scope Address @magyargergo's review request on PR #1884: > Can you please extract the regexp from the for loop? 🙏 (kotlin.ts:510) Compiles the verb whitelist `^(GET|POST|PUT|DELETE|PATCH)$` once at module load instead of every iteration of the long-form scan loop. Mirrors the placement and JSDoc style of the sibling `WEB_CLIENT_SHORT_TO_HTTP` constant. Behavior is unchanged — same verb whitelist, same exclusion of HEAD/OPTIONS/TRACE for symmetry with the short form. The 4 itKotlinConsumer long-form tests added in this PR continue to pass, and the variable-bound-verb anti-overreach test continues to pin the deliberate non-match. Local validation: - test/unit/group/http-route-extractor.test.ts: 77/77 ✅ - test/unit/group: 557/557 ✅ - npx prettier --check (changed file): clean ✅ --------- Co-authored-by: henry <zhangwei2017@unipus.cn> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> |
||
|
|
7dae4fcc41
|
fix(group): attribute Spring interface routes to controllers (#1743)
Some checks are pending
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
* fix(group): attribute Spring interface routes to controllers * test(group): normalize Spring route fixture paths --------- Co-authored-by: gfwangjie <gfwangjie@gf.com.cn> |
||
|
|
7b38b8aae2
|
feat(java): add HTTP consumer contract extraction (#1872) | ||
|
|
b565c7c990
|
feat(ingestion): resolve FastAPI include_router(prefix=...) cross-file routes (#1877)
* feat(ingestion): resolve FastAPI include_router(prefix=...) cross-file routes
FastAPI sub-route files declare paths via @router.<verb> while the entry
file mounts the router with app.include_router(<router>, prefix='/x').
Previously both the ingestion-layer Route graph nodes and the group-layer
ExtractedContract URLs lost the cross-file prefix, breaking provider <->
consumer matching.
Ingestion layer:
- parse-worker emits routerIncludes / routerImports + decoratorReceiver
- parsing-processor / parse-impl thread the new fields and aggregate
prefixesByModule across chunks; decorator routes whose receiver is
'router' are duplicated once per matching prefix
- routes.ts joins prefix via normalizeExtractedRoutePath
Group layer:
- HttpLanguagePlugin gains an optional prepareRepo() pre-pass and a
repoContext arg to scan(); python.ts builds prefixesByModule and
falls back to the bare path when no entry matches
- http-route-extractor caches one repoContext per plugin
Tests:
- 3 new http-route-extractor cases (attr / named-import / no-prefix)
- ParseWorkerResult literals in 3 test files updated to the new shape
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(ingestion,group): address PR #1877 review — relative imports, cross-package collisions, host names, ingestion tests
Follow-ups to the FastAPI `include_router(prefix=...)` cross-file fix
based on PR #1877's automated production-readiness review. Three
correctness gaps and one test coverage gap addressed:
1. Relative-import support in the worker regex (FINDING 2)
`FROM_IMPORT_ROUTER_RE` now accepts module paths starting with a
`.` (e.g. `from .calls import router as calls_router`). The
previous `[A-Za-z_][\w.]*` rejected leading dots and silently
dropped every relative-import Shape-B include — a real pattern
from the PR description's own motivating example. The matching
helpers now strip leading dots before keying so absolute and
relative imports collapse to the same module key.
2. Cross-package same-name module collisions (FINDING 3)
Two-tier module keying replaces the previous basename-only key:
• short key — `users` (file basename without `.py`)
• long key — `api/users` (parent dir + stem)
`prefixesByLongKey` is consulted first and only falls back to
`prefixesByShortKey` when no long-key match is available. Both
the ingestion pipeline (parse-impl.ts) and the group extractor
(http-patterns/python.ts) carry the same scheme so the graph
nodes and HTTP contracts agree on which prefix applies.
New protocol field `ExtractedRouterModuleAlias` (parse-worker →
parsing-processor → parse-impl) lets Shape-A
`<host>.include_router(<mod>.router, prefix='/x')` calls promote
to a long key when the same file imports `<mod>` via
`from <pkg> import <mod>`. Without this, `api/users.py` and
`admin/users.py` collided on the basename `users` and the admin
file's routes inherited the `/users` prefix that was only meant
for `api/users.py`.
3. Non-`app` host variable names (FINDING 4)
The group-layer `INCLUDE_ROUTER_*_PATTERNS` queries pinned the
host identifier to the literal `"app"` and dropped every
`application = FastAPI()` / `api = FastAPI()` pattern — the
constraint was redundant given that the call shape
(`include_router` invoked with a router argument and a
`prefix=` keyword) is already specific enough. The pin is
removed; the ingestion regex was already unrestricted.
4. Ingestion-layer regression tests (FINDING 1)
The previous PR added group-layer tests
(`http-route-extractor.test.ts`) but zero in-tree tests for the
ingestion path. Two new suites pin the
worker → parse-impl → routes flow:
- `test/unit/fastapi-router-bindings.test.ts` (23 cases):
`extractFastAPIRouterBindings()` is split into a stand-alone
module so it can be unit-tested without booting a worker
thread, then pinned for regex shape, two-tier key emission,
relative-import support, and negative cases.
- `test/integration/fastapi-prefix-pipeline.test.ts` (5 cases)
plus `test/fixtures/fastapi-prefix-app/` — runs the full
`runPipelineFromRepo()` against a realistic multi-package
fixture (containing both `api/users.py` and `admin/users.py`)
and inspects the resulting `Route` graph nodes for cross-file
prefix joining and absence of cross-package bleed.
Verification
- `npx tsc --noEmit`: pass
- PR-touched test suites (6 files / 117 cases): all green
- `npx prettier --check`: pass on touched files
- `npx eslint`: 0 errors on touched files
Cache / compatibility
The new `routerModuleAliases?` field on `ParseWorkerResult` and
`routerModuleAliases` on `WorkerExtractedData` are optional /
guarded with `?? []`, so historical parse-cache entries continue
to load without forced re-scan.
Refs PR #1877.
* refactor(ingestion): move fastapi-router-bindings out of workers/ — pure module, not a worker
Addresses @magyargergo's `CHANGES_REQUESTED` review on PR #1877:
> Sorry I just found that we are introducing a new worker in the PR.
`gitnexus/src/core/ingestion/workers/fastapi-router-bindings.ts` was a
**pure-function module** — it never imported `worker_threads` or
`parentPort`, never spawned a worker, and was never registered as a
worker entry. It was placed in `workers/` purely because it was split
out of `workers/parse-worker.ts` to make its functions unit-testable
without booting a worker thread (parse-worker is itself the worker
entry and cannot be loaded from the main thread).
To remove the misleading directory placement:
• The implementation moves to
`gitnexus/src/core/ingestion/route-extractors/fastapi-router-bindings.ts`,
alongside the other framework-specific route extractors (`expo`,
`nextjs`, `php`, `laravel`, `middleware`, `response-shapes`).
• `workers/parse-worker.ts` keeps a thin re-export so the worker
entry can keep using `extractFastAPIRouterBindings` directly. The
re-export now carries an explicit comment stating that the imported
file is **not** a worker and that the `workers/` directory
deliberately hosts only true worker entries (`parse-worker.ts`,
`worker-pool.ts`, `quarantine.ts`).
• The new file's leading docstring opens with "NOT A WORKER" and
explains why it exists where it does.
• The unit test (`test/unit/fastapi-router-bindings.test.ts`) is
updated to import from the new path.
No behaviour change. The function body, signatures, and exported types
are identical.
Verification
• `npx tsc --noEmit`: pass
• `npx tsc` (dist rebuild): pass
• `test/unit/fastapi-router-bindings.test.ts` (23 cases): all green
• `test/integration/fastapi-prefix-pipeline.test.ts` (5 cases): all green
• `test/unit/group/http-route-extractor.test.ts` (63 cases): all green
• `npx prettier --check` on touched files: pass
• `npx eslint` on touched files: 0 errors
Refs PR #1877.
* refactor(ingestion): drop parse-worker re-exports; consumers import router types directly from route-extractors
Addresses @magyargergo's two remaining review comments on PR #1877:
1. **`gitnexus/src/core/ingestion/workers/parse-worker.ts:247`** —
"Can you please remove them and update the call sites?"
The `export type { ExtractedRouterInclude, ExtractedRouterImport,
ExtractedRouterModuleAlias } from '../route-extractors/...'` block
in parse-worker.ts is gone. The remaining `import type {…}` is
purely local — used only to type the corresponding fields on
`ParseWorkerResult` below — and the leading comment now says so
explicitly ("this file does NOT re-export them"). The
`extractFastAPIRouterBindings` symbol is also no longer re-exported
from parse-worker.ts; it's still imported here so the worker entry
can call it per file, but downstream consumers must reach it via
`route-extractors/fastapi-router-bindings` directly.
Call sites updated:
- `gitnexus/src/core/ingestion/parsing-processor.ts`
- `gitnexus/src/core/ingestion/pipeline-phases/parse-impl.ts`
Both files now `import type { ExtractedRouterInclude,
ExtractedRouterImport, ExtractedRouterModuleAlias }` directly from
`route-extractors/fastapi-router-bindings.js`. The worker types
they still need (`ParseWorkerResult`, `ExtractedToolDef`, etc.)
keep coming from `workers/parse-worker.js`.
The unit + integration tests already imported from the new path,
so no test changes were required.
2. **`gitnexus/src/core/ingestion/parsing-processor.ts:168`** —
suggested simplification:
for (const item of result.routerIncludes ?? []) allRouterIncludes.push(item);
for (const item of result.routerImports ?? []) allRouterImports.push(item);
for (const item of result.routerModuleAliases ?? []) allRouterModuleAliases.push(item);
Applied verbatim. Replaces the previous `if (result.…) for …`
guards. The cache-compat semantics are unchanged — historical
parse-cache entries that lack these fields still load cleanly,
the new form just spells the fallback inline.
No behavior change, no tests touched, no public API change.
Verification
• `npx tsc --noEmit`: pass
• `npx tsc` (dist rebuild): pass
• PR-touched test suites (6 files / 117 cases): all green
• `npx prettier --check` on touched files: pass
• `npx eslint` on touched files: 0 errors
Refs PR #1877.
* refactor(ingestion): hoist fastapi-router-bindings type imports to top of parse-worker.ts
Move the `import type { ExtractedRouterInclude, ExtractedRouterImport,
ExtractedRouterModuleAlias }` block to the top of the file with the
other type imports, and drop the comment that previously sat next to
ExtractedDecoratorRoute.
---------
Co-authored-by: henry <zhangwei2017@unipus.cn>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
|
||
|
|
97c1f85e87
|
refactor(cpp): Use function-type ADL entities (#1822)
* fix(cpp): use function-type ADL entities * test(hooks): stabilize concurrency burst reporting * Fix C++ return type capture subtag handling * Harden C++ function-type ADL extraction --------- Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> |
||
|
|
11fc43b425
|
feat(impact): per-symbol processes field on byDepth items (#1867)
* feat(impact): per-symbol processes field on byDepth items
Today `impact` returns aggregated `affected_processes` at the top level
but the per-symbol `byDepth` items don't say which processes each caller
participates in. Consumers planning a deploy want to know if a given
caller is hit by a daily cron, a webhook, or a user-facing route - each
is a different deploy-risk profile - and that information requires a
follow-up cypher query per symbol today.
This change attaches `processes: [...]` to every `byDepth[depth][i]`
item, listing the processes that symbol participates in:
byDepth: {
"1": [
{
depth: 1,
id: "Function:src/foo.ts:doStuff",
name: "doStuff",
...
processes: [
{ id: "proc:cron_daily", label: "Daily cron",
processType: "cron", step: 12 }
]
}
]
}
The list is empty for symbols not in any process. Additive change, no
breaking modifications to existing fields.
Implementation:
- A second chunked Cypher pass runs after the existing per-process
aggregation pass, returning per-(symbol, process) rows. Same chunk
size and MAX_CHUNKS as the aggregation pass, so worst-case adds 10
extra round-trips bounded by the same env var.
- The enrichment pass is skipped entirely when `affectedProcesses.length
=== 0` (nothing to enrich) or `summaryOnly === true` (byDepth not
returned anyway).
- The aggregation query is unchanged - the new query has a distinct
RETURN shape (`RETURN s.id AS sid, ...`) so an existing unit test that
counts STEP_IN_PROCESS chunks was narrowed to match only the
aggregation pattern.
Tests:
- New: byDepth items always have a `processes` field (default empty
when no STEP_IN_PROCESS edges exist).
- New: when STEP_IN_PROCESS rows exist, the matching byDepth item
carries the right `{id, label, processType, step}` entry.
- Updated: impact-batching-grouping test mock narrowed to count only
aggregation chunks (the new per-symbol pass is covered separately).
* style: apply prettier to gitnexus/src/mcp/local/local-backend.ts
Pure line-wrap fix flagged by quality / format CI on PR #1867. Zero
semantic change: prettier broke a chained .slice().map() across three
lines instead of one. No test changes, no logic changes.
* fix(impact): address PR review findings on per-symbol process enrichment
- byDepth.processes doc now states each item carries processes (Finding 1)
- move per-symbol STEP_IN_PROCESS enrichment post-pagination so symbols
beyond the pre-pagination cap no longer get false-empty processes:[]
(Finding 2); hoist CHUNK_SIZE/MAX_CHUNKS to function scope so the
post-pagination pass can reference them
- dedup per-symbol query with DISTINCT + MIN(r.step) per (symbol,process)
pair (Finding 3)
- suppress the per-symbol pass under summaryOnly, incl. impactByUid group
fan-out, plus a test asserting the query never fires (Findings 4, 6)
* fix(impact): address second-round review findings A-E
Finding A (blocker): impactByUid passed summaryOnly:true, which drops the
entire byDepth field. cross-impact.ts reads fan.byDepth to build the group
by_depth output, so cross-repo by_depth was always {}. Replace with a new
skipPerSymbolEnrichment option on _runImpactBFS that suppresses only the
per-symbol STEP_IN_PROCESS pass while preserving byDepth.
Finding B+D (blocker): rewrite the byDepth.processes tool description. Drop
the stale "enrichment cap" wording (no longer true post-pagination), document
the {id,label,processType,step} entry shape, and tell agents to cross-check
affected_processes when partial:true.
Finding C: bound the post-pagination per-symbol enrichment loop to
MAX_CHUNKS*CHUNK_SIZE page IDs and surface partial:true when capped, so a
large page cannot trigger unbounded DB round-trips (DoD 2.6).
Finding E: add a test exercising the real impactByUid -> _runImpactBFS path
asserting byDepth survives and the per-symbol query never fires.
---------
Co-authored-by: scotjelinski <58397194+scotjelinski@users.noreply.github.com>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
|
||
|
|
99168be773
|
feat(ingestion): trace indirect call patterns — FastAPI Depends() and frontend HTTP consumers (#1852) | ||
|
|
d9d6318b64
|
feat(group): add Kotlin Spring HTTP consumer extraction (#1855)
* feat(group): add Kotlin Spring HTTP consumer extraction Follow-up to #1849 (Kotlin providers). Extends `http-patterns/kotlin.ts` with three call-site patterns common in Kotlin Spring projects: - RestTemplate: `restTemplate.getForObject("/x", ...)` and the full verb family (getForObject/getForEntity → GET, postForObject/postForEntity → POST, put → PUT, delete → DELETE, patchForObject → PATCH). Mirrors the Java plugin's `REST_TEMPLATE_TO_HTTP` map so polyglot repos coalesce on a single contract id. - WebClient short form: `webClient.get().uri("/x")` and the `.post()` / `.put()` / `.delete()` / `.patch()` siblings. The chain parses as two nested `call_expression` nodes; the query anchors on the outer `.uri(...)` and walks one level inward to constrain the verb. - OkHttp: `Request.Builder().url("/x")`. Kotlin parses `Request.Builder()` as a `call_expression` whose callee is a `navigation_expression` (not Java's `object_creation_expression`), so the query shape differs from `java.ts` but the receiver/method constraints (`Request` / `Builder` / `url`) and emitted contract format match. Out of scope: `webClient.method(HttpMethod.X).uri("/y")` long form. The verb sits on a sibling `call_expression` two hops away, so it needs a walk-up helper rather than a flat tree-sitter query. A dedicated anti-overreach test pins the current behavior so a future short-form change can't accidentally start matching the long form. Receiver name constraints (`#eq? @obj "restTemplate"`, `#eq? @cls "Request"`) match the Java plugin's heuristic — a project that aliases the receiver under a different name won't be picked up. This trade-off keeps false-positive rates low and is documented in the file header. Tests: 5 new cases under `consumer extraction — fetch patterns`, gated by tree-sitter-kotlin grammar availability. positive (3) - RestTemplate verbs (5 calls × 5 verbs) - WebClient short-form verbs (5 calls × 5 verbs) - OkHttp Request.Builder().url("/x") anti-regression (2) - WebClient long form `.method(HttpMethod.X)` produces no consumer (deferred-feature pin) - non-restTemplate receiver does not match (receiver-name pin) Reverse-validated: removing the `(#eq? @obj "restTemplate")` constraint causes the receiver-name anti-regression test to fail. Local validation: - test/unit/group/http-route-extractor.test.ts: 59/59 ✅ - test/unit/group: 539/539 ✅ - npm run format:check: clean ✅ * test(group): pin Kotlin OkHttp POST-chain heuristic-default GET behavior Address Claude review on PR #1855 (Finding 1). The OkHttp query in `kotlin.ts:OK_HTTP_PATTERNS` matches the `.url("/x")` sub-expression of a builder chain, but the verb is encoded on a separate sibling call (`.post(body)` / `.delete()` / ...). The query intentionally does not walk the chain to recover the verb — it emits `method: 'GET'` for every match, mirroring the Java plugin's `OK_HTTP_PATTERNS` (java.ts). Concretely: `Request.Builder().url("/x").post(body).build()` becomes `http::GET::/x`, not `http::POST::/x`. This is an already-accepted Java parity heuristic, but it was untested on the Kotlin side. This commit: - Adds an anti-overreach test pinning the current behavior: * exactly one consumer is emitted with method=GET * no second http::POST::/x consumer appears - Documents the limitation in kotlin.ts as a "Known limitation" block tied to the test, so a future verb-walk implementation has to update the comment in lockstep with the assertion. Rationale for not implementing verb-walk in this PR: - Verb-walk requires walking sibling call_expression nodes (the `.post(body)` chain), which is the same shape as the deferred WebClient long-form work - Java has the same limitation in production today; fixing only Kotlin would create polyglot drift - A coordinated future PR can add verb-walk to both plugins at once and update both comments + the pin tests together Finding 2 (silent test-skip when tree-sitter-kotlin grammar is unavailable) is intentionally NOT addressed here — same gating pattern was accepted in #1849 for Provider tests, and a coordinated follow-up should add a CI sentinel covering both Provider and Consumer suites in one place. Local validation: - test/unit/group/http-route-extractor.test.ts: 60/60 ✅ - test/unit/group: 540/540 ✅ - npm run format:check: clean ✅ --------- Co-authored-by: henry <zhangwei2017@unipus.cn> |
||
|
|
46eb0ebf56
|
feat(group): add Kotlin Spring HTTP route extraction (named + positional) (#1849)
* feat(group): add Kotlin Spring HTTP route extraction (named + positional)
Mirror the Java Spring named-argument fix for Kotlin Spring Boot
controllers. Adds a new `http-patterns/kotlin.ts` plugin behind the
optional `tree-sitter-kotlin` grammar, registered for `.kt`/`.kts`.
Both annotation forms produce providers:
@RequestMapping("/api") / @GetMapping("/users")
@RequestMapping(path = "/api") / @GetMapping(value = "/users")
@RequestMapping(value = "/api") / @GetMapping(path = "/users")
The Kotlin AST (fwcd/tree-sitter-kotlin) shares one node type
(`value_argument`) for positional and named forms, so the queries
are split:
- positional: anchors `string_literal` as the first named child
of `value_argument` via the immediate-child anchor `.`
- named: explicitly captures `simple_identifier` and constrains
it to `^(path|value)$` via `#match?`, mirroring the same
safety bar enforced by `http-patterns/java.ts` and
`topic-patterns/java.ts`. Without this constraint the query
would also capture non-route attributes like `produces`,
`consumes`, `headers`, `name`, `params`.
`tree-sitter-kotlin` is an optionalDependency (parser-loader.ts,
parse-worker.ts pattern). When the native binding is unavailable
the plugin exports `null` and `index.ts` skips registering
`.kt`/`.kts` so the orchestrator stays healthy.
Scope: providers only. Consumer detection (RestTemplate, WebClient,
OkHttp) on Kotlin call-site ASTs differs enough from Java's
`method_invocation` shape to warrant a separate, focused PR.
Tests: 11 new cases under `provider extraction — source-scan
fallback (Strategy B)`, gated by the kotlin grammar availability.
positive (8)
- class @RequestMapping("/api/v1") (positional)
- class @RequestMapping(path = "/api/v2")
- class @RequestMapping(value = "/orders")
- method @GetMapping(value = "/users")
- method @GetMapping(path = "/users")
- method @PostMapping(path = "/users")
- mixed: class named-arg + method positional
- mixed: class positional + method named-arg
anti-regression (3)
- @GetMapping(produces = "application/json") emits no provider
- @GetMapping(name = "x", value = "/users") emits exactly one provider
- @RequestMapping(path = "/api", name = "myApi") prefix stays /api
Reverse-validated: removing the `(#match? @key "^(path|value)$")`
constraint causes precisely the 3 anti-regression tests to fail.
Local validation:
- test/unit/group/http-route-extractor.test.ts: 54/54
- test/unit/group: 534/534
- npx tsc --noEmit: clean (modulo the pre-existing TS2339 in
user-defined-conversions.ts merged from main, unrelated)
* style(test): apply prettier line wrapping to long itKotlin titles
---------
Co-authored-by: henry <zhangwei2017@unipus.cn>
|
||
|
|
eeea46466b
|
fix(group): handle named annotation args in Java Spring route extraction (#1834)
Some checks are pending
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
* fix(group): handle named annotation args in Java Spring route extraction
The Java HTTP plugin only matched positional `@RequestMapping("/path")`
syntax for class-level prefixes and method-level routes. Named argument
forms (`path = "/path"` and `value = "/path"`) produce an
`element_value_pair` AST node that the tree-sitter queries did not cover,
causing the class prefix to be lost and named-arg method routes to be
missed entirely during cross-repo contract extraction.
Add a second pattern to both SPRING_CLASS_PREFIX_PATTERNS and
SPRING_METHOD_ROUTE_PATTERNS matching the element_value_pair structure.
* fix(group): constrain Spring named-arg query to path/value keys + add regression tests
Address Claude review on PR #1834. The named-argument patterns added
in
|
||
|
|
b1445daf04
|
feat(cpp): rank user-defined conversions (#1829) | ||
|
|
d903152eba
|
fix(typescript): reuse suffix index in scope resolver (#1840)
* fix(typescript): reuse suffix index in scope resolver Build a suffix index once per TypeScript scope-resolution pass and pass it into standard import resolution so package-style imports avoid repeated linear file-list scans.\n\nFixes #1839 * test(typescript): add wiring-level test for scope-resolver suffix index - Test typescriptScopeResolver.resolveImportTarget directly (the real production entry point) with package-style, unresolvable, and relative imports - Use vi.spyOn on buildSuffixIndex to verify the index is built inside the makeTsResolveImportTarget closure — fails if index wiring is removed - Fix existing test to pass real file lists instead of empty arrays alongside the prebuilt index, matching production wiring --------- Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Test <test@example.com> |
||
|
|
7556a8e73a
|
feat(cobol): migrate COBOL to scope-based resolution (regex provider) (#941) (#1835)
* feat(cobol): migrate COBOL to scope-based resolution (regex provider)
Migrate COBOL to scope-based registry resolution, validating the
parse-source-agnostic contract — COBOL uses regex, not tree-sitter,
but implements the same LanguageProvider interface via emitScopeCaptures.
Phase 1-5 complete per #941 DoD.
New files:
languages/cobol/captures.ts — emitScopeCaptures wrapping regex tagger
languages/cobol/interpret.ts — import/type-binding/receiver hooks
languages/cobol/index.ts — barrel export
languages/cobol/scope-resolver.ts — ScopeResolver wiring (9 fields, 3 toggles)
Modified files:
languages/cobol.ts — wire 4 scope-resolution hooks
registry.ts — register cobolScopeResolver
registry-primary-flag.ts — document REGISTRY_PRIMARY_COBOL
Fixtures:
17 fixture files, 30 test cases across 11 required classes
test/integration/resolvers/cobol-scope.test.ts
Tests: 24/24 pass (default + REGISTRY_PRIMARY_COBOL=0)
tsc: zero cobol-specific errors
Shadow mode (GITNEXUS_SHADOW_MODE=1): zero crashes
Regex perf: 10K-line file in 408ms (threshold: 2000ms)
NOT added to MIGRATED_LANGUAGES — REGISTRY_PRIMARY_COBOL env var only.
* chore(cobol): add COBOL to MIGRATED_LANGUAGES
* Revert "chore(cobol): add COBOL to MIGRATED_LANGUAGES"
This reverts commit
|
||
|
|
681a352006
|
fix(worker): analyze native worker aborts (#1833)
* fix(analyze): avoid native aborts on generated worker bundles Retire timed-out parse workers instead of force-terminating native parser state, and skip Monaco generated worker bundles by default while preserving explicit .gitnexusignore negation overrides. Constraint: Node native tree-sitter bindings can abort the process when a timed-out worker is terminated while inside parser state. Rejected: Falling back to sequential parsing for native stalls | it can move the same native crash onto the main thread. Confidence: high Scope-risk: moderate Directive: Keep timeout recovery from force-terminating workers until they return to JS or exit naturally. Tested: npm test; npx tsc --noEmit; npm run build; targeted analyze on /Users/wangxc/Code/keep; gitnexus detect_changes --scope staged Not-tested: Node 22 LTS runtime and non-macOS platforms * fix(worker): bound retired parser worker lifetimes Keep timeout recovery from immediately terminating workers that may still be inside native parser state, while making terminal pool shutdown own retired worker cleanup so long-lived processes do not accumulate retired threads. Constraint: Claude review on PR #1833 required retiredWorkers cleanup in pool.terminate() and tripBreaker() without regressing no-immediate-terminate timeout safety. Rejected: clearing the retiredWorkers set without terminating | would remove JS bookkeeping while leaking the underlying worker thread. Confidence: high Scope-risk: moderate Directive: Preserve the distinction between recoverable timeout retirement and terminal pool shutdown; do not reintroduce immediate terminate in removeWorkerFromSlot(..., 'retire'). Tested: npx vitest run test/unit/worker-pool-timeout-retire.test.ts; npx vitest run test/unit/worker-pool-timeout-retire.test.ts test/unit/worker-pool-resilience.test.ts test/unit/worker-pool-cumulative-timeout.test.ts test/unit/worker-pool-slot-generation.test.ts; npx tsc --noEmit; npm run build; npx prettier --check src/core/ingestion/workers/worker-pool.ts test/unit/worker-pool-timeout-retire.test.ts ../docs/todo/pr-1833-retired-worker-cleanup-plan.md; npx eslint src/core/ingestion/workers/worker-pool.ts test/unit/worker-pool-timeout-retire.test.ts; gitnexus detect_changes --scope staged. Not-tested: npm test full suite did not complete green in this environment; two runs each had one unrelated test/unit/hooks.test.ts parseHookOutput null failure, and each failed hook test passed when rerun in isolation. * ci: retrigger checks Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: wangxc <wangxc_a_bj@si-tech.com.cn> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Test <test@example.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
5e012c373b
|
fix(cli): detect missing LadybugDB native binary at startup with actionable guidance (#835) (#1837)
* fix(cli): detect missing LadybugDB native binary at startup with actionable guidance (#835) Add checkLbugNative() pre-flight that verifies lbugjs.node exists before any command transitively imports @ladybugdb/core. When missing (bun default install, --ignore-scripts), prints repair instructions instead of crashing with ERR_DLOPEN_FAILED. Also enhances `gitnexus doctor` to probe the native binary status. * fix(review): guard eval-server, un-guard status command eval-server transitively loads @ladybugdb/core and needs the native binary check. status only reads filesystem metadata and should remain accessible when the binary is missing. * fix(lint): use console.log instead of console.error in native check gate The project eslint config only allows console.log. * fix(cli): route native-check to stderr and validate binary loadability Fixes two Codex adversarial review findings: 1. Native-check failure message now goes to process.stderr.write instead of console.log, preventing MCP stdout protocol contamination. 2. checkLbugNative now attempts a controlled require() probe after the existence check. Truncated, ABI-mismatched, or wrong-platform binaries produce actionable guidance instead of passing through to crash at process.dlopen. --------- Co-authored-by: Test <test@example.com> |
||
|
|
05d269ec28
|
feat(ruby): migrate Ruby to scope-based resolution (RFC #909 Ring 3) (#1831)
* feat(ruby): migrate Ruby to scope-based resolution (RFC #909 Ring 3) Implement the full scope-resolution pipeline for Ruby following the PR #1639 (Rust migration) standard, targeting registration in MIGRATED_LANGUAGES with 100% scope parity. Scope resolver hooks (languages/ruby/): - query.ts: RUBY_SCOPE_QUERY covering scopes, declarations, imports, type-bindings (constructor inference via .new), and references - captures.ts: emitRubyScopeCaptures orchestrator with import decomposition, receiver-binding synthesis, method reclassification, and arity metadata for both declarations and calls - receiver-binding.ts: self type-binding synthesis for instance methods, singleton methods, and class << self blocks - interpret.ts: interpretRubyImport (wildcard semantics) and interpretRubyTypeBinding (YARD, constructor, alias sources) - import-target.ts: resolveRubyImportTarget adapting the existing suffix resolver for require/require_relative/load - merge-bindings.ts: tier-based shadowing (local > namespace > import) - arity.ts: Ruby arity check with *args/**kwargs/&block support - scope-resolver.ts: rubyScopeResolver with custom buildRubyMro (kind-aware IMPLEMENTS partitioning: prepend > direct > include; extend excluded from instance MRO per legacy semantics) - simple-hooks.ts: bindingScopeFor, importOwningScope, receiverBinding Wiring: - ruby.ts provider gains 7 scope-resolution hooks - Registered in SCOPE_RESOLVERS map and MIGRATED_LANGUAGES - 127 legacy tests wired with createResolverParityIt('ruby') - 27 new scope-specific tests in ruby-scope.test.ts Parity: 89/127 legacy tests pass under registry-primary; 38 are heritage/property/YARD gaps expected in V1. All 127 pass under legacy. Closes #931 * feat(ruby): add emitHeritageEdges hook, YARD parsing, bare calls, property emission Extend the scope-resolution pipeline with a new optional `emitHeritageEdges` hook (ScopeResolver contract + run.ts wiring) that runs between `preEmitInheritanceEdges` and `buildMro`. This lets languages whose heritage declarations are syntactic method calls (Ruby include/extend/prepend) emit IMPLEMENTS edges from the scope-resolver without touching the legacy pipeline. Ruby scope-resolution improvements: - Heritage: intercept include/extend/prepend in captures.ts, encode as special imports, emit IMPLEMENTS edges via emitHeritageEdges hook - Properties: intercept attr_accessor/attr_reader/attr_writer, emit Property nodes + HAS_PROPERTY edges via the same hook - Bare calls: add (body_statement (identifier)) capture to scope query, matching the legacy query pattern for zero-arity method calls - YARD parsing: second-pass comment scanner for @param/@return/@type annotations with findFollowingMethod that handles body_statement nesting - Query fixes: @declaration.trait for modules (was @declaration.module which normalizeNodeLabel didn't recognize), constant constructor bindings (SERVICE = UserService.new), call-return inference Parity: 114/127 legacy tests pass under registry-primary (up from 89). Remaining 13 are advanced type-inference chain resolution (compound receiver, cross-file return-type propagation, for-in element types). * feat(ruby): achieve 100% scope-resolution parity (127/127) Fix all 13 remaining type-inference failures: - Add expandsWildcardTo hook (expandRubyWildcardNames) so finalize can materialize individual bindings from require/require_relative wildcard imports, unblocking cross-file return-type propagation - Add member-call-return type binding synthesis in captures.ts for assignments like `x = obj.method()` — enables compound receiver chaining through member call return types - Add YARD @return support for attr_accessor/attr_reader/attr_writer calls, creating field-type bindings for chain resolution - Add @declaration.property captures alongside __property__ imports so properties register in localDefs → model.fields → write-access - Add constructor-return inference for methods ending with Foo.new() - Add for-loop variable type aliasing in scope query - Rebuild nodeLookup after emitHeritageEdges in run.ts so Property nodes created by the heritage hook are visible to downstream passes - Extend compound-receiver resolver to handle compound member-call rawNames with () and increase max depth from 4 to 8 - Extend receiver-bound-calls Case 3b for compound rawNames All 127 legacy Ruby tests pass under both REGISTRY_PRIMARY_RUBY=0 (legacy) and =1 (registry-primary). Ruby is now fully registered in MIGRATED_LANGUAGES with 100% scope parity. * test(ruby): add pipeline benchmark exercising heritage emission Synthetic Ruby codebases at 100/250/500 files with include + extend + prepend mixins, diamond mixin patterns (shared BaseMixin modules), attr_accessor properties, YARD annotations, and cross-file imports. Strict equality assertions verify exact IMPLEMENTS and HAS_PROPERTY edge counts: 4 IMPLEMENTS per class (include x2, extend, prepend) plus 1 per non-base mixin module, 3 HAS_PROPERTY per class. Dedup in emitRubyMixinEdges prevents double-counting when the worker path (repos >= 15 files) already created Property/IMPLEMENTS edges before scope-resolution runs. Scaling: 0.76x and 1.40x (both linear, well under 3x threshold). * ci: retrigger build * fix(ci): resolve format, registry-primary-flag, and sequential-mixin test failures - Run prettier on all changed files (captures.ts, run.ts, ruby-scope.test.ts, ruby.test.ts, ruby-pipeline-benchmark.test.ts) - Update registry-primary-flag.test.ts: use Swift (not in MIGRATED_LANGUAGES) instead of Ruby for the isolation and env-var mutation tests - Pin ruby-sequential-mixin.test.ts to REGISTRY_PRIMARY_RUBY=0 (legacy mode) since it tests inferImplicitReceiver + selectDispatch hooks that live in the legacy call-processor (gated off under registry-primary) --------- Co-authored-by: Test <test@example.com> |
||
|
|
d5b2edddc4
|
fix(test): use retry cleanup in antigravity e2e to prevent ENOTEMPTY flake (#1838)
* fix(test): use retry cleanup in antigravity e2e to prevent ENOTEMPTY flake Replace bare `fsp.rm` / `fs.rmSync` in antigravity-hook-e2e.test.ts afterAll with `cleanupTempDir` / `cleanupTempDirSync` from test-db.ts which retry with backoff on transient filesystem errors. Also make `shouldSwallowCleanupError` swallow ENOTEMPTY on all platforms (was Windows-only). The CI failure on macOS was ENOTEMPTY on a deeply nested node-gyp cache directory inside the temp HOME — a cleanup-time race that retries usually resolve, but the final attempt must not crash the test suite if the race persists. * fix: restore fsp import needed for mkdtemp/mkdir --------- Co-authored-by: Test <test@example.com> |
||
|
|
4870879b21
|
fix(wiki): add budget-aware grouping to prevent context overflow on large repos (#627) (#1832)
* fix(wiki): add budget-aware grouping to prevent context overflow on large repos (#627) When the grouping prompt exceeds 100k tokens (e.g. Apache TVM with ~2,378 files and ~306k estimated tokens), batch files by top-level directory and issue one LLM call per batch. Partial results are deterministically merged; any batch failure falls back to directory-based grouping. * fix(wiki): address review findings — exact assertions, progress fix, error logging - Replace bounds-only .toBeGreaterThan assertions with exact .toBe values - Add per-batch budget compliance assertion for sub-batch case - Add assertion that partial LLM results don't leak through nuclear fallback - Pass fixedPercent/percentRange to streamOpts in batched LLM calls - Log batch failure in onProgress before falling back to directory grouping - Strengthen mergeGroupings dedup test from .toContain to exact .toEqual * chore(autofix): apply prettier + eslint fixes via /autofix command * fix(wiki): prevent slug collisions and handle single-file oversize in batched grouping mergeGroupings now normalizes module keys by slug so case/punctuation variants ("API Routes" vs "API routes") merge into one module instead of producing colliding .md files. batchFilesForGrouping now truncates per-file symbol lists via binary search when a single file exceeds GROUPING_TOKEN_BUDGET, so every LLM request stays within the context window. * style(wiki): apply prettier formatting to generator.ts --------- Co-authored-by: Test <test@example.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
c916c88361
|
feat(mcp): add limit/offset/summaryOnly pagination to impact tool (#1818)
* feat(mcp): add limit/offset/summaryOnly pagination to impact tool (#414) The impact tool returns unbounded byDepth arrays for hub symbols (base error classes, shared utilities), producing 140KB+ responses that get truncated by MCP clients. maxDepth alone does not help when most dependents are at depth 1. Add three new parameters: - summaryOnly: returns counts/risk/processes/modules without byDepth - limit: caps symbols per depth level (default 100) - offset: skips symbols for pagination Also adds byDepthCounts to all responses so agents can see total counts even when the symbol list is paginated or omitted. Closes #414 * fix(mcp): prevent pagination from silently truncating cross-repo impact Address review findings on #1818: - F1 (blocker): _runImpactBFS no longer defaults to limit 100 when limit is not set — only _impactImpl (MCP entry) applies the default. Internal callers (impactByUid, group impact) get complete results. GroupToolPort.impact interface gains optional limit param, and cross-impact.ts passes limit: 10000 for local UID collection. - F2 (blocker): tool description updated — byDepth is now documented as paginated, not 'all affected symbols'. - F3: impactByUid calls _runImpactBFS without limit, so Phase-2 neighbor results are no longer capped at 100. - F4: pagination metadata now appears when offset > 0 (head truncation), not just tail truncation. Pagination.limit is null when uncapped. - F5: limit/offset schema types changed from number to integer; Math.trunc applied in implementation as defense-in-depth. - F6: 7 new tests — multi-depth pagination, offset-only truncation, offset past end, float inputs, _runImpactBFS internal uncapped path, collectImpactSymbolUids with paginated vs complete data. * fix(mcp): NaN guard on pagination params, complete GroupToolPort interface - Add Number.isFinite guard to limit/offset in _runImpactBFS so NaN inputs fall through to uncapped/zero defaults instead of producing silent empty byDepth with no truncation signal. - Add offset and summaryOnly to GroupToolPort.impact interface to match the implementation and prevent silent param loss at the port boundary. - Replace bounds-only toBeLessThan assertion with exact byDepthCounts and pagination assertions per DoD §2.7. * fix(mcp): address remaining review findings for impact pagination - #3: Forward limit/offset/summaryOnly through callToolAtGroupRepo so group-mode MCP callers can use the new pagination params. - #4: Extract GROUP_LOCAL_PHASE_LIMIT constant from magic 10000 in cross-impact.ts with a comment explaining the intent. - #7: eval-server formatImpactResult uses byDepthCounts[depth] for the 'and N more' suffix instead of paginated slice length. - #8: Extract ImpactParams interface from duplicate inline type definitions in impact() and _impactImpl(). - #9: Add --limit, --offset, --summary-only CLI flags to the impact command with i18n help strings (en + zh-CN). - #10: Clarify in tool description that limit/offset apply per depth level, not per total result set. * chore(autofix): apply prettier + eslint fixes via /autofix command * @ fix(mcp): address Copilot review feedback on impact pagination - Sanitize limit/offset with Number.isFinite in _impactImpl to prevent NaN passthrough from bypassing the default limit of 100 - Omit pagination.limit field instead of emitting null when paginationLimit is Infinity, keeping the response schema consistent - Move GROUP_LOCAL_PHASE_LIMIT after all imports in cross-impact.ts - Stop forwarding limit/offset/summaryOnly to group-mode impact since runGroupImpact overrides limit with GROUP_LOCAL_PHASE_LIMIT for UID collection and does not re-paginate - Validate CLI parseInt results with Number.isFinite before passing to the backend, falling back to undefined so defaults apply - Use byDepthCounts to decide whether to render depth sections in formatImpactResult, handling empty pages from offset past end @ * @ fix(mcp): address code review findings on impact pagination - Fix formatImpactResult "N more" count: use Math.min(items.length, 12) instead of hardcoded 12, so paginated pages with <12 items show the correct remaining count - Detect summaryOnly responses (byDepth absent, byDepthCounts present) and show a summary-mode message instead of misleading "(0 items on this page — adjust offset)" per depth level - Document that limit/offset/summaryOnly are single-repo only and ignored in group mode (@groupName) in MCP tool schema descriptions - List byDepthCounts in summaryOnly description and note byDepth absence when summaryOnly is true - Remove unused limit/offset/summaryOnly from GroupToolPort.impact interface since they are never forwarded to group impact - Deduplicate parseInt calls in CLI tool.ts: extract to local variables with consistent optional-chain usage @ * chore(autofix): apply prettier + eslint fixes via /autofix command * @ fix(group): restore limit in GroupToolPort.impact interface cross-impact.ts passes limit: GROUP_LOCAL_PHASE_LIMIT through the GroupToolPort.impact interface for UID collection. Only offset and summaryOnly were truly unused — limit must stay. @ * @ docs: add limit/offset/summaryOnly to impact tool options in README @ --------- Co-authored-by: Test <test@example.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
d4449b4ec8
|
fix(lbug): resolve non-ASCII paths for KuzuDB on Windows (#1811) (#1817)
* fix(lbug): resolve non-ASCII paths to 8.3 short form on Windows (#1811) KuzuDB's native C++ layer uses ANSI file APIs (fopen) on Windows. When the repo path contains CJK or other non-ASCII characters, the UTF-8 bytes from Node.js are misinterpreted as the system's Active Code Page (e.g. GBK), producing a garbled path — "Error 3: The system cannot find the path specified." Add `toNativeSafePath()` which converts non-ASCII paths to their Windows 8.3 short-name form (all-ASCII) before passing them to the native layer. Applied to both the database open path and the COPY CSV paths. No-ops on non-Windows and on all-ASCII paths. Closes #1811 * test(lbug): add unit + integration tests for non-ASCII path handling (#1811) - Unit tests for toNativeSafePath: ASCII passthrough, non-Windows no-op, Windows short-path conversion, nonexistent-path fallback - Integration test: full initLbug + loadGraphToLbug round-trip with CJK characters in the storage path — runs on all platforms - Fix toNativeSafePath to reject cmd.exe output containing '?' chars (replacement for unrepresentable Unicode in the console code page) - Register integration test in vitest lbug-db project and cross-platform-tests.ts matrix * chore(autofix): apply prettier + eslint fixes via /autofix command * feat(lbug): junction fallback, tmpdir CSV staging, pool-adapter coverage (#1811) U1+U4: toNativeSafePath now tries 8.3 short path → NTFS junction fallback → diagnostic warning. Junctions target path.dirname(p) and reconstruct the leaf. Handles EEXIST races. Registers cleanup on exit/SIGTERM/SIGINT. Orphan scan on first call removes stale junctions from prior crashes. U2: loadGraphToLbug redirects csvDir to os.tmpdir() when storagePath contains non-ASCII on Windows, avoiding non-ASCII characters in COPY FROM paths entirely. U3: All 4 createLbugDatabase call sites in pool-adapter.ts now wrap dbPath with toNativeSafePath. * fix(test): fix CI failures from toNativeSafePath addition (#1811) - Fix lbug-non-ascii-path integration test: use CodeRelation (actual relationship table name) instead of CALLS - Add toNativeSafePath to lbug-config.js mocks in pool-wal-recovery and lbug-pool-win-fts-probe tests — pool-adapter now imports it * fix(lbug): sanitize path before cmd.exe shell expansion (CodeQL) Reject paths containing cmd.exe metacharacters (" % | & < > ^) before interpolating into the `for %I` short-path command. Prevents command injection via crafted path names. * fix(lbug): address code review findings in non-ASCII path implementation - U1: Use process.exit(0) on Windows instead of process.kill re-raise (SIGTERM forcefully kills on Windows, handlers never fire) - U2: Pass safePath to openWithLockRetry so sidecar sweep targets the path KuzuDB actually opened, not the original non-ASCII path - U3: Skip junction creation in worker threads (isMainThread guard) to prevent junction leaks from pool-adapter workers - U4: Replace existsSync with lstatSync in orphan scan to avoid 30s blocking on unreachable UNC network targets * chore(autofix): apply prettier + eslint fixes via /autofix command * fix(lbug): correct SIGTERM exit code and run Prettier (#1811) - Use exit code 143 (SIGTERM) / 130 (SIGINT) on Windows instead of 0 so termination is not masked as success - Run Prettier to fix formatting (CI Gate blocker) * fix(lbug): eliminate CodeQL command-injection taint in tryShortPath Pass the path via GITNEXUS_SP environment variable instead of interpolating it into the cmd.exe command string. The FOR loop reads %GITNEXUS_SP% from the environment, so the command text is entirely static — no user-controlled data in the shell command. Also removes CMD_UNSAFE_RE since the env var approach makes character-level sanitization unnecessary. --------- Co-authored-by: Test <test@example.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
50c6acb108
|
feat(setup): implement antigravity integration setup and hook adapter… (#1730)
* feat(setup): implement antigravity integration setup and hook adapter for gitnexus * docs(readme): list Antigravity in supported editors * test(setup-antigravity): pin platform per-test to fix Windows CI failure The MCP entry assertion expected `npx` directly, but on Windows `getMcpEntry()` wraps it as `cmd /c npx ...`, which broke the Windows runner. Pin platform to darwin in beforeEach so the existing assertion is deterministic, restore the descriptor in afterEach, and add a parity test for the win32 cmd-wrapper shape. * fix(antigravity): align hook adapter to Gemini CLI schema + fix Windows CI Rebase the Antigravity integration on the canonical Gemini CLI hooks contract (https://geminicli.com/docs/hooks/reference/), which is the documented schema Antigravity 2.0 inherits: - Hook adapter: replace PreToolUse/PostToolUse with the single AfterTool event. BeforeTool has no documented context-injection channel in the Gemini contract, so augmentation runs in AfterTool where hookSpecificOutput.additionalContext is the documented way to append text to the tool result the agent reads. Stale-index hints land in the same channel (so the agent sees them) and are mirrored to stderr for terminal users. Tool-name matcher updated to Gemini CLI snake_case (search_file_content|glob|run_shell_command). - Setup: write hooks to ~/.gemini/settings.json under canonical hooks.AfterTool[] (replaces the ad-hoc hooks.json top-level group). Polite-neighbor merge preserves existing user hooks. Also copy win-rm-list-json.ps1 alongside hook-db-lock-probe.cjs so the Windows MCP server ownership probe doesn't silently fail open. - Tests: 17 regression tests covering MCP write, win32 shape, hook schema, polite-neighbor merge, idempotency, adapter context emission, stale-index hint, and skill layout. - README: footnote documenting the AfterTool design choice and a link to the Gemini CLI hooks reference. Windows CI fix: installSkillsTo previously used glob('*.md') + glob('*/SKILL.md'), which returned zero matches under the Windows runner's temp paths (8.3 short-name like RUNNER~1). Replace with fs.readdir + dirent type checks — same behavior, no path quirks. This fixes the only failing Windows job on the PR. * fix(antigravity): address PR review — windowsHide, stale docs, dead code Addresses the production-readiness review findings on PR #1730: - F1 (blocker): add windowsHide:true to all four spawnSync sites in the Antigravity hook adapter (findCanonicalRepoRoot, runGitNexusCli's two branches, buildStaleIndexHint) so they don't flash console windows on Windows. Matches the fix #1794 already on main for the Claude hook. - F2 (blocker): update gitnexus/README.md editor table to say AfterTool and link the Gemini CLI hooks reference. The published README had drifted to the pre-c1872b4 PreToolUse + PostToolUse schema. - F3: rewrite the stale ~/.gemini block comment in setup.ts. It still described the old hooks.json + gitnexus group + grep_search design. - F4: remove grep_search dead code from extractPattern and its doc comment. The registered matcher is search_file_content|glob|run_shell_command, so grep_search would never be invoked. - F5: annotate timeout:10000 with a ms-unit comment noting Gemini CLI uses milliseconds (Claude Code uses seconds). - F6: add the GITNEXUS_DEBUG branch to extractAugmentContext for parity with the Claude adapter, so suppressed augment stderr is recoverable. - F7: stageAdapter test helper now copies win-rm-list-json.ps1 alongside the .cjs helpers, so the adapter's Windows lock-probe path isn't a silent fail-open in child-process smoke tests. * test(antigravity): add integration tests and register in cross-platform matrix Adds end-to-end coverage on top of the unit-level tests, per maintainer request: - test/integration/setup-antigravity.test.ts (10 tests): exercises the real setupCommand() against a temp HOME with ~/.gemini/antigravity/ present. Verifies mcp_config.json shape, ~/.gemini/settings.json AfterTool entry, adapter + helpers + win-rm-list-json.ps1 copy, baked-in cliPath rewrite (issue #108 regression class), skill layout, polite-neighbor merge against existing user hooks, idempotency, skip-when-absent, corrupt-file safety, and key preservation. - test/integration/antigravity-hook-e2e.test.ts (19 tests): runs the full install-then-execute flow — invokes setupCommand to lay down the adapter + helpers, then spawns the INSTALLED adapter as a real child process against a temp git repo + .gitnexus/. The source adapter cannot be spawned directly (it requires sibling .cjs helpers that only live in hooks/claude/); install-then-spawn mirrors the production codepath. Covers staleness detection across all five git mutation types, --embeddings propagation, polite skip on toolResponse.error / exit_code !== 0, augment crash-free behavior, cwd validation, corrupted/missing meta.json, unknown event names, empty stdin, and the no-.gitnexus deep-nested case. - scripts/cross-platform-tests.ts: registers all three antigravity test files (unit in PLATFORM_LOGIC, two integration files in SPAWN_CLI) so Windows and macOS CI exercise them on every run. * fix(antigravity): review fixes — dedup, silent-failure guard, type coercion, glob filter - Delete mergeGeminiSettingsHooks (verbatim copy of mergeHooksJsonc), replace call site with the original - Unify geminiHasGitnexusHook into hasGitnexusHook with commandFragment parameter; delete the duplicate - Guard against silent adapter-copy failure: verify the adapter file exists before registering the AfterTool hook entry in settings.json; surface helper copy errors instead of swallowing - Fix toolSucceeded type coercion: use Number() so string exit_code values from Gemini CLI are handled correctly - Align glob tool extractPattern with Claude adapter's restrictive regex filter (/[*\/]([a-zA-Z][a-zA-Z0-9_-]{2,})/) - Remove bounds-only toBeGreaterThan(0) assertion (DoD §2.7) - Add antigravity adapter to HOOK_FILES windowsHide regression list * chore(autofix): apply prettier + eslint fixes via /autofix command * chore: trigger CI --------- Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Test <test@example.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
baf57bec88
|
feat(rust): Migrate Rust to scope-based resolution (RFC #909 Ring 3) (#1639)
* Initial plan * feat: add Rust scope-resolution hooks (RFC #909 Ring 3) Implement the scope-based resolution pipeline for Rust, following the established pattern from Go and other migrated languages. New files in gitnexus/src/core/ingestion/languages/rust/: - query.ts: tree-sitter scope query covering scopes, declarations, imports, type bindings, and references - cache-stats.ts: parse cache hit/miss counters - import-decomposer.ts: decomposes use declarations into individual import captures (handles grouped, wildcard, renamed, re-exported) - receiver-binding.ts: synthesizes self type bindings for impl methods - interpret.ts: interprets captures into ParsedImport/ParsedTypeBinding - arity.ts: arity compatibility checker (no overloading in Rust) - merge-bindings.ts: local-shadows-import binding merge strategy - simple-hooks.ts: binding scope, import owning scope, receiver binding - import-target.ts: resolves Rust module paths (crate/super/self) - method-owners.ts: bridges impl block methods to struct defs - captures.ts: main emit function with import decomposition and self-binding synthesis - scope-resolver.ts: ScopeResolver implementation - index.ts: barrel re-exports Wiring changes: - rust.ts: add scope hook imports and properties to defineLanguage - registry.ts: register rustScopeResolver in SCOPE_RESOLVERS - registry-primary-flag.ts: add Rust to MIGRATED_LANGUAGES Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * feat(LANG-rust): add scope-resolution hooks and register Rust ScopeResolver Implements RFC #909 Ring 3 deliverables: - query.ts: tree-sitter scope query for Rust - captures.ts: emitRustScopeCaptures with method reclassification - import-decomposer.ts: use statement decomposition (groups, renames, globs) - interpret.ts: interpretRustImport + interpretRustTypeBinding - import-target.ts: crate/module/super/self path resolution - receiver-binding.ts: self/&self/&mut self receiver synthesis - method-owners.ts: impl block → struct ownership bridging - arity.ts: no-overloading arity check - merge-bindings.ts: local > import > wildcard binding precedence - simple-hooks.ts: binding/import scope, receiver binding - scope-resolver.ts: ScopeResolver contract implementation - Wired into rustProvider (rust.ts) with scope hooks - Registered in SCOPE_RESOLVERS (pipeline/registry.ts) - NOT yet added to MIGRATED_LANGUAGES (29 advanced pattern tests pending) Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/8f14b730-79d4-4356-9505-325750d71f84 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * Add Rust scope-resolution integration tests (RFC #909 Ring 3) Tests cover the core deliverables for the Rust scope-resolution pipeline: - impl blocks and trait implementations - Module resolution (crate::, super::, self::) - Struct fields and type bindings - Self/&self/&mut self receiver binding - Generic functions (V1 ignores generic args) - Grouped imports (use foo::{A, B}) - Renamed imports (use foo::Bar as Baz) - Arity checking (no overloading) - Struct literal constructor inference - Return type inference - Scoped/qualified calls (Foo::new()) - Enum declarations - Multiple impl blocks - Free function calls - Typed let bindings Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * test(LANG-rust): add 28 scope-resolution integration tests Covers 15 test suites validating: impl blocks, trait impls, grouped imports, renamed imports, module resolution, receiver binding, arity filtering, struct literal inference, return type inference, qualified calls, struct fields, enums, multiple impl blocks, free calls, and typed let bindings. Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/8f14b730-79d4-4356-9505-325750d71f84 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * feat(LANG-rust): add implicit crate path fallback, 35 scope tests - Import resolver now falls back to crate-relative for unqualified module paths (Rust 2015 edition compat) - Added 7 more test cases: re-exports, shadowing, closures, default trait methods (35 total, exceeding ≥30 requirement) Agent-Logs-Url: https://github.com/abhigyanpatwari/GitNexus/sessions/8f14b730-79d4-4356-9505-325750d71f84 Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> * feat(rust): add Rust to MIGRATED_LANGUAGES with 100% scope-resolution parity 35/35 integration tests pass under both REGISTRY_PRIMARY_RUST=0 (legacy) and =1 (scope-resolution). Rust scope-resolution is now the default production call-resolution path. * test(rust): add pipeline benchmark matching PHP benchmark pattern Generates synthetic Rust codebases at 100/250/500 files with structs, impl blocks, traits, cross-module use declarations, and method calls. Measures wall-clock time, peak heap, and scaling ratios. Results: sub-linear scaling (0.79x ratio), 500 files in 3.8s with workers, 110MB peak heap. Gated by GITNEXUS_BENCH=1. * chore(autofix): apply prettier + eslint fixes via /autofix command * perf(rust): optimize captures, type normalization, and method-owner linking - Cache findEnclosingImpl result to avoid duplicate tree walk per function - Avoid double namedChild accessor call in struct field arity counting - Extract regex constants (REF_PREFIX_RE, PTR_PREFIX_RE) from hot normalization loops - Replace O(s) suffix-match scan with O(1) Map lookup in method-owner linking Benchmark: 500 files 3806ms → 2970ms (-22%), 250 files 2432ms → 1752ms (-28%) * fix(rust): resolve CodeQL alerts — file-system race and dead code - Remove existsSync+appendFileSync/writeFileSync TOCTOU in benchmark fixture generator; appendFileSync creates if missing - Remove always-true guard on computeRustCallArity return; narrow return type from number|undefined to number - Remove no-op .filter() in fixture generator * feat(rust): hoist impl return-type bindings to struct scope for chain resolution Synthesize a module-level duplicate of @type-binding.return captures for methods inside impl blocks. The scope-extractor's auto-hoist places these on the struct's Class scope, making them visible to the compound receiver chain resolver via classScopeByDefId. Without this, method return types are only on the impl block scope (which has no class-like def and is not indexed by classScopeByDefId), so chains like svc.get_user().save() cannot follow the intermediate return type. This is the structural prerequisite for chain resolution, pattern binding, and for-loop element-type parity (28 remaining tests). The cross-file return-type propagation step still needs wiring for full parity. * fix(rust): use implNode anchor for return-type hoisting — fixes chain resolution Use the enclosing impl_item node (not tree.rootNode) as the synthetic capture anchor. The scope-extractor's auto-hoist places bindings whose anchor matches the innermost scope on the parent scope. With implNode, the binding lands on the Module scope (parent of impl's Class scope), giving declaredAtScope the correct context for findClassBindingInScope to resolve the return type across the scope chain. Unlocks: chain calls (svc.get_user().save()), return-type inference, assignment chains, cross-file binding propagation, call-result binding, deep field chains — 28→27 failing tests. * feat(rust): add populateRangeBindings hook + .await query capture Implement populateRustRangeBindings (Phase 2 hook, same pattern as Go's populateGoRangeBindings) to populate type bindings that need runtime type lookup — for-loop element types, if-let/while-let captured patterns, match arm patterns, and struct destructuring field types. Also add tree-sitter query capture for let x = fn().await — unwraps await_expression to find the inner call_expression. 28→19 failing tests: fixes for-loop Tier 1c, .iter()/.into_iter(), async .await, if-let captured_pattern. * fix(rust): fix tuple_struct_pattern variable extraction + Result<T,E> raw type lookup - Skip wrapper type identifier when finding bound variable in tuple_struct_pattern (Some(user) was binding 'Some' not 'user') - Add lookupRawParameterType to read unstripped generic type from AST for Ok/Err pattern resolution (normalizeRustTypeName strips generics) 28→15 failing tests: fixes if-let Some, if-let Ok/Err, match arm patterns. * fix(rust): fix match_arm parent traversal + raw return type for for-loop calls - Walk up from match_arm through match_block to find match_expression for source variable extraction - Add lookupRawFunctionReturnType to find unstripped return type from AST for same-file for-loop call expression iterables 28→14 failing tests. * feat(rust): inject field type bindings on struct scopes for chain resolution Walk struct_item AST nodes and inject field types (e.g., address -> Address) as typeBindings on the struct's Class scope. The compound receiver chain resolver uses these to follow field chains like user.address.save(). Also fixes: match_arm parent traversal to match_expression, lookupFieldType to check typeBindings first. 28→11 failing tests: fixes field type chains, deep chains, struct destructuring. * feat(rust): cross-file return type lookup for for-loop call iterables Build allReturnTypes map across all parsedFiles in Phase 2 first pass, then use it to resolve for-loop iterables like `for x in get_fn()` when get_fn is defined in another file. 28→9 failing tests. * feat(rust): cross-file field type map for struct destructuring Build allFieldTypes map across parsedFiles in Phase 2 first pass. Used by processStructDestructuring to resolve `let Point { x, y } = p` when Point is defined in another file. 28→7 failing tests. * fix(rust): compound assignment write capture + pending assignment fixpoint - Add compound_assignment_expr query for +=, -=, etc. field writes - Add processPendingAssignments with 3-pass fixpoint for field access and method call result variable bindings (let addr = user.address, let city = addr.get_city()) 28→5 failing tests. * fix(rust): identity method return-type bindings for unwrap/expect chains Inject unwrap/expect/clone/as_ref/as_mut as return-type bindings on struct scopes that return the struct's own type. Since normalizeRustTypeName already unwraps Option<T> → T, calling .unwrap() on a value typed as T is semantically an identity — the return type equals the receiver type. 28→3 failing tests: fixes user.unwrap().save() and repo.unwrap().save() chains. * fix(rust): skip enum variant call-return bindings + cross-file pending assignments + identity alias - Skip Some/None/Ok/Err in @type-binding.call-return — these are enum variant constructors, not type names; let the annotation capture win - Add identifier alias handler in processPendingAssignments for `let alias = opt` chains - Cross-file field type and method return type lookup in pending assignment fixpoint via findFieldTypeAcrossFiles/findMethodReturnTypeAcrossFiles - Identity method bindings (unwrap/expect/clone) on struct scopes 155/156 tests pass (99.4%). Remaining: trait default method dispatch via MRO (repo.count() where count has default impl on Repository trait). * feat(rust): 100% scope-resolution parity — MRO with same-file IMPLEMENTS + trait default method reclassification - Add buildRustMro that includes same-file IMPLEMENTS edges in the MRO chain, so trait default methods (e.g., repo.count()) resolve through the struct → trait ancestry walk - Only add IMPLEMENTS to MRO when struct and trait are in the same file; cross-file trait calls require the trait to be imported (Rust semantics) - Reclassify function_item inside trait_item as @declaration.method so default trait methods register in the model's methods lookup 156/156 legacy parity tests pass. 35/35 scope tests pass. 0 regressions. * fix(rust): address code review findings — null guard, name collision, scope order - Fix Array.find() null guard: check === undefined not === null in processCapturedPattern (find() never returns null) - Fix allReturnTypes/allFieldTypes name collision: delete entry on second occurrence so colliding names (new, default, Config) produce no result rather than a wrong result - Fix lookupTypeInScopes: search function scope then module scope only, skip unrelated Class scopes that could shadow names from other functions --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: magyargergo <11230420+magyargergo@users.noreply.github.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Test <test@example.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
5ce448a93a
|
feat(wiki): support local Claude and Codex providers (#1769)
* feat(wiki): support local Claude and Codex providers * chore(autofix): apply prettier + eslint fixes via /autofix command * fix(wiki): address local CLI provider review findings - Add subprocess timeout: LocalCLIConfig gains requestTimeoutMs, runLocalCLI sets a kill timer that rejects with an actionable error matching the HTTP timeout message format. --timeout is no longer silently ignored for claude/codex providers. - Add windowsHide: true to spawn() to prevent console window flash on Windows, matching cursor-client.ts behavior. - Skip GITNEXUS_MODEL env var for local providers so a user's OpenAI model name doesn't cross-contaminate claude/codex CLI invocations. Precedence for local providers: --model → savedLocalModel → ''. - Guard against empty stdout: reject with actionable error when CLI exits 0 but produces no output, preventing silent empty wiki pages. * fix(wiki): address deep-review findings in local CLI providers - Move empty-output guard from runLocalCLI to per-provider callers so Codex can read --output-last-message file even when stdout is empty - Merge existing config in interactive setup (local + Azure paths) to prevent saveCLIConfig from erasing previously saved API keys - Use StringDecoder for stdout/stderr to handle multi-byte UTF-8 chars split across pipe chunk boundaries - Distinguish ENOENT from non-zero exit in detectLocalCLI so users see auth guidance instead of misleading "CLI not found" when the binary exists but is not authenticated * test(wiki): add subprocess contract tests for local CLI providers Add 21 integration-level tests covering the Claude and Codex subprocess contracts that wiki-flags.test.ts mocks out: - Claude argv: -p, --output-format text, --no-session-persistence, --model conditional, stdin prompt content, CI=1, windowsHide:true - Codex argv: exec subcommand, --sandbox read-only, -c approval_policy, --output-last-message temp path, --cd, stdin marker, --model - Timeout: kill timer fires and rejects, no timer when unset - Codex file fallback: stdout used when file missing, error when both empty - detectLocalCLI: warn on non-ENOENT, silent on ENOENT - onChunk: cumulative byte count forwarded Also register the test in cross-platform-tests.ts SPAWN_CLI section and fix detectLocalCLI ENOENT detection logic (invert the check so non-ENOENT errors produce a warning). * fix(wiki): platform-aware process tree kill and Codex contract snapshot - Add killChildTree helper that uses taskkill /T /F /PID on Windows to terminate the entire process tree (including cmd.exe grandchildren), with fallback to child.kill() if taskkill fails or on non-Windows - Add Codex CLI flag contract snapshot test that locks the exact spawn args — any flag rename, reorder, or removal is caught immediately - Add Windows taskkill tests: success path asserts taskkill called with correct PID and /T /F flags, failure path verifies child.kill() fallback --------- Co-authored-by: eddie.pan2 <eddie.pan2@jtexpress.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Test <test@example.com> |
||
|
|
1bbc876336
|
fix(cpp): dependent-base resolution across nested/inline namespaces (#1634) (#1814)
* fix(cpp): dependent-base resolution across nested/inline namespaces (#1634) Replace exact namespace-prefix match with prefix-contains filter capped at one level deeper, then accept only if exactly one candidate survives. Behavior change: - Derived<T> in ns::outer can now find Inner<T> in ns::outer::inner (nested namespace) or ns::v1 (inline namespace) via prefix walking - Global-scope deriving classes match any single-segment namespace - Sibling namespace collisions (e.g. detail::Inner vs public_api::Inner) correctly suppress when multiple candidates share the same simple name - Deep nesting (ns → ns.a.b) still suppresses (one-level cap) Fixtures added: pos: nested ns, this->f() -> 1 edge to inner::Inner::f neg: no Inner exists -> 0 edges inline: inline namespace variant -> 1 edge sibling-suppress: sibling collision -> 0 edges (ambiguity suppressed) Part of #1564. 64. * test: add deep-nesting suppression fixture, link #1815 in comment, unqualify inline fixture - Update code comment to reference follow-up issue #1815 instead of 'deferred to follow-up' - Inline fixture: drop explicit v1:: qualifier (exercise inline-expansion path more idiomatically as DoD intended) - Add deep-nesting suppression fixture (ns.a.b -> 0 edges) that pins the one-level cap as a documented invariant - Add legacy parity entry for deep-nesting fixture Part of #1564, #1634. --------- Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> |