* chore: release v1.6.10
* fix(eval): derive the pinned runtime version from package.json
The containment suite mounts a GitNexus runtime built from this checkout and
asserts its version equals PINNED_GITNEXUS_VERSION, a constant hardcoded to
"1.6.9" when the harness landed in #2566. The first release after that lands
1.6.10 in gitnexus/package.json, the built runtime reports 1.6.10, and
`eval / containment (ubuntu)` fails on drift the release itself created.
Read the version from gitnexus/package.json instead. The check keeps its real
job -- proving the mounted runtime came from this checkout rather than a
published package -- without a copy that only ever drifts on release day.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(group): resolve Java constant-based route paths via repo constant map
- prepareRepo builds repo-wide Java constant map (constant-definition files only,
cheap regex gate; per-file try/catch so one bad file degrades not forfeits)
- bind parser language in prepareRepo (orchestrator hands over a bare Parser)
- scan() lazily overlays the importing file's own import table (extracted from
the tree already in hand, zero extra parses) before folding operands
- foldJavaOperands resolves qualified refs (Class.CONST) + static imports +
string concatenation against the merged view; unresolved refs are skipped,
never guessed
Real-repo validation (winning-winex-opt, 23k Java files):
providers 2 -> 1701 (1700 source_scan_resolved), cross-links 0 -> 589 exact
Unit: 14/14 (java-route-const-resolver.test.ts)
* fix(review): address bot review findings on PR #2980
- P2-1 (real): spring.ts route loop dropped every @value_expr match — the
'!valueNode' guard ran before the operand branch, so ingestion emitted zero
constant-referencing routes. Guard now accepts @value_expr when @value is
absent; two downstream valueNode dereferences made conditional.
Added 2 extractor-level regression tests (16 total).
- P2-2 (real): collectSpringTypes copied rawPath:'' for constant routes into
the shared Spring inheritance view — now skipped there (fold happens in
scan(); empty-path noise would leak into inheritance-based providers).
- P1-1 (false positive): Java 'static final' allows exactly one initializer
(duplicate declarations are compile errors), so the Python-style rebinding
shadowing cleanup does not apply — documented at the site.
- P1-2 (false positive): constant-resolver.ts and prepareDurableParsedFileChunk
both exist on upstream main (#2391 / parsedfile-store.ts:562); the bot's
'repository lookup' appears to have compared against a stale index.
- P3: removed dead FQN_CONTROLLER fixture.
Real-repo regression: 589 cross-links / 2423 contracts (was 2424 — the
dropped contract is the empty-path inheritance artifact fixed above).
* docs(cache): note Java constant-route capture set in the SCHEMA_BUMP ledger
The Java constant-route harvest (route-extractors/java-const-resolver.ts +
the spring.ts operand branch + the parse-worker Java constant harvest)
changes the worker capture set: a warm pre-feature cache replays
moduleConstants=0 captures verbatim and silently drops every constant-based
Spring route on unchanged files. After rebasing onto current main the
ledger already sits at 70, whose capture set post-dates and includes this
harvest, so v70 invalidates those caches — no additional bump is needed.
* fix(feign): guard @RequestLine against the constant-valued shape
A constant-valued `@RequestLine(SOME_CONST)` is captured as @value_expr,
not @value, so `valueNode` is undefined in that shape and the literal
dereference crashed the scan. Skip instead — folding verb+path literals
through the constant map is out of scope for this PR.
Found in maintainer review of #2980.
* fix(resolver): bound qualified-ref recursion depth for self/mutual import cycles
Maintainer review point: the qualified branch of resolveJavaConstant
recurses through resolveJavaImport without a guard — a self-import
(X = SelfConsts.X + ...) or a pair of mutually-importing constants
would recurse without bound before reaching the shared fold's
visited-stack, which only guards the bare-name path.
Bound the Java-qualified walk with a depth cap (32) and thread it
through every recursive call. Two regression tests use real repo
shapes (repoOf fixtures): self-import and mutual-import cycles both
terminate with null (skip floor), as before, but promptly.
Also drops the stray machine-local .gitignore entry that rode along
from the fork's dev branch.
* fix(routes): address round-2 review — provider hooks, FQN fold, interface nesting
F1 (High): production harvest silently dropped routes when the constants
class is not named *Constants (e.g. ApiPaths). The content gate is now
SYNTAX-driven (static-final String field or any class import) and lives in
the provider (moduleConstantHeuristic), not a shared-layer regex.
F2: shared ingestion layers no longer branch on language. The harvest and
the qualified-ref fold run through new provider hooks
(extractModuleConstants / foldRoutePathOperands); parse-impl resolves the
provider by filePath (getProviderForFile). Python wires the same hooks for
architecture parity.
F3: multi-segment FQN chains (com.example.ApiPaths.USERS) now flatten
recursively; verified via tree-sitter that the existing query already
captures the whole nested field_access — the gap was resolver-side only.
F4: implicit-final interface semantics no longer leak into nested classes
at type boundaries (JLS 9.5).
F5: nested same-name shadowing now drops the stale entry (rebind-drop,
matching Python #2391 semantics) instead of keeping the first binding.
Tests: 9 new unit tests (27/27) + real-pipeline e2e over a reviewer-shaped
fixture (non-*Constants class, cold run + warm parse-cache replay) — the
exact production gap unit tests missed.
* style: prettier --write on the two touched test files (CI format gate)
* fix(routes): address the open review findings on Java constant route folding
Answers every reproduced finding still open on #2980, plus the defects an
adversarial pass found in the first round of those fixes. The wrong-path group
each turned a *missing* fact into a *wrong* one, which is what this module's
skip-or-correct contract exists to prevent.
Wrong-path fixes
* Escapes were deleted from constant values. tree-sitter-java splits a
`string_literal` around its `escape_sequence` children, so joining
`string_fragment`s alone folded `"/user/{id:\\d+}"` — the standard Spring
path-variable constraint — to `/user/{id:d+}`, and a pure-escape literal to
the empty string. Worse, the LITERAL path keeps escapes verbatim, so one Java
route had two irreconcilable spellings. `stringLiteralValue` now reuses
`unquoteSpringLiteral`, the helper that literal path already uses. Java text
blocks are excluded: that helper's `"""` arm would hand back the raw block,
newline and incidental indentation included, so they keep the old skip.
* A constant-valued class prefix produced a truncated route. The new
`@value_expr` query branches were `method_declaration`-only, so
`@RequestMapping(ApiPaths.BASE)` left the prefix empty and the method route
was emitted unprefixed — a path the application does not serve, where the base
emitted nothing at all. Both subsystems now detect such a class and suppress
its method routes, the rule `classesWithArrayPrefix` already encodes for the
array form. The suppression covers ingestion's separate no-argument-mapping
loop too, without which a bare `@GetMapping` under a constant prefix still
shipped an empty-path Route while the group emitted nothing.
* A shadowed static import survived a non-foldable rebind. The rebind-drop
deleted `literals`/`exprs` but not `imports`, so a name both static-imported
and locally redeclared resolved through the stale import to the imported
value instead of skipping (#2393's Python defect, reproduced for Java).
* `resolveJavaImport` guessed where its own docstring promised null. The
nearest-shared-directory tie-break is gone: javac resolves duplicate FQNs by
classpath order, so proximity can return a src/test fixture copy.
Parity and coverage fixes
* One constant-file gate, exported as `isJavaConstantFile` and used by both the
ingestion provider and the group `prepareRepo` pre-pass. The two spellings
disagreed on a constant INTERFACE — implicitly `public static final`, so it
carries neither keyword — which the group admitted and ingestion rejected, so
the group published a contract while the graph got no Route node. It is also
modifier-order agnostic now, and its interface arm requires a String
assignment so a javadoc mentioning "interface" no longer costs a parse.
* Import ambiguity is measured over constant-DEFINING files on both sides.
Ingestion's harvest gate also admits import-only files, so handing
`resolveJavaImport` every repo key let a duplicate FQN that defines nothing
make ingestion alone floor to skip — reopening the same parity break in the
same losing direction.
* Python's constant harvest is unconditional again. The gate added here
required NAME immediately followed by `=`, so it dropped `API: str = "/api"`,
`API: Final[str] = "/api"` and every composed constant whose RHS starts with
an identifier — routes that already resolve on main. The worker now treats a
missing heuristic as "harvest" rather than "skip".
* Enum and record declarations were traversed but never collected, so a
`static final String` declared in one was absent from the map. The walk still
descends the whole body, so a type nested in an enum-constant body is kept.
* Constants composed across files through a qualified ref never resolved:
operands found inside an initializer went to the agnostic core, which only
knows bare names, so `X = BConsts.Y + "/tail"` floored to null even
acyclically. The Java binding now folds its own expressions — and carries the
core's guards with them: a `visited` stack popped on unwind, a memo of
successes, and `MAX_FOLD_LENGTH`. Without the memo a shared-descendant DAG
re-folds each child per reference; because a chain of empty strings never
accumulates output, the length cap could not stop it, and one route over a
31-line constants file took 11 s at 28 levels on the main thread.
* Dropped the dead `com.java.lang.` type normalization.
Cache
* `SCHEMA_BUMP` 70 -> 72. Leaving it at 70 was justified by "the ledger already
sits at 70, whose capture set post-dates and includes this harvest" — it does
not: 70 was cut by fe3d7e56b for #2417/#2891, an ancestor of this base. With
package.json untouched, `PARSE_CACHE_VERSION` was byte-identical across the
merge, so every same-version warm cache replayed pre-feature captures and the
feature was inert. 72 rather than 71 because open PR #3017 already claims 71
with an identical pin test — the ledger's rule is the next value above every
in-flight claim, not above origin/main.
Tests
* Regression cover for each fix above, including a gate-level test (the gate
itself had none), an import-ambiguity test, a text-block test, and a 30-level
shared-descendant DAG that fails by timeout if the memo is ever removed.
* New `group/java-const-route-parity.test.ts` drives `prepareRepo` + a
three-argument `scan`. Every existing Spring parity guard calls `scan(tree)`
with ONE argument, and the plugin drops constant-valued routes without a repo
context — so those guards were structurally blind to this whole feature.
* The pipeline e2e now proves the warm run is a REPLAY (`usedWorkerPool` false)
instead of only comparing route sets. It was not one: the test never persisted
the durable ParsedFile store, so the "warm" run reparsed through the workers
and would have passed with the cache round-trip completely broken.
* Its dist freshness gate covers every source the pipeline loads, not just
parse-worker.ts, and prints the loud message the docblock promised.
* The self-import cycle fixture now actually self-imports, so it reaches the
qualified-ref recursion and its depth cap.
* Removed the dead `WIN_POST_MAPPING` fixture and the claim behind it: Spring
alias recognition is an exact-name map on this base, so `@WinPostMapping`
extracts zero routes no matter how its value folds (#2883 is still open).
Fixtures now use annotations this branch actually recognises.
* fix(routes): widen the Java constant-file gate to match its extractor
Answers the gitnexus-check round on 43a0ff290.
The gate was still narrower than the extractor it feeds, in two ways the
extractor explicitly supports:
* `static final String` was matched as an ADJACENT pair, but the extractor
scans modifiers independently (`isStaticFinal`), so `static public final
String PATH = "/x";` — legal Java — was extracted when parsed and never
parsed, because the gate returned false.
* the type had to be the bare token `String`, but the extractor also accepts
`java.lang.String`, so `public static final java.lang.String PATH = "/x";`
was skipped the same way.
Both are the same defect class as the ingestion/group divergence this predicate
was introduced to prevent, one layer down: a cost gate that is narrower than
the thing it gates silently drops facts. The modifier run is now matched as a
span excluding `;{}()`, so every legal order and the qualified type name are
admitted while precision holds — a local `String s = "x"` inside
`static void f() { … }` still does not match, because reaching it from `static`
crosses `(`, `)` and `{`. `final` is deliberately not required: the gate may be
wider than the extractor, never narrower.
Also: the worker's harvest condition moves into `shouldHarvestModuleConstants`
in `language-provider.ts`. The rule that is easy to get backwards — a provider
declaring no `moduleConstantHeuristic` harvests unconditionally — was only
reachable by booting a worker, so the Python tests could assert the extractor
harvests and the provider declares no heuristic while a regression to
`provider.moduleConstantHeuristic?.(content)` still turned the hook off. The
tests now drive the predicate itself, plus the two branches around it.
One finding in that round is not reproducible: the parity helper is not made
unresolvable by its import-only fixture. Every `resolveJavaImport` call site
passes the fold state's `constantKeys` — files with `literals`/`exprs` — not
`repo.keys()`, so a same-FQN class defining nothing creates no ambiguity. That
filtering is what the helper exists to exercise, and the test is green.
---------
Co-authored-by: ChunxueLi <mecoloud@users.noreply.gitee.com>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Remediates GHSA-xcpc-8h2w-3j85 (DoS via crafted ZIP file 4GB memory allocation in onnxruntime-node).
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
LadybugDB ≤0.18.2 mis-evaluated `r.type IN [...]` on relationship table
groups: the boolean-filter fallback skipped writing selection buffers for
single-row unflat chunks, dropping/duplicating callers in context() and
impact() (upstream LadybugDB#692, fixed by LadybugDB#699, shipped in
0.18.3). Floor the dependency at ^0.18.3 and lock core + all five platform
packages.
Resurrect the caller-identity regression test from PR #2553 (closed as
superseded by the upstream fix): it pins context()/impact() to exact
caller IDs across CodeRelation sub-table pairs so any future predicate
regression fails loudly. Note: with CREATE-seeded data the test also
passes on 0.18.2 (the upstream repro needs COPY-written chunk layouts) —
it is a behavioural pin, not a bug reproduction.
Fixes#2508
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* chore(deps)(deps): bump js-yaml from 4.3.0 to 5.0.0 in /gitnexus
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.3.0 to 5.0.0.
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.3.0...5.0.0)
---
updated-dependencies:
- dependency-name: js-yaml
dependency-version: 5.0.0
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
* fix(spring-config): migrate YAML parsing to js-yaml 5 event API
js-yaml 5 removed the loadAll `listener` callback, the EventType/State
types, and DEFAULT_SCHEMA that spring-config relied on, breaking the build.
Rebuild the per-key line tree from parseEvents()/constructFromEvents()
(positions are source offsets → mapped to lines), apply the `<<` merge tag
via CORE_SCHEMA.withTags(mergeTag) (CORE alone leaves merge keys unexpanded),
and resolve aliases by anchor name, which lets the object-identity WeakMap go.
Behavior preserved: 9 unit + 8 integration spring-config tests pass, including
merged-key declaration-line, cyclic-alias termination, and the depth budget.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(spring-config): restore v4 tag coverage, cover the v5 rewrite with tests
Review follow-up for #2618.
CORE_SCHEMA.withTags(mergeTag) was a narrowing, not a port: js-yaml 5
throws "unknown tag" on !!timestamp/!!binary/!!set/!!omap/!!pairs, and an
unknown tag aborts the whole parse, which readConfigKeys swallows — so an
application.yml using any of them would have gone from its full key set to
zero keys, silently. Carry the rest of what DEFAULT_SCHEMA was; none of
these tags can execute code.
Add tests for every path the review flagged as uncovered: multi-document
files, empty/comment-only/bare-`---`/bare-scalar documents, sequence-form
merge keys, and explicitly tagged values (which fail against the one-tag
schema, so they target the changed line).
Clear the anchor map per document. It cannot change output today —
constructFromEvents rejects a cross-document alias before the event tree is
built, now asserted — but it keeps both layers on YAML's scoping rule.
Drop the stale @types/js-yaml devDependency; js-yaml 5 ships its own types
and tsc --noEmit is clean without it. Lockfile hand-edited because npm
uninstall also strips every libc field.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(autofix): apply prettier + eslint fixes via /autofix command
* fix(spring-config): flatten !!set members, walk YAML iteratively
Review follow-up for #2618.
js-yaml 5 constructs `!!set` as a native Set; v4 built a plain
`{member: null}` object. Object.entries of a Set is empty, so a tagged set
collapsed to a bare leaf key and lost every member. Enumerate the Set
instead. Sets arrive as mapping events with key/value scalar pairs, so
member lines resolve through the usual lookup. !!binary and !!timestamp are
unaffected — both are scalar events and take the leaf path, which is why a
Uint8Array never explodes into one key per byte.
Convert findYamlMappingLocation and flattenYamlValue from recursion to an
explicit stack. Children are pushed in reverse so pops happen in
declaration order, preserving "first match" and `out` insertion order;
`leave` frames release the cycle guard where the old `finally` did. The
depth budget still throws at the same boundary with the same message.
Cover the gaps the review named: !!pairs (both duplicate entries survive),
anchor-name reuse resolving to the nearest preceding declaration, and
marker-only leading documents staying index-aligned across the two streams.
buildYamlEventTree keeps no node budget by design — one node per event over
an already-materialized array, bounded by MAX_CONFIG_FILE_BYTES. The
docstring now says so rather than implying MAX_YAML_TRAVERSAL_NODES covers
it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.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>
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>