Commit graph

1107 commits

Author SHA1 Message Date
Gergo Magyar
0f016dc467 fix(config): read core.excludesFile and .git/info/exclude for global ignores (#2606)
Replace the custom ~/.gitnexus/ignore file with the same two sources
real git itself consults for exactly this purpose (gitignore(5)):

- core.excludesFile: git's own all-repos global ignore file (defaults
  to $XDG_CONFIG_HOME/git/ignore when unconfigured)
- $GIT_COMMON_DIR/info/exclude: per-repo, untracked, so it works
  without push/commit access to the repo

Precedence mirrors git exactly (lowest to highest): core.excludesFile,
then info/exclude, then .gitignore, then .gitnexusignore -- each later
source can negate an earlier one via a `!pattern` line, same
last-match-wins semantics git itself uses.

Adds getCoreExcludesFilePath and getGitInfoExcludePath to git.ts,
following the same execSync + git-common-dir pattern as
getCanonicalRepoRoot. GITNEXUS_NO_GLOBAL_IGNORE (or noGlobalIgnore)
still skips both global sources, mirroring GITNEXUS_NO_GITIGNORE.
2026-07-21 18:06:22 +00:00
Gergo Magyar
a4a79ac920 style: fix prettier formatting in ignore-service.test.ts 2026-07-21 17:41:18 +00:00
Gergő Magyar
8a67acb9dd
Merge branch 'main' into fix/2606-global-ignore-file 2026-07-21 18:39:22 +01:00
Gergo Magyar
5893de1194 docs(readme): document the global ignore file (#2606) 2026-07-21 16:58:57 +00:00
Gergo Magyar
322e05a6be fix(config): add user-level global ignore file (#2606)
IgnoreService only read per-repo .gitignore/.gitnexusignore, so an
exclusion meant to apply across every indexed repo had to be repeated
per repo or hand-patched into node_modules (wiped on every upgrade).

loadIgnoreRules now also reads a global ignore file at
$GITNEXUS_HOME/ignore (default ~/.gitnexus/ignore), reusing the
existing global directory that already holds registry.json and
config.json. It is added first, so per-repo .gitignore/.gitnexusignore
rules can still negate it, mirroring the .gitignore -> .gitnexusignore
precedence already in place. GITNEXUS_NO_GLOBAL_IGNORE (or
noGlobalIgnore) skips it, mirroring GITNEXUS_NO_GITIGNORE.
2026-07-21 16:58:07 +00:00
Gergő Magyar
aa8a441202
Merge branch 'main' into fix/2605-rename-edit-count 2026-07-21 17:34:36 +01:00
Gergo Magyar
9f57984372 style: fix quote style per prettier in new dyn-normalization test 2026-07-21 16:12:20 +00:00
Gergo Magyar
e18b4416c6 test(rust): cover Box<dyn Trait> and dyn-bound-list normalization (#2604)
GitNexus review-agent finding: stripDynBound's documented Box<dyn Trait>,
Rc/Arc<dyn Trait>, and auto-trait/lifetime bound-list (dyn Trait + Send)
shapes had no test anywhere — only the bare &dyn Trait parameter case was
exercised end-to-end. Add direct unit coverage on normalizeRustTypeName and
(via interpretRustTypeBinding) normalizeRustReturnType for these shapes.
2026-07-21 16:10:01 +00:00
Gergo Magyar
a7bfe819eb test: update hardcoded schema-version expectations for v11 (#2604)
call-summary-schema-version.test.ts pins INCREMENTAL_SCHEMA_VERSION as a
literal per bump, documenting the reuse-gate boundary for each version.
Update the "current" expectation to 11 and add the v10 pre-current case,
matching the v7/v8/v9/v10 precedent already in the file.
2026-07-21 15:42:58 +00:00
Gergo Magyar
00141d0da2 test(bench): rebaseline rust scope-capture fingerprint for #2604
RUST_SCOPE_QUERY gained a function_signature_item capture, shifting the
capture fingerprint for every bench fixture with a required trait method.
Verified: node --import tsx bench/scope-capture/measure.mjs --check now
passes across all 14 languages (rust scaling 1.036 < 1.5 budget).
2026-07-21 15:32:11 +00:00
Gergo Magyar
66f11badaf style: wrap long filter predicate per prettier (PR autofix) 2026-07-21 15:19:48 +00:00
Gergo Magyar
54c44d91de fix(mcp): reconcile rename report on partial failure; harden enumerate (#2605)
Addresses gitnexus-review-agent findings on PR #2608:

- MED: on a partial apply (a file's write throws), drop that file's edits
  from total_edits/graph_edits/text_search_edits/changes so the reported
  result describes what actually reached disk, not what was attempted. The
  comprehensive enumeration otherwise let a failing file contribute its
  entire line count as phantom 'applied' edits. failed_files still names
  every dropped file. Counts are now derived once from the reported set.
- MED: hoist the word-boundary regexes out of the per-line loop (one compile
  each instead of one per line), reused by the apply loop.
- LOW: apply loop reuses escapedOldName instead of recomputing the escape
  formula inline (removes a preview/apply drift risk).
- Soften the in-code comment: enumeration gives per-call preview/apply
  consistency; the pre-existing two-read TOCTOU (external write between
  preview and apply) is out of scope and noted, not newly introduced.

Tests: add a mixed graph-ref + text_search multi-file case (asserts per-file
confidence and the never-downgrade guard, via a stubbed rg), and a
partial-write-failure case (asserts only landed files are reported). Assert
concrete graph_edits/text_search_edits splits, not just their sum.
2026-07-21 15:14:32 +00:00
Gergő Magyar
aaefbda226
Merge branch 'main' into fix/2604-rust-trait-object-dispatch 2026-07-21 16:12:24 +01:00
Gergo Magyar
67d55d7e59 fix(storage): bump INCREMENTAL_SCHEMA_VERSION for Rust dyn-dispatch fix
RUST_SCOPE_QUERY gained a function_signature_item capture (previous commit)
so abstract trait methods can now dispatch a CALLS edge through a &dyn
Trait receiver. The incremental write set only covers changed files, so a
top-up against a pre-v11 index would keep silently missing these edges for
every unchanged Rust trait file — same contract as v7/v10; force a full
re-analyze instead.
2026-07-21 15:08:06 +00:00
Gergo Magyar
881c6bccc7 test(rust): regenerate captures golden snapshot for function_signature_item
Expected drift from the query.ts change: abstract trait methods now emit a
scope + declaration capture, shifting captureGroups/digest for every rust-*
fixture containing a trait with a required (bodyless) method.
2026-07-21 14:49:45 +00:00
Gergo Magyar
052319c9cc test(rust): add regression coverage for trait-object dispatch (#2604)
New minimal fixture (single trait + impl + &dyn Trait call site, no other
same-named callers) proves the dyn-dispatch CALLS edge discriminates: fails
against the pre-fix source (0 edges) and passes against the two preceding
commits' fix (exactly 1 edge, verified via the CLI analyze pipeline against
a standalone repo).

The existing rust-abstract-dispatch fixture was NOT extended for this,
deliberately: it already has other callers referencing the same method
names (process()'s repo.find()/save()/count()), and an existing resolution
fallback picks those up via simple-name matching regardless of receiver
type — masking this specific defect in the in-process test-pipeline path.
A dedicated, single-caller fixture keeps the regression test load-bearing.
2026-07-21 14:48:54 +00:00
Gergő Magyar
4dd16ea8c9
Merge branch 'main' into fix/2605-rename-edit-count 2026-07-21 15:43:53 +01:00
Gergo Magyar
902186c4f8 style: prettier-format rename-edit-report test (#2605) 2026-07-21 14:41:19 +00:00
Gergo Magyar
4e97a278d1 fix(mcp): report every rename edit that apply writes (#2605)
rename() reported total_edits from a partial enumeration (definition line
only, one-edit-per-graph-file then break, and text search that skipped any
file already covered by the graph) while the apply step does a whole-file
\boldName\b global replace on every touched file. When a private symbol's
definition and all its call sites live in one file, only the definition line
was reported (total_edits: 1) even though apply rewrote every occurrence, in
both dry-run and apply.

Rebuild changes/total_edits/graph_edits/text_search_edits from one file set:
classify each file to rewrite (definition + graph refs = graph confidence;
rg-only files = text_search, never downgrading a graph file), then enumerate
every matching line per file with apply's exact escaped global regex. The
reported edit list now equals what apply writes. Apply behavior is unchanged.

Adds a regression test reproducing the issue's single-file Rust case (def +
3 same-file call sites, empty graph): total_edits is 4 in both dry-run and
apply, and equals the replacements that land on disk.
2026-07-21 14:31:47 +00:00
Gergo Magyar
57db7bc166 fix(rust): capture abstract trait methods for scope resolution
fn foo(&self) -> T; (no body) parses as function_signature_item, a grammar
node distinct from function_item that RUST_SCOPE_QUERY never captured. An
abstract trait method therefore had no Function scope and no declaration,
so populateClassOwnedMembers never wired its ownerId to the trait's Class
scope — invisible to the CALLS-edge receiver-bound resolution pass even
after a receiver's type resolves to the trait correctly.

Together with the previous commit's dyn-stripping fix, a call through a
&dyn Trait parameter now emits a CALLS edge to the trait's method (#2604).
2026-07-21 14:29:37 +00:00
Gergo Magyar
3375beec89 fix(rust): strip dyn keyword when normalizing trait-object type names
normalizeRustTypeName/normalizeRustReturnType stripped reference sigils,
pointer sigils, and smart-pointer wrappers but never the `dyn` keyword, so a
`&dyn Trait`-typed receiver normalized to the literal string "dyn Trait"
instead of "Trait" — an unmatchable name that silently broke every
downstream receiver-type lookup for trait-object dispatch.

Part of the #2604 fix (root cause has a second, independent half: abstract
trait methods are invisible to scope resolution until function_signature_item
is captured — next commit).
2026-07-21 14:29:05 +00:00
Claude
70e0a7766c fix(java): address #2561 review — inherited-dispatch test + bodied fail-safe
Two gitnexus-review-agent findings on PR #2602:

- MEDIUM: the bodied-constant MRO-to-host-enum path (a qualified call to an
  inherited, non-overridden enum method) was claimed in a comment but never
  tested. Add EnumConst.A.log() -> EnumConst.log#0, exercising E$N's
  @reference.inherits MRO arm end to end.

- LOW: `bodiedName ?? hostEnum` conflated "body-less" with "name synthesis
  failed on a bodied constant" (reachable only on malformed/error-recovery
  trees), silently binding an overriding constant's receiver to the host
  enum — a wrong edge instead of no edge. Switch to `isBodied ? bodiedName :
  hostEnum` so a bodied constant binds ONLY to its E$N class, mirroring the
  object_creation_expression branch's skip-on-synthesis-failure. Verified
  output-neutral on the well-formed bench corpus.

Rebaseline the java scope-capture fingerprint (a822cef9 -> d04298a9): the
bench corpus IS test/fixtures/lang-resolution, so the new dispatchInherited
fixture method shifts it (+6 capture groups); the logic change contributes
nothing (confirmed by isolating the fixture-only fingerprint). java.test.ts
242 passed; measure.mjs --check PASS (14 languages); tsc/prettier/eslint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 13:52:27 +00:00
Gergő Magyar
ced02df06f
Merge branch 'main' into fix/2561-enum-constant-receiver-dispatch 2026-07-21 14:40:37 +01:00
Ko
2a85425ad8
Merge pull request #2542 from GenKoKo/fix/worker-stdout-and-ready-timeout
fix(ingestion): pipe worker stdout and make ready timeout configurable
2026-07-21 13:54:34 +01:00
Claude
d9437e6d74 test(bench): rebaseline java scope-capture fingerprint for #2561
The enum-constant receiver-dispatch fix adds one @type-binding.* capture
per enum constant, so the java scope-capture fingerprint shifts
(85fc7af9 -> a822cef9). Pure capture-additive drift; no bench fixtures
added; scaling 1.024 < 1.5 budget. Verified `measure.mjs --check` passes
for all 14 languages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 12:19:51 +00:00
Gergő Magyar
c111dfd4ae
Merge branch 'main' into fix/2561-enum-constant-receiver-dispatch 2026-07-21 12:50:37 +01:00
Claude
7666a009f0 fix(java): resolve E.CONST.method() enum-constant receiver dispatch (#2561)
Calling a method on an enum-constant receiver (E.CONST.method()) emitted
no CALLS edge. The receiver "E.CONST" is a two-segment compound receiver;
resolveCompoundReceiverClass walks each dotted segment via the owning
class scope's typeBindings map, but enum constants had no typeBinding, so
the constant segment dead-ended and no target was ever resolved.

#2555/#2558 gave bodied constants a first-class synthesized E$N class with
an MRO that includes the host enum; this is the receiver-side follow-up.
synthesizeJavaAnonymousClassDeclarations now emits a class-scope
typeBinding for every enum constant's simple name -> its E$N class (bodied)
or the host enum itself (body-less), reusing the exact mechanism a field
declaration uses. The generic compound-receiver chain walk then resolves
E.CONST.method() with no change to any shared scope-resolution code.

Bodied dispatch (EnumConst.A.hook() -> EnumConst$1.hook#0) and body-less
inherited dispatch (Plain.A.m() -> Plain.m#0) are covered by new tests in
the existing java-enum-constant-body fixture; both were verified to fail
against the pre-fix tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 11:24:35 +00:00
Claude
1415bd5c2f docs(embeddings): update engines-floor comments for the 22.18 minimum
The module.registerHooks compat seam and the onnxruntime resolvers cited
the old '>=22.0.0' floor as the reason their sub-22.15 fallback was
reachable. With the floor now ^22.18.0 || >=24.11.0 (all >=22.15), every
supported runtime exposes the API; the fallback stays as defensive
handling for below-floor runtimes (engines is advisory, not
engine-strict). Comments only - no behavior change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:09:34 +00:00
Claude
eea9ac92dc ci: move Node pins to the 22.18 floor
With the supported minimum raised to Node 22.18, retarget every lane and
pinned runtime that sat at a lower version so nothing builds or runs the
package on an unsupported (EBADENGINE-warning) Node:

- ci-tests.yml: node-floor-compat 22.14 -> 22.18.0 (name, comment, pin,
  version assertion) so the floor gate guards the new minimum; its #2372
  registerHooks failure mode cannot recur above 22.15. Containment-canary
  pin 22.16.0 -> 22.18.0.
- gitnexus-review-agent.yml + the pinned review/canary runtime: the
  reproducible runtime is version-locked in lockstep across
  .github/{gitnexus-review-runtime,claude-canary-runtime}/package.json and
  their lockfiles (engines), the workflow's node-version, its two
  'node --version = v22.18.0' assertions, the lockfile-engines guard, and
  NODE_VERSION. Moved all of them 22.16.0 -> 22.18.0.
- gitnexus-skill-evolution.yml: pinned runtime 22.16.0 -> 22.18.0.
- CONTRIBUTING.md prerequisite floor updated.
- review-agent-workflow.test.ts, which enforces the runtime lock, updated
  to expect 22.18.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:09:34 +00:00
Claude
c26b78d153 fix(deps)!: require Node >=22.18 and drop @types/uuid stub
Babel 8 (devDep for the bench mutation oracle, pulled in by dependabot
previous floor (>=22.0.0), so every dev install on Node <22.18 emitted
nine EBADENGINE warnings. Rather than pin Babel back to 7, adopt Node
22.18+ as the supported minimum: set engines to ^22.18.0 || >=24.11.0,
matching Babel 8 exactly so the warnings resolve honestly with no
dependabot ignore needed.

@types/uuid@11 is a deprecated stub - uuid@14 ships its own types and no
tsconfig references it. Lockfile edited by hand (engines + @types/uuid
entry) to preserve the libc platform metadata a newer npm wrote;
verified consistent via npm ci (exit 0).

BREAKING CHANGE: the gitnexus package now requires Node ^22.18.0 || >=24.11.0
(previously >=22.0.0). Node 22.0-22.17 are no longer supported.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 10:09:30 +00:00
Gergő Magyar
a2cce72fa0
Merge branch 'main' into dependabot/npm_and_yarn/gitnexus/ladybugdb/core-0.18.2 2026-07-21 10:18:38 +01:00
Gergő Magyar
c7701613ec
Merge branch 'main' into dependabot/npm_and_yarn/gitnexus/ladybugdb/core-0.18.2 2026-07-21 09:52:37 +01:00
Gergő Magyar
450f641b36
Merge branch 'main' into codex/spring-config-bindings-2412 2026-07-21 09:51:42 +01:00
Gergő Magyar
522d1ee62a
Merge branch 'main' into fix/2564-record-newexpr-callgraph 2026-07-21 09:29:45 +01:00
Gergo Magyar
dac2b770a0 fix(test): address gitnexus-review-agent findings on PR #2598
- Anchor isBenignDropFtsIndexError to the START of the message
  (startsWith, not includes) so a future genuine failure that merely
  mentions "Binder exception" or "Catalog exception" mid-message can't
  be misclassified as benign. New test proves the old substring match
  would have swallowed such a message.
- incremental-fts-drop-ordering.test.ts: probe FTS availability once in
  beforeAll and skip VISIBLY via ctx.skip() in beforeEach (matching the
  withTestLbugDB/lbug-vector-extension convention) instead of a silent
  console.warn+return inside the test body, which reported a false pass
  with zero coverage of the ordering invariant when FTS was unavailable.
  The post-first-run FTS-index-built check is now a hard assertion
  instead of a second soft skip, since the beforeEach gate already
  proved the extension loads.
2026-07-21 07:57:28 +00:00
Gergő Magyar
10545a52f0
Merge branch 'main' into dependabot/npm_and_yarn/gitnexus/ladybugdb/core-0.18.2 2026-07-21 08:40:14 +01:00
Gergo Magyar
993abbb7ea Merge branch 'main' auto-update (GitHub PR sync) into repro/issue-2589 2026-07-21 07:25:53 +00:00
Gergo Magyar
f460157470 style(test): fix prettier formatting in incremental-fts-drop-ordering.test.ts
CI's prettier --check flagged one over-long line; no behavior change.
2026-07-21 07:25:15 +00:00
Gergo Magyar
5099e8ff1e test(bench): rebaseline java scope-capture fingerprint for record support (#2564)
CI caught this: adding the record_declaration capture legitimately
changes the pinned java capture fingerprint, same as every prior
capture-behavior change to this language (#2550, #2555). Rebaselined
following the established _rebaselined_* precedent; scaling ratio
1.059 stays well within the 1.5 budget.
2026-07-21 07:18:38 +00:00
Gergő Magyar
bbd1c4cd47
Merge branch 'main' into repro/issue-2589 2026-07-21 08:12:59 +01:00
Gergő Magyar
6c4c93533b
Merge branch 'main' into codex/spring-config-bindings-2412 2026-07-21 08:07:42 +01:00
Gergő Magyar
1864309872
Merge branch 'main' into fix/2564-record-newexpr-callgraph 2026-07-21 08:06:15 +01:00
dependabot[bot]
b028cc0212
chore(deps)(deps): bump body-parser from 2.2.2 to 2.3.0 in /gitnexus (#2594)
Bumps [body-parser](https://github.com/expressjs/body-parser) from 2.2.2 to 2.3.0.
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/v2.2.2...v2.3.0)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-version: 2.3.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 08:05:49 +01:00
dependabot[bot]
cdd0ce9b8e
chore(deps)(deps): bump brace-expansion from 5.0.6 to 5.0.7 in /gitnexus (#2593)
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 5.0.6 to 5.0.7.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v5.0.6...v5.0.7)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 5.0.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 08:05:33 +01:00
Gergo Magyar
d7a4f47580 fix(analyze): drop FTS indexes before the incremental DETACH DELETE
Fixes #2589: incremental analyze intermittently crashed with "FTS
index 'file_fts' is inconsistent: term is missing during delete" after
markdown-only commits, and --repair-fts also failed in that state.

deleteNodesForFiles' batched DETACH DELETE ran against tables that
still carried the FTS index built at the end of the PREVIOUS analyze
run -- createSearchFTSIndexes only drops+rebuilds every index in Phase
3, well after that delete already ran. LadybugDB's FTS extension is
not proven to survive DML against an indexed table (its own docs never
demonstrate the sequence). Call the new dropSearchFTSIndexes() up front
in the non-escalated incremental branch, before deleteNodesForFiles --
Phase 3 still rebuilds every index from the final row set regardless.

New end-to-end test drives a real runFullAnalysis full+incremental
cycle and confirms it fails without this change (file_fts and 50
sibling indexes still present at delete time) and passes with it.
2026-07-21 07:04:50 +00:00
Gergo Magyar
c548652eca fix(lbug): stop dropFTSIndex from swallowing genuine engine failures
dropFTSIndex previously caught and discarded every DROP_FTS_INDEX error
unconditionally. Extract isBenignDropFtsIndexError, a pure classifier
for the two legitimate "nothing to drop" cases (Binder/Catalog
exceptions: index never created, or the FTS function isn't registered)
verified end-to-end against @ladybugdb/core 0.18.x's real conn.query()
error text. Anything else -- e.g. the Runtime exception "FTS index is
inconsistent" class from #2589 -- now rethrows instead of being masked,
so a corrupted index can no longer persist across analyze runs
undetected.
2026-07-21 07:04:50 +00:00
Gergo Magyar
1fd1f14cee refactor(search): extract dropSearchFTSIndexes from createSearchFTSIndexes
Pulls the existing per-index dropFTSIndex loop out into its own exported
function so the incremental writeback can drop FTS indexes up front,
before deleteNodesForFiles runs (#2589). No behavior change here —
createSearchFTSIndexes calls the new function and still rebuilds every
index afterward.
2026-07-21 07:04:49 +00:00
Gergo Magyar
1595a90a13 fix(storage): bump INCREMENTAL_SCHEMA_VERSION for the Java record fix (#2564)
Review finding: the record_declaration container-node fix (894110bf)
makes previously-uncaptured Record nodes and HAS_METHOD edges appear
for the first time, but the incremental write set only covers changed
files. Without this bump, an existing index would silently keep
omitting the Record node and its HAS_METHOD edges for unchanged
record files after an ordinary incremental analyze.

Same contract as v7 (#2437/#2522) and the two closest precedents, v8
(#2550) and v9 (#2555), which bumped this constant for the identical
"model X as first-class node" class of change.
2026-07-21 07:04:08 +00:00
Gergo Magyar
0b933aa43f fix(java): treat a new-expression as a typed receiver for its chained call (#2564)
new Local().inner() bound the whole object_creation_expression as
@reference.receiver, so its raw source text ("new Local()") became the
receiver name. That text can never match a scope binding, so the call
silently fell through to name-only fallback resolution and could
resolve to an unrelated same-named method on a collision.

Normalize the receiver to the constructed type's simple name (reusing
javaBaseSimpleNameOf, already used for the anonymous-class inheritance
edge) so Case 2 (class-name / static receiver) in
receiver-bound-calls.ts resolves it via its normal MRO walk. Mirrors
the existing normalizePhpReceiver precedent in php/captures.ts - a
language-local capture rewrite, no shared-pipeline change.
2026-07-21 07:04:07 +00:00
Gergo Magyar
1e190e6fdd fix(java): emit a graph node for record_declaration (#2564)
JAVA_QUERIES had no @definition.record capture, unlike its
class_declaration/interface_declaration/enum_declaration siblings and
unlike CSHARP_QUERIES' own record_declaration pattern. A Java record's
container node was never created, so its HAS_METHOD edges were dropped
at persistence even though ownership resolution computed a valid
ownerId for its methods.

Downstream label mapping, the class-extractor config, the dispatch
table, and ownership reconciliation already treated 'Record' correctly
- this was purely a missing structure-phase capture.
2026-07-21 07:04:07 +00:00