* fix(deps): make tree-sitter peer installs clean
Keep the eight audited lockfile peer ranges consistent with the bundled tree-sitter 0.25.1 runtime and apply the existing manifest preparation during postinstall. Ordinary and strict npm installs resolve without peer warnings.
* docs: explain audited tree-sitter peer maintenance
* fix(deps): pin audited tree-sitter peers to 0.25.1
* fix(deps): normalize audited peers to the exact runtime
* docs: clarify exact tree-sitter runtime peer pins
* test(deps): cover exact peer pins and existing-install migration
Verify exact 0.25.1 peers, repeatable preparation, and migration from the previously widened peer metadata.
* fix(deps): support pnpm symlinks in bundle preparation (#3555)
Follow package symlinks and pnpm sibling dependency containers. Deduplicate real paths to avoid revisiting aliases or cycles while preserving the audited manifest and duplicate-instance checks.
Validated with strict npm ci, both typechecks, npm pack, a real pnpm layout, and a pnpm-installed tarball parsing all 19 grammars on main and worker threads.
* test(deps): cover pnpm layout and symlink cycles (#3555)
Exercise real package symlinks, transitive sibling dependencies, a self-cycle, metadata drift before writes, and rejection of distinct duplicate grammar instances.
The original script fails the pnpm regressions; the updated script passes all 10 bundle tests.
* chore(autofix): apply prettier + eslint fixes via /autofix command
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(deps): upgrade native tree-sitter to 0.25.1
* fix(tree-sitter): preserve sync loading and update verified capture baselines
Route C# scope queries through the synchronous native grammar loader so the compiled analyze module remains require-compatible on Node 22.18. Refresh only the audited empty-Python-module and renamed-PHP-fixture captures, and pin the runtime assertion to 0.25.1.
Validated 479 targeted tests, all 16 scope-capture benchmark cases, Python capture/import guards, compiled C# worker parsing, build, typecheck and formatting. Performance budgets are unchanged.
* fix(tree-sitter): refresh upstream vendors and preserve parser semantics
* fix(ci): refresh prebuilds and support Windows ARM
Refresh macOS, Linux ARM, and Windows x64 grammar binaries from the successful native CI builds. Pin node-gyp 12.4.0 so the Windows ARM jobs recognize Visual Studio 2026.
Use local Git filtering for E2E to avoid PR-files API timeouts on generated parser diffs.
Validation: 143 focused tests, Actionlint, and all 16 scope-capture benchmark checks passed. Full npm test run started; native database suites still running.
* fix(ci): refresh Windows ARM grammar prebuilds
Import all seven Windows ARM grammar artifacts from successful native build run 37965761760. Artifact filenames and SHA-256 hashes verified; all 42 native build jobs passed.
Validation: 31 prebuild coverage tests passed.
* fix(bench): stabilize scope capture timing guard
Warm each input size seven times and use 21 median samples while retaining isolated timing blocks. Yield between languages so native finalizers release allocations outside the measured sections. Keep all fixture sizes, fingerprints, scaling formulas, and budgets unchanged.
Validation: all 16 language guards passed with a 2 GB heap limit (1.38 deep-chain ratio; 1518 MB peak RSS). Linear and quadratic controls passed their expected guard outcomes. Formatting and graph change analysis passed. Full npm test is running without failures so far.
* fix(parser): reduce TypeScript capture traversal cost
* fix(test): await parser worker readiness before teardown
* fix(parser): load C# synchronously in workers
* fix(grpc): resolve native proto detections against their own file
With the native proto grammar active, sibling .proto files that declare
the same short service name under different packages tied in the
directory-based resolveProtoConflict heuristic and both providers were
dropped. A proto-origin detection already knows its defining file, so
use that file's entry before falling back to the heuristic.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* ci(packaging): assert native grammars load from the installed tarball
The packaged-install smoke only ran `gitnexus --version`, so a grammar
that failed to load from the published package (bundled runtime, patched
peer manifests, vendored prebuilds, C# sync loader, Protobuf wrapper)
would ship silently; the dev-tree ABI smoke also accepts vendored
grammars that report unavailable. Parse a sample for every registered
grammar plus the native Protobuf plugin from the installed package, on
the main thread and in a worker thread.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* ci(tree-sitter): track compatibility workarounds instead of 0.25 readiness
The daily readiness report still targeted tree-sitter@0.25.0, so after the
upgrade it would keep reporting "Blocked" and never close its tracking issue.
Repurpose it to track what we carry for the bundled runtime: derive the target
from the package.json pin, list each pack-time peer patch from
prepare-tree-sitter-bundle.cjs with its drop condition (bump, wait for an
upstream release, transitive, or intentionally pinned), and reword the
buckets. The workflow adopts the issue opened under the old title.
Also update the grammar-update-monitor header and auto-PR text, which still
described the 0.21.1 runtime and a tree-sitter-c hold.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(dart): assert both nested labels target the loop; fix Zig call-shape doc
The nested-label CFG test only jumped to `outer` and checked reachability,
which still passes when a jump is retargeted to the inner loop (its exit
reaches the outer header). Jump to both labels and assert the exact
`continue` edges; dropping the inner label now fails the test.
Update the Zig callable-flow comment: call_expression now wraps actuals in a
required `arguments:` field.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(release): add fixed-answer native tool accuracy
* fix(release): gate stable artifacts on pinned paired evaluations
Apply review findings #1-4: gate Docker publication, grade in-flight retries, preserve repository context, and execute negative controls in CI.
* fix(eval): verify native context and resolve harness security findings
Inspect Claude's first startup reminder for ordinary repository guidance.
Bound launcher-option matching and escape Markdown backslashes and pipes.
Exclude only the parsed synthetic accuracy corpus from CodeQL; keep the
benchmark harness and evaluator under security analysis.
Validated focused Python and TypeScript regressions plus core typecheck.
* fix(eval): wake the EC2 runner and prove paired evaluator execution
Bootstrap the existing dedicated instance from a protected hosted job, bound
native runner pickup, and stop only instances started by this run. Keep paid
sessions inside the fixed stop window and add a runner-only dispatch.
Require a contained six-cell prepare/session/oracle/report canary in CI,
including a failed repair that remains in the measured denominator.
* fix(ci): reuse existing configuration and disambiguate accuracy cases
Remove the new AWS credential/settings path and release opt-in variable. Bound native runner pickup with the existing GitHub token and retain private EventBridge startup until its existing mechanism can be reused. Reuse current workflow environment names and evolution schedule controls.
Name malformed-observation cases explicitly so the execution audit distinguishes null from missing and actually tests invalid arrays.
* fix(review): isolate release builds and preserve benchmark evidence
* fix(release): gate RC publication on paired quality and manage EC2 lifecycle
* fix(ci): clarify release shell redirects and build script
* fix(eval): remove temporary patch sinks after capture
* fix(bench): retire tool-accuracy allowances repaired on main
Main at 50aa4be3b repaired three #3487 route checks (#3505) and all four
#3499 Python scope checks (#3502, #3504). The ratchet correctly failed the
merged head with stale allowances, so remove them and keep the fixed answers
as release protection: 18/31 pass, 13 recorded gaps remain.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(release): gate RCs on accuracy only and keep paid runs for stable
Follow the cost split proposed in discussion #3493: fixed-answer tool
accuracy on every RC, paired agent runs before stable releases and on a
weekly schedule against the latest RC.
RC publication no longer prepares a bundle, calls release-evaluation.yml
and waits for a paid run of up to 21 hours on the shared EC2 lock. Every
release attaches this run's accuracy report; stable npm publication still
requires exact-commit paired evidence. release-evaluation.yml drops its
workflow_call path and the now-unused candidate bundle module.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(release): address PR #3503 review feedback
- Page through recent release-evaluation runs instead of reading only
the newest 50, so valid stable evidence cannot be pushed off page one.
- Bound each runner-pickup jobs request by the remaining deadline.
- Replace non-finite floats at any depth in failure receipts so the
incomplete report still serializes with allow_nan=False.
- Clarify that the summary.cap case has 501 names over 1001 sites.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(review): harden candidate build and close review gaps
- Mount the candidate checkout's .git read-only inside the build sandbox,
so lifecycle scripts cannot plant git config (e.g. core.fsmonitor) that
host git later runs in that checkout during actions/checkout cleanup.
The real-Bubblewrap canary now also attempts that write.
- Type tool-accuracy observations instead of using explicit any.
- Cover the fail-closed branches reviewers found untested: unsafe or
missing evidence artifacts, mismatched task pins, malformed repo/SHA,
an instance that stops again during bootstrap, and unbalanced GitNexus
guidance markers.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs(release): describe RC accuracy gate and stable evidence step
- CONTRIBUTING now states that RCs are gated by CI (including the
fixed-answer tool-accuracy check) without a paid run, and that stable
publication needs a passing Release evaluation for the exact commit
within seven days.
- The oracle-control fixture passes tarfile's data filter only where it
exists (3.11.4+), matching the declared Python 3.11 floor.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* refactor(bench): pin tool-accuracy fixture line anchors in one place
run.ts bucketed rename edits and explain findings by line literals that
expectations.ts duplicated. Export FIXTURE_ANCHORS (file, line, pinned text)
from expectations.ts, build the fixed answers and run.ts classifiers from it,
and fail loudly (runner and unit test) when a fixture line no longer holds
the pinned text. Expected answers and observations are unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(bench): fail closed when ripgrep is missing from the tool-accuracy run
rename's text-search pass shells out to rg and only logs a degraded warning
when it is absent, so a runner without ripgrep scored a degraded rename
(homonym.ts:1 missing) and still passed. Check rg --version before indexing,
record it in accuracy.json source.externalTools, and install ripgrep in the
ci-tests tool-accuracy job and the docker release-gate (same if: condition).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* refactor(eval): split baseline guidance, share bwrap preamble, drop dead bare option, harden patch cleanup
- Move the baseline (no-GitNexus) guidance scrubbing out of proposer_sandbox.py
into baseline_guidance.py, with its unit tests.
- Expose real_directory, runtime_mount_args and bwrap_base_args publicly so
release_build no longer imports private helpers or re-assembles the shared
bubblewrap preamble; the candidate build command is byte-identical.
- Remove the unused run_claude `bare` parameter and its --bare/--tools branches.
- capture_patch: a failed temporary-directory removal no longer discards the
read patch or replaces an earlier error; it is attached as a note, or warned
on stderr when there was no earlier error.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(ec2-runner): keep stop observing through transient describe failures
- stop() treats a failed or timed-out describe-instances call as unknown
state and keeps observing until the stop deadline; a persistent failure
is still raised at the deadline with the last command error. Unusable
states and identity mismatches still fail at once (new CommandError
subclass separates command failures from semantic ones).
- Readiness CLI has one paid mode: --job-name NAME. --evolve is removed;
skill evolution passes its job name, and tests tie the watchdog command
to the paid job's actual name in both EC2 workflows.
- Jobs-API requests never get a timeout larger than the remaining pickup
budget (previously rounded up to 1s past the deadline).
- Document that the shared concurrency group keeps only one pending run,
so a queued release evaluation can be replaced and must be confirmed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs(eval): record verified EC2 lifecycle configuration
The README still described the AWS settings as assumed and unverified.
The OIDC role, environment settings and runner_only lifecycle were
configured and verified live on 2026-10-09.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(release-eval): grade both runtimes against one pinned task toolchain
Candidate and stable each staged task dependencies (node_modules,
gitnexus-shared/dist) from their own runtime checkout, so the same v1.6.12
task source was graded with different TypeScript, Vitest and LadybugDB
versions and a per-task solve delta also measured dependency drift.
- Check out and build the pinned task commit once (tasks-base) and point
every task's repo at it for both runtimes; the runtime under test reaches
sessions only through --gitnexus-root. prepare requires --task-repo at the
single pinned task commit (new task-sha subcommand resolves it).
- Retain sandbox_dependency_content_digest per measured row and make
release_gate fail when any task's cells, across candidate and stable, do not
share one recorded dependency digest.
- Move the task-pin comparison into validate_report(task_pins=...) and use
it from release_report check and release_gate.
- Cover the gate CLI with a missing and a corrupt candidate report.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs(ci): warn that a pending release evaluation can be replaced
GitHub keeps one pending run per concurrency group, so a newer queued
EC2 run cancels a pending release evaluation. Operators must confirm the
startup job ran before relying on the evidence.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(eval): prove hidden oracles against the grading toolchain
Release evaluation now grades every task with dependencies built at the
pinned task commit (TypeScript 5.9.3, Vitest 4.1.11), but the oracle
controls still ran against the current checkout's toolchain. The Ubuntu
containment job now builds the pinned task toolchain and points the
controls at it. All seven controls pass locally against that build.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(ci): pin the duplicated EC2 lifecycle jobs together
Both EC2 workflows carry their own copy of the live-verified start,
check, readiness and stop jobs. A reusable workflow would change that
verified job structure, so instead a test requires the copies to stay
identical apart from the job display name and the paid-job dependency.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(release-eval): accept stable evidence only from main's current evaluator
Stable publish validated downloaded agent evidence against the release
commit's eval/ tree and never tied a report to the run that produced it.
Evidence from an older evaluator stayed acceptable for seven days after
graders changed, while task changes on main made every fresh evaluation
mismatch the tag. The first invalid artifact also hid older valid runs.
The composite action now extracts eval/ from main's head and runs the
validator there with locked base dependencies only (no dev extras or
project build). A report counts only when its harness_sha is the head_sha
of its trusted main run and the compare API shows no change under eval/,
the release-evaluation workflow or the pinned agent CLI between that
harness and the evaluator; a missing, diverged or 300-file comparison
fails closed. Runs are tried newest first, rejected runs are skipped
with a bounded reason list, every gh call has a timeout, and task pins
use validate_report's task_pins check.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(eval): break the sandbox import cycle and resolve code-scanning alerts
- baseline_guidance is now pure text handling with its own GuidanceError;
the baseline mount builder lives in proposer_sandbox again and converts
that error to SandboxError, so imports run one way only.
- task_assets uses the public real_directory name; the unused private
alias is gone.
- The oracle-control fixture always extracts with tarfile's data filter
and skips on Pythons that lack it, instead of extracting unfiltered.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(release-eval): run candidate lifecycle scripts offline; reject smuggled report fields
- build_candidate now downloads locked dependencies with --ignore-scripts,
then runs every lifecycle script (dependency installs, prepare, build)
in a fresh network namespace, so candidate code cannot reach host-local
services. Verified locally that the current head and the pinned task
commit build this way; the real-Bubblewrap canary now asserts only
loopback is visible to a lifecycle script.
- validate_report requires the evidence document to equal its
field-whitelisted rebuild, so per-run or top-level fields outside the
published schema are rejected before the publisher copies the file.
- The sandbox test suite also covers a no-GitNexus sandbox refusing
unbalanced guidance markers.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* docs(eval): describe the offline candidate lifecycle
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(release-eval): pin downloads to the npm registry; require dependency binding
Address review feedback on PR #3503:
- The candidate's online install phase now refuses lockfile entries that
resolve outside https://registry.npmjs.org/ (other than in-checkout
workspace links) and refuses shipped .npmrc files, so a candidate
cannot steer npm at loopback, private or metadata endpoints.
- Every measured row must carry a 64-hex task-dependency digest, so a
single report cannot be accepted with its grading toolchain unbound.
- Oversized JSON integers mark a measurement untrustworthy instead of
crashing report generation.
- Baseline guidance stripping recognises headings with up to three
leading spaces (CommonMark).
- Remove a stale comment about the old private helper name.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(eval): parse CommonMark ATX headings; compare evidence by exact JSON
- Baseline guidance stripping now parses headings as CommonMark ATX
headings (0-3 leading spaces, optional closing # run, tabs), so a
GitNexus section heading like '## GitNexus rules ##' is removed too.
- Evidence validation compares the serialized rebuild with the report,
so a retyped value (true for 1, 2.0 for 2) no longer passes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(eval): drop continuations of every CommonMark list item in baseline guidance
A removed GitNexus instruction left its indented continuation behind when
the item used '+' or an ordered marker (1. / 1)). The scrubber now
recognises every CommonMark list-item marker.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(eval): isolate candidate MCP from agent task writes (#3503)
Run MCP in a nested Bubblewrap boundary with read-only task, graph,
registry and runtime mounts, private state and isolated processes/network.
Keep task writes on the agent's built-in tools and remove mutating MCP grants.
Add startup/tool mutation canaries and preserve explicit unsafe diagnostics.
Validation: focused pytest 138 passed, 16 skipped. Full locked evaluator
996 passed, 29 skipped; real containment canaries require Ubuntu CI.
Note: eight pre-existing comparator-reuse failures reproduce on the
unchanged head due to missing os.supports_dir_fd support. One process-control
timeout failed in the full run and passed alone and on the unchanged head.
* fix(eval): close baseline mount overlap and test symlink evidence (#3503)
Reject supplied no-MCP mounts that cover forbidden GitNexus paths, including ancestor mounts and lexical aliases. Keep ordinary dependency mounts available.
Exercise evidence symlink rejection with a real valid-report target and retain dangling-link coverage.
Validation: 1026 evaluator tests passed, 29 skipped; targeted mount tests 36 passed and evidence tests 34 passed. Removing the symlink guard in memory makes the repaired regression fail. Ruff and diff checks passed.
Note: eight pre-existing comparator-reuse failures remain in this environment because os.supports_dir_fd lacks the required os.lstat support.
---------
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(fastapi): carry package router mount prefixes to child routes
* fix(fastapi): address review feedback on nested router prefixes (#3408)
- Skip unprefixed includes in the parse-impl legacy loop so a bare
include_router in another file no longer shadows the real prefix.
- Union exact-file prefixes with legacy long/short prefixes via a shared
mergeMountPrefixes helper in both ingestion and the group extractor.
- Join the parent APIRouter(prefix=...) between the mount prefix and the
child include prefix.
- Resolve the group layer over every repo path (empty files included) so
absolute-import ambiguity matches ingestion.
- Memoize (file, prefix) frames so diamond-shaped include graphs stay
linear; drop the stack.pop() non-null assertion.
- Accept extra keyword arguments and a trailing comma in unprefixed
include_router calls without double-firing on prefix= calls.
- Document that pass-through is limited to a host named `router`.
- Bump parse-cache SCHEMA_BUMP to 123 for the new capture fields.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(fastapi): seed prefix propagation from bare router mounts (#3408)
- A router mounted without a prefix now seeds traversal with an empty
prefix (only when no prefixed mount targets the same file), so its own
APIRouter(prefix=...) reaches unprefixed children on both surfaces.
- An all-empty chain records nothing and leaves the child on its legacy
fallback.
- The bare-mount integration test no longer asserts that the test app's
unprefixed mount is absent; it pins only that the real prefix survives.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(fastapi): capture include prefixes after nested-call arguments (#3408)
- Let the Shape A/B and unprefixed include_router patterns step over one
level of nested calls such as dependencies=[Depends(auth)], so a
prefix= written after them is captured by the worker (the group
layer's tree-sitter patterns already handled this shape).
- Replace the unit test that pinned the dropped prefix with one that
pins the captured prefixes and the unprefixed Depends-only edge; add a
group-layer parity test.
- Correct the diamond test comment to 2^39 root-to-leaf paths.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): model restoring helper calls in decorator identity (#3414)
A bare module-level call to a same-file helper whose every global
binding of a descriptor name is an unconditional del or builtins import
now restores the builtin at the call site, matching CPython. A nonlocal
rebind nested in the enclosing function now shadows an owned builtins
import, closing a false builtin. Unprovable call orders stay fail-closed
and are pinned against CPython 3.11.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(review): apply review findings
Close three false-builtin paths the review found: a match-pattern
capture now counts as a binding (at any scope, including inside a
restoring helper), a call before the helper's def no longer counts as a
restore, and the helper-name uniqueness check sees match captures.
Pin the helper rejections (conditional restore, async, early and nested
return, wildcard import) against CPython 3.11.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(cache): bump parse-cache schema to v122 for #3414
Python decorator identity verdicts changed, so warm v121 ParsedFiles
would replay stale receiver bindings.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): require an argument-free call to a helper with no required parameters
A call that fails to bind the helper's parameters raises TypeError
before the body runs, so it proves no restore. Keep such calls
fail-closed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): count only real captures and module bindings for decorator identity
Match value patterns, class names and keyword keys read a name rather
than capture it, so they no longer shadow a builtin descriptor. A local
of the same name as a restoring helper no longer disqualifies the
module-level helper; only a module binding or a global rebind does.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(python): state the fail-closed contract of the descriptor identity table
`false` means the resolver does not prove the builtin, not that CPython
shadows it. Cases where CPython keeps the builtin but the resolver fails
closed carry a comment saying so.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): resolve decorator identity like CPython
Decorator identity was decided by two different predicates. One read
the raw decorator text, so a trailing comment such as
`@staticmethod # type: ignore` hid the builtin and turned an explicit
first parameter into a fabricated receiver. The other trusted any
`staticmethod` spelling, including a module-level rebinding and a
`staticmethod(classmethod(f))` stack, which CPython cannot call.
Read the decorator expression node only, and recognize a bare builtin
descriptor only when the file does not rebind that name. Publish subtype
capacity only for a plain function or a single builtin staticmethod or
classmethod wrapper. Drop a no-op coverage guard, move the implicit
classmethod comment next to the code it describes, and bump the parse
cache to v121.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): shadow builtin descriptors only by visible bindings
The whole-file identifier scan counted plain reads (`staticmethod(f)`),
`from builtins import staticmethod`, and bindings that run after the
decorator as rebindings. CPython evaluates a class-body decorator with
LOAD_NAME when the `def` runs, so none of those change which object the
decorator names. Methods decorated with the real builtin lost their
subtype call shape, and static methods lost their first parameter in
arity metadata.
Move decorator identity into builtin-descriptors.ts and count only
binding occurrences (assignment and loop targets, walrus, def/class,
parameters, import aliases, except/with/match captures, del, type
parameters, and wildcard imports) that are visible where the decorator
runs: the class body or module before the definition, a repeating
enclosing loop, any binding in an enclosing function, and any
global/nonlocal rebind.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): model global and del like CPython's symbol table
`global x` and `nonlocal x` bind nothing; they redirect the declaring
function's own bindings of `x` to an outer scope. A bare declaration
was treated as an unconditional rebinding, so `@staticmethod` anywhere
in the file lost builtin recognition.
A module- or class-level `del` restores the outer lookup rather than
binding the name. Treat an unconditional `del` that runs after a
binding and before the decorator as undoing that binding. A `del`
inside control flow may not run, and a `del` inside a function still
makes the name local there.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): order global rebinds and honor builtins re-exports
A function that declares `global staticmethod` and assigns it rebinds
the module name only when called, and it cannot be called before the
top-level statement that defines it runs. Treat such a rebind as
visible only when that statement precedes the decorator, or when the
decorator sits in a deferred class body. `nonlocal` rebinds stay
visible anywhere in the enclosing function.
`from builtins import staticmethod as staticmethod` binds the builtin
to its own name, so it no longer counts as shadowing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(python): scope the descriptor-identity CPython claim
The wildcard-import case expects the fail-closed resolver verdict, not a
CPython outcome, because the imported module's exports are unknown.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): resolve descriptor names as LOAD_NAME does
Model each binding by its effect on the namespace (Language Reference
4.2.1): an import that binds the `builtins` object itself (plain, aliased
to the same name, or `from builtins import *`) restores the builtin, a
module- or class-level `del` unbinds so lookup falls through, and any
other binding shadows. Resolve the decorator like LOAD_NAME (4.2.2):
the class namespace, then module globals, then builtins, each as it
stands when the `def` runs.
A restoring effect counts only as an unconditional simple statement that
runs before the decorator, so an import or `del` under `if`/`try` or a
loop stays fail-closed. A helper's `global` delete depends on whether
the helper is called, which the resolver does not model, so it keeps the
override.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* refactor(python): simplify decorator descriptor lookup
Derive the descriptor type and name set from one `as const` list,
replace indexed non-null assertions with destructuring, build the scope
chain without an assertion, and skip the enclosing-function owner lookup
when the decorator has no enclosing function. Key the stacked-decorator
verdicts by case name so a failure names its case.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): resolve enclosing-function and deferred descriptor lookups
A class body reads a free name from the innermost enclosing function that
binds it (Language Reference 4.2.2). Evaluate that function's namespace
the same way as the class and module ones, so an unconditional
`from builtins import staticmethod` there resolves to the builtin. Any
other binding still shadows, including a local assigned only after the
class, which raises NameError rather than falling back to the builtin.
A class body inside a function runs whenever that function is called,
which can be any time after its top-level statement starts. Read module
state at that statement instead of after the whole module, so an earlier
`del` restores the builtin, and treat any later module override as
possibly visible.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): suppress uncertain decorated receivers
* fix(ci): keep uncertain Python receivers out of method arity
Unrecognized decorators now leave the receiver kind unproven, but the
first parameter is still the implicit receiver slot for ordinary bound
calls. Method extraction stopped stripping it, so decorated methods
reported one extra parameter and shifted capture arity metadata.
Share the uncertain-receiver classification between type-binding
synthesis and parameter extraction, then refresh the Python capture
golden and benchmark fingerprint for the intended capture change.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(python): resolve mixin calls with CPython C3 order
Breadth-first MRO bound a diamond mixin call to the wrong base, and dropping the site left the real method out of the graph. Use C3 and take the first compatible method in that order.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(autofix): apply prettier + eslint fixes via /autofix command
* fix(python): correct mixin receiver baseline counts
* fix(python): guard incomplete mixin inheritance
* fix(python): record unresolved MRO tail coverage (#3393)
Track a missing subtype target when the last indexed MRO owner has an unindexed parent, and cover the case with an integration test. Correct the C3 fixture description.
Note: local full npm test timed out amid parse-worker startup failures; focused tests and benchmark baseline passed.
---------
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* feat(mcp): add read_file + grep tools (REST parity for /api/file slice + /api/grep)
* chore(autofix): apply prettier + eslint fixes via /autofix command
* Address PR review feedback (#3377)
- Fail read_file and grep when full source is unavailable, matching the HTTP 410 contract instead of an empty grep or a not-found on a missing checkout.
- Reject branch on those tools so a pinned index is not labeled onto checkout bytes, and stop advertising branch in their schemas.
- Point the grep hint at a 0-based read_file window, pass caseSensitive and literal through, and test the handlers.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Address PR review feedback (#3377)
- Keep read_file and grep in the multi-repo schema requirement without advertising branch.
- Reject negative maxLines and return integer slice bounds for fractional line positions.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Address PR review feedback (#3377)
- Reject a negative read_file endLine before slicing so JavaScript does not treat it as an offset from the end of the file.
- Drop the fractional startLine/endLine claim so the integer schema is the advertised contract.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Address PR review feedback (#3377)
- Skip indexed grep paths whose realpath leaves the checkout so a symlink cannot return lines from outside the repo.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(bench): record the 19-tool MCP roster
read_file and grep are real tools, so tools/list and GITNEXUS_TOOLS both
moved from 17 to 19. The timing ratios were already inside budget.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(mcp): share read_file and grep contracts with existing helpers
Boolean grep flags go through isFlagTrue, the whole-file cap is one constant, and checkout tools stay on the per-repo schema without advertising branch.
---------
Co-authored-by: svjack <svjack@example.com>
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(#2965): system headers must not resolve to in-repo files
C and C++ use two syntactically distinct include forms:
#include <x.h> -- angle-bracket: search system include paths only
#include "x.h" -- quoted: search relative to the including file first
The old suffix-match fallback in resolveCImportTarget had no awareness
of this distinction, so a repo containing its own stdio.h would capture
every #include <stdio.h> and resolve it to the local file.
Fix:
- Add isSystem?: boolean to the wildcard variant of ParsedImportSyntax
- interpretCImport / interpretCppImport now set isSystem from the
@import.system tree-sitter capture (present for angle-bracket form)
- resolveImportTarget in both cScopeResolver and cppScopeResolver
short-circuits to null when context.parsedImport.isSystem is true,
refusing to suffix-match system headers against workspace files
- Remove C and C++ from KNOWN_GAPS in the conformance test; add proper
test cases with a parsedImport factory that distinguishes angle-bracket
(isSystem:true) from quoted (isSystem:false) includes
Test: all 36 external-import-conformance cases pass, including the two
new c/cpp arms that were previously in KNOWN_GAPS.
* fix(#2965): update cpp-imports unit tests for isSystem field
Two test assertions were broken by the interpreter change:
1. Local include: the wildcard ParsedImport now always includes
isSystem (false for quoted includes). Updated expected object
to include isSystem:false.
2. System header: the old test asserted interpretCppImport returned
null for system headers. The refactored design moves the null
decision to the resolver layer (cppScopeResolver.resolveImportTarget)
so the call graph and resolution stay separate concerns. The
interpreter now returns { kind:'wildcard', isSystem:true } and
the test name/assertion are updated to reflect this.
* fix(#2965): resolve C and C++ includes on search paths
Angle includes follow each translation unit's include roots, so a local
stdio.h no longer captures system headers or another file's -I list.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Address PR review feedback (#3341)
- Accept in-repo include roots whose names start with `..` while still rejecting parent escapes.
- Correct the import-target bench comments so CONTEXT_LANGS and newPass match C/C++ header passes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(c,cpp): read include config per directory for monorepos (#2965)
Angle includes now resolve only against declared search roots, so config
read only at the repo root left monorepo sub-projects with nothing declared.
- compile_commands.json, compile_flags.txt, .ccls, .clangd and
c_cpp_properties.json are read in every directory; a file takes the
nearest one, and a nearer database's entry beats a shallower one (clangd).
- CMake include_directories / target_include_directories are read:
directory-scoped and PRIVATE roots reach their subtree, PUBLIC and
INTERFACE roots reach every file. ${CMAKE_CURRENT_SOURCE_DIR} and friends
expand; unresolvable variables and generator expressions are dropped.
- Declared roots win: implicit include/Headers/inc roots apply only when no
config speaks for the file, and never to a database-listed file.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(c,cpp): give CMake PUBLIC includes only to linked targets (#3341)
target_link_libraries now decides who sees PUBLIC and INTERFACE roots, so an unrelated target no longer resolves another package's headers.
---------
Co-authored-by: Gergő Magyar <gergomagyar@icloud.com>
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(auto-sync): allow self-hosted remotes via allowed_hosts
Auto-sync skipped any remote whose host was not github.com, gitlab.com, or gitee.com. Operators can now name exact extra DNS hosts in watch_config.yml without opening the default set.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Address PR review feedback (#3391)
- Dial auto-sync DNS names as absolute hosts and store that URL so a later fetch cannot follow a search domain.
- Reject ambiguous numeric host spellings; an exact dotted IPv4 the operator listed stays opt-in.
- Document allowed_hosts on the root auto-sync contract.
Note: pre-existing failure in unit tests that require dist/cli/index.js and parse-worker.js (this worktree has no build); not addressed by this PR.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(swift): discover nested Package.swift manifests for module grouping
A Swift monorepo laid out as Core/<pkg>/Package.swift has no root manifest
and no root Sources/, so every Swift file fell into one __default__ module.
The Swift resolver now walks the repo (bounded, skipping dot, ignored, and
Xcode bundle directories) and adds each nested package's targets, keyed by
repo-relative directory and ordered deepest-first so first-match grouping
picks the most specific target. Import resolution keeps the root view.
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(swift): bound implicit IMPORTS edges by a total budget
Implicit same-module IMPORTS are n*(n-1) edges per module, and the graph
keeps every relationship in one Map capped by V8 at 2^24 entries. Emission
now fills a 4M-edge budget smallest module first and skips, with a warning,
any module that does not fit, so no module layout can crash analyze.
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(swift): skip pairwise sibling passes for oversized modules
The target-siblings and sibling-type-bindings passes copy every file's
declarations into every other file of a module, so heap grows as n^2:
about 3.8 GB at 1,000 files with 15 defs each, about 15 GB at 2,000.
Modules over 1,000 files now skip both passes with a warning and resolve
through the global name fallback. GITNEXUS_SWIFT_MAX_MODULE_FILES changes
the ceiling.
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(swift): cover nested SwiftPM packages end to end
A fixture with three nested Package.swift manifests (two declaring a target
named Net) and no root manifest. Each target gets its own implicit IMPORTS,
none cross packages, and Config() resolves to the caller's own package.
The Swift capture golden and scope-capture fingerprint grow with the new
fixture corpus only.
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(review): apply review findings
- Rebase nested target paths with the existing Zig path helpers, which also
reject Windows drive paths and paths that resolve to the repo root (whose
empty prefix would group every file into one target).
- Document GITNEXUS_SWIFT_MAX_MODULE_FILES in the README env table.
- State that skipped modules resolve through lower-confidence fallback edges,
why nested-type fragments still run for oversized modules, and fix a stale
loader name in the target-grouping header.
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(swift): cover every skipped Xcode bundle suffix in the package walk
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(swift): model modules the way the compiler does
Replace the caps from the first round with representations that stay
linear, and derive module identity from the same sources the compiler uses.
- Same-module visibility is one File -> Module IMPORTS edge per file
(reason `module-membership`) instead of an edge per ordered file pair.
Incremental importer expansion treats files sharing a Module hub as
importers of each other. The 4M edge budget is gone.
- Sibling declarations and type bindings live in one shared table per
module in the namespace channel C# uses since #1871, instead of being
copied into every file. The 1,000-file ceiling and
GITNEXUS_SWIFT_MAX_MODULE_FILES are gone.
- Modules come from root and nested SwiftPM manifests (Sources, Source,
src, srcs; plugins under Plugins; the newest Package@swift-X.Y.swift)
and from Xcode native targets in project.pbxproj, including Xcode 16
synchronized folders. Target paths are matched from the repo root, so
a vendored copy of the same layout is no longer grouped into a root
target (this reverses #2931's floating match).
- `import X` resolves to the modules named X instead of any folder named
X. A name no module carries is external when every manifest and
project was read completely.
- The global-name-fallback veto uses the same membership, so test
targets, custom-path targets and Xcode targets have module identity.
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(bench): move the Swift package bench to module grouping
The bench still imported the removed groupSwiftFilesBySpmTarget. Its
first-wins probe keeps its meaning under root-anchored grouping: the
clash file sits under Sources/Mod0, and the Sources/Mod1 further down its
path is a vendored copy.
Plugins are now non-importable modules under Plugins/, so parse_targets
counts importable source targets (still 3) and parse_binary_skipped also
checks that the plugin is recorded that way. Baseline values unchanged;
the notes say why the definitions moved.
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(swift): match compiler module names, manifests, and target filters
- Module names follow the compiler's c99 mangling (`my-lib` imports as
`my_lib`); Xcode targets use a literal PRODUCT_MODULE_NAME or
PRODUCT_NAME when the project sets one.
- Package manifests are one-file modules, as SwiftPM compiles them. Files
outside every target are one-file modules once every manifest and
project was read; otherwise they keep the shared __default__ module.
- Xcode 16 synchronized-folder exceptions add a file to a target that
does not list the folder, and remove it from one that does.
- SwiftPM `sources:` / `exclude:` narrow a target; a computed list marks
the manifest unreadable.
- The default target folder is chosen once per package, as SwiftPM does,
instead of per target.
Refs #3355
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Address PR review feedback (#3387)
- Inferred Swift folders keep SwiftPM's first predefined parent when a
target name repeats (Sources before srcs).
- The pbxproj parser rejects a \U escape without four hex digits instead
of decoding garbage, so the project reads as incomplete.
- Extension owners are stamped in every Xcode membership of a shared file.
- A plugin name never reaches a plugin: neither the fallback veto nor the
folder-index fallback treats a known non-importable module as imported.
- A file an Xcode target compiles keeps that membership even when it also
lies under a SwiftPM target directory.
- The workspace scan bounds the queue, not only the directories read.
- Integration tests require each module hub to exist before comparing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>