Commit Graph

1312 Commits

Author SHA1 Message Date
Colby McHenry 533c1af768 docs(changelog): ready [Unreleased] for 1.6.2; release verify waits up to 5 min
- Adds the Highlights block and groups the 164 entries the way 1.6.1's notes
  are: New Features for the newly supported routes and newly indexed code,
  Fixes under sub-headings (Windows; the background server and CLI; indexing;
  across languages; then one per language family) so a skimmer finds their
  area. Duplicates left by merges are folded together (the Windows console
  window entry twice; two overlapping Vapor closure-route entries; three
  Windows crash entries into one). No entry's wording is otherwise changed.
- The release workflow's "Verify every package is actually on the registry"
  gave each package 60 s. 1.6.1 published all seven packages fine, but the
  first took longer than that to appear and the run went red. It now waits up
  to 5 minutes per package.

No viewer entries: those stay in docs/viewer-launch-changelog.md, and
`codegraph ui` stays behind CODEGRAPH_UI=1 (checked on a fresh build: absent
from --help, refused with the "not in this release yet" message).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:46:17 -05:00
Colby Mchenry 70fe0ecc52 fix(windows): helper threads never end mid-start or with GC marking in flight (#2309)
On Windows a worker thread that ends - terminate(), its own process.exit(),
or the process exiting - while V8's concurrent marker is marking its heap
crashes the whole process (exit 3221225477 / 0xC0000005, no error, no dump).
Bisected on the Windows 11 ARM64 VM: --no-concurrent-marking alone stops it
(18/480 -> 0/480; no other concurrency flag does), but it costs about a third
of indexing speed, so CodeGraph avoids the dangerous moments instead:

- src/worker-teardown.ts: owners terminate a worker only once it has started
  (its first message, posted after its modules load - mid-load is by far the
  worst moment), and a worker about to exit runs a full collection first,
  which finishes any marking in flight (gc reached at runtime, never global).
- Resolver pool / store writer: the worker collects before exiting on
  'close' (the normal path - main 21/480 crashed on the VM, now 2/1200), and
  the 5 s close fallback never terminates a worker still starting.
- codegraph_status change counts: the worker posts 'loaded' after its heavy
  require and collects before answering; a deadline answers unknown at once
  but terminates only once loaded (3/720 -> 0/1440), and MCPEngine.stop()
  waits for measurements in flight.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:58:28 +00:00
Colby Mchenry 3d86bcc037 fix(windows): the query pool never terminates a worker still starting up (#2307)
Terminating a worker thread while it is still loading its modules can crash
the whole process on Windows (exit 3221225477 / 0xC0000005, no error, no
dump). QueryPool.destroy() terminated every worker at once, and the daemon
destroys its pool whenever it stops - a session that ends within a few
seconds of starting had its eager worker in exactly that state.
MCPEngine.stop() didn't even wait for the pool before the daemon called
process.exit().

- QueryPool tracks each worker's start (settled on 'ready', error or exit);
  destroy() answers outstanding calls first, then terminates each worker once
  it has started, capped at 15 s - the parse pool's #2301 mechanism.
- MCPEngine.stop() awaits the pool.
- #2301's explanation is corrected: on the Windows VM, terminating workers
  mid grammar compile never crashed (0 in 2,161), but terminating them while
  they load CodeGraph's extraction modules did. The parse pool's wait already
  covers that window, so only its comment and changelog wording change.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 18:03:28 +00:00
Colby Mchenry 9d4e805bec test(windows): daemon-pid-reuse cleanup retries a still-held temp dir (#2304)
afterEach SIGKILLs the servers and the detached daemon, waits 50 ms and
removes the temp dir. A killed process releases its handles asynchronously on
Windows, and under full-suite load the removal hit EPERM on the VM (the test
itself passed; it passes 3/3 alone). Retry the removal like the other
process-spawning suites do.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:36:42 +00:00
Colby Mchenry e0f9c95e2f fix(resolution): a busy machine doesn't boot the resolver pool for a small project (#2303)
The resolve loop boots the worker pool mid-run when the remaining refs'
projected sequential settle (observed per-ref rate x refs left) clears 400 ms.
Load inflates the observed rate, so on a loaded 4-core Windows VM a ten-file
project (19 refs) projected 506 ms for its last 11 and booted three workers in
122 of 240 runs under 24 parallel inits (0 of 80 at 8). The pool only fans
out batches of 1,000 refs, so it resolved nothing; synthesis then waited out
its boot (dedupe-merge 6.3 s vs a 6.5 s boot) and its three extra database
connections pushed the VM's free commit to 11 MB.

Adaptive engagement now also needs 20,000 refs left. tokio-class Rust repos
(~55k refs at ~36 us) still engage; a smaller remainder never repays a
seconds-long boot. With the floor, the same load booted the pool in 0 of 240
runs.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:20:23 +00:00
Colby Mchenry 91b9bba133 fix(extraction): never terminate a parse worker while it is loading grammars (#2301)
On a loaded Windows machine `codegraph init` / `index` sometimes died right
after the parse phase with 0xC0000005 (STATUS_ACCESS_VIOLATION), no WER report
and no output past the last parsed file. The parse pool's destroy() terminated
every worker at once, and a short index often ends while a late-spawned worker
is still compiling its grammar WASM; terminating a worker with that compile in
flight crashes the process.

Reproduced on a Windows 11 ARM64 VM without CodeGraph's pipeline: starting
three parse workers with preloaded grammar bytes and terminating them mid-load
crashed 5 of 720 child processes, terminating them only after
grammars-loaded crashed 0 of 360. Under the real load (24 parallel
`codegraph init` runs on 4 cores) main crashed after parsing in 8 of 1,200
runs; with this change 0 of 1,080 did.

destroy() now waits for a worker that is still loading to report
grammars-loaded or exit before terminating it, capped at 15 s so a wedged load
can't hold teardown forever. Recycling only ever touches idle workers, and a
hung parse is still killed by the hard timeout.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 08:48:01 +00:00
Colby Mchenry 8abebda02c test(windows): two #1910 tests no longer time out on Windows (#2298)
oversize-file-not-read's drift test wrote a 1.4 MB `.js` made of one statement
repeated 110k times. Windows Defender's script scan of that freshly written
file takes about 54 s on its first read (the viewer's read in the test), so the
test always timed out on Windows and its cleanup then hit EPERM on the still
open file. A varied 2.4 MB `.js` and a real 2 MB bundle scan in 35 ms and
144 ms, so this is the fixture, not something users hit; the fixture now has
a different statement on every line.

The mpeg-ts git-path cases build a git repository and index it, the last one
twice. At ~100 ms per git process on Windows that is 5–6 s, past vitest's 5 s
default; the describe now allows 30 s.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 07:07:34 +00:00
Colby Mchenry 273e5cdc4c fix(upgrade): a Windows upgrade no longer breaks the install while CodeGraph is running (#2185) (#2294)
* fix(upgrade): a Windows upgrade no longer breaks the install while CodeGraph is running (#2185)

On Windows, `codegraph upgrade` renamed only node.exe aside and then
Copy-Item'd the new bundle over current\. Any open agent session runs a
CodeGraph MCP server from current\, which keeps the native kernel loaded, so
the copy failed on lib\kernel\codegraph-kernel.node halfway through, leaving
no node.exe and a mix of versions that no codegraph command could repair.
Re-running install.ps1 failed the same way, because it Remove-Items current\.

Both now share one PowerShell function (a test pins the two copies equal).
The bundle is unpacked next to current\ (same volume), then swapped in file
by file: every file being replaced or dropped is first renamed aside (Windows
allows renaming a running exe or a loaded DLL, just not overwriting or
deleting it), then the staged file is moved in. Any failure or interruption
undoes every step. Renamed-aside files, including the node.exe.old-* left by
earlier upgrades, are deleted on the next successful run once nothing holds
them. The upgrade's exit code now tells whether the install was left
unchanged or needs a reinstall, and the message says which.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(changelog): Windows upgrade with CodeGraph running (#2185)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 06:19:41 +00:00
Colby Mchenry 7bbc1fb7f6 fix(tests): the test suite no longer writes to the developer's real home dir (#2275) (#2295)
Running the suite on a machine with Claude Code configured could wire the
CodeGraph prompt hook into the developer's own ~/.claude/settings.json:
every upgrade test whose fake upgrade succeeded ran the real post-upgrade
prompt-hook self-heal, which detected the real global Claude profile and
wrote it. Daemon suites likewise left records in the real
~/.codegraph/daemons. On Windows a HOME-only redirect would not have
helped, since os.homedir() reads USERPROFILE there.

- The prompt-hook writer is now injected through UpgradeDeps
  (wirePromptHook); the CLI passes the real defaultWirePromptHook and the
  upgrade tests a recorder. New tests pin that a successful upgrade calls
  the recorder and that the real writer never touches a configured profile.
- A vitest setupFiles entry gives every engine test file a throwaway home:
  HOME/USERPROFILE (plus HOMEDRIVE/HOMEPATH/APPDATA/LOCALAPPDATA on
  Windows), XDG_CONFIG_HOME, and GIT_CONFIG_GLOBAL (seeded with a dummy
  identity) point into it, and CLAUDE_CONFIG_DIR/CODEX_HOME/COPILOT_HOME/
  HERMES_HOME are cleared. Spawned CLI/MCP children inherit it. A sandbox
  test asserts os.homedir(), the Claude profile, the daemon registry, a
  child process and git's global config all resolve inside it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 06:18:46 +00:00
Colby Mchenry e7389b22fb fix(mcp): a session serving in-process hands the project back to the shared daemon (#2277) (#2293)
* fix(mcp): a session serving in-process hands the project back to the shared daemon (#2277)

When a proxy lost its daemon (or never reached one) it served the rest of
the session through an in-process engine. That engine takes the project's
writer lock in fallback mode and nothing ever released it or tried the
daemon again, so every later daemon start for the project failed on the
held lock and every other session ran read-only without auto-sync until
that one session ended. Sessions that fell back read-only stayed read-only
for life too.

The degraded proxy now retries the shared daemon with backoff (5 s,
doubling to a 5 min cap; CODEGRAPH_DAEMON_RETRY_MS / _MAX_MS, 0 disables)
through the existing probe/spawn/poll path. A writing engine is stopped
first, after the calls it is serving have answered, so its lock is free
before a daemon is spawned and two writers never overlap; calls arriving
meanwhile are buffered and go to the daemon, or are served in-process
again if none comes up. A read-only engine keeps serving until a daemon
answers and is closed once its calls finish. The client's initialize is
replayed to the new daemon with its reply suppressed, as on first attach.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(changelog): a degraded session hands the project back (#2277)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 06:18:02 +00:00
Colby Mchenry 45a680df07 fix(mcp): one daemon per project however its root is cased on Windows (#2278) (#2285)
* fix(mcp): canonicalize the daemon rendezvous root on Windows

A project spelled d:\work\codegraph or D:\work\codegraph is one directory, but the daemon socket/pipe name and the registry record name hashed a raw path.resolve, which preserves whichever casing the caller passed. A proxy that computed the other casing probed a socket nobody bound, spawned a redundant daemon, and that daemon exited on the lock the running one held, so the session silently served the graph in-process: no shared watcher, no auto-sync, one extra copy of the index per open window.

Both names now come from one shared canonicalProjectRoot (native realpath, lowercased on win32), so every spelling meets the same daemon and codegraph list / stop --all see one record per project.

(cherry picked from commit 1811788018)

* fix(mcp): share one in-process project however its root is cased (#2278)

The engine's project lifecycle and `codegraph stop`'s registry fallback keyed
a project by its realpath, which keeps the caller's casing, so two spellings
of one root opened two graphs and two watchers in one process. Both now use
the same identity key as the daemon socket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0a3239e603d5796b9f2cf636b4c09635239e32dd)

* docs(changelog): file the Windows rendezvous fix under Unreleased

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: 养心堂主 <zhouzhk@qq.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 06:16:25 +00:00
Colby Mchenry 7c01910e54 fix(cfml): tag-based calls, wrapped functions and <cfinterface> are indexed (#2091) (#2296)
* fix(cfml): tag-based calls, wrapped functions and <cfinterface> are indexed (#2091)

Tag-based CFML lost almost all of its call edges. The tag walk sent only
<cfscript> and <cfquery> bodies through call extraction, although the cfml
grammar parses the expressions in <cfset>, <cfif>/<cfelseif>, <cfreturn>
and #hash# (output, strings, attributes) with the same rules as cfscript.
The walk now records each such expression with the scope that owns it
(the enclosing <cffunction>, else the component, else the file) and reads
them all through the existing cfscript extraction in one parse per file:
the expressions are copied out on their original lines, each ended with a
`;`, and every reference is handed back to its expression's scope with its
column restored. <cfloop condition="..."> is read the same way.

A <cffunction> nested in a generic container tag at component or template
scope (<cfprocessingdirective> in Application.cfc, <cfsilent>) was skipped
because only direct children were examined; it is now extracted (never
through an ERROR node, where a lost <cfcomponent> would misfile methods as
top-level functions). <cfinterface>, a generic tag to the grammar, now
yields an interface node with its functions as methods and an `extends`
ref per comma-separated parent, so `implements` resolves to it.

The tag-based parse tree is now freed after the walk.

Resolution: the CFML/Ruby/C# bare-call scope filters evaluated the
receiver-on-line check once per same-named candidate though only the ref
decides it. With tag calls extracted, that made Mach-II's resolution ~8x
slower; the check is now memoized per ref (edges byte-identical).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(changelog): tag-based CFML calls (#2091)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 05:00:47 +00:00
Colby Mchenry 2ff7a99c0e fix(cpp): bound the macro-visibility include walk (#2127) (#2292)
* fix(cpp): bound the macro-visibility include walk (#2127)

isVisibleCppMacro walks the call site's translation unit to learn whether a
function-like macro is visible there (#1838). A header whose guard the walk
cannot decide -- `#define X_H 1` (the OpenSceneGraph / osgEarth idiom, which
guardsItself does not read as a guard), or any header reached under an
unknown `#if`, where neither its guard nor `#pragma once` settles -- was re-scanned on
every inclusion path, and every re-scan pushed its define events onto the
cached timeline again. On a layered include graph that is 2^depth scans and
2^depth timeline entries: "Resolving refs" died with "Ineffective
mark-compacts near heap limit" at the first ref whose file reached such a
tree, at the same ref whatever the heap size.

The walk now keeps a version that every observable change bumps
(definitions, `#pragma once`, the macro-name set). A re-entry with the same
inherited truth, while the version still equals that of an earlier visit
which itself changed nothing, is skipped: it would start from the same state,
take the same branches and change nothing again, and the events it would push
repeat each macro's current state, already its last event. Include cycles cut
by the recursion stack are recorded per visit and must still be cut for a
skip. A hard budget of 1M directive events per walk bounds what is left;
past it the timeline is unknown and nothing at or after the cut line is
suppressed, so the budget can only fall back to ordinary resolution, never
invent a macro.

Answers are unchanged: 20,000 random include graphs (guards bare / valued /
pragma once / under flags, #if/#elif/#else, #undef, cycles) give identical
isVisibleCppMacro results to the previous walker on 1.25M queries, with
about one re-entry in eight skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 73db32f81a)

* docs(changelog): credit the C/C++ macro walk bound

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:49:00 +00:00
Colby Mchenry f838c5a02a fix(resolution): resolve method values on untyped Python module globals (#2074) (#2291)
* fix(resolution): resolve method values on untyped Python module globals (#1820)

A method value whose receiver is a module global without a static type
(`thread_pool_exec(settings.conn.fetch, ...)`, where `conn = None` is
rebound by `global conn; conn = Backend()`) resolved to a `variable` node
and produced no edge. The global's type is now the set of classes its
module assigns to it, at module scope or in a function that declares it
`global`. One class resolves to its own method; several bind to the
nearest declaration every candidate inherits, as a base-typed receiver
does.

No edge (a wrong callback edge is worse than none) when:
- any binding of the global in its module is not a whole constructor
  call: a factory, a conditional, a tuple target, `for`/`with`/import,
  a star import, or an annotation the constructor contradicts;
- the caller or an enclosing function binds the name itself: parameter,
  assignment (any target position), loop, comprehension, `as`, `case`
  pattern, lambda parameter;
- the receiver is a deeper chain (`settings.conn.pool.fetch`);
- the importing file rebinds the name, or imports it from two sources.
Statements are read with their continuation lines, and only statement
lines (bracket depth 0) can assign. Not seen: rebinding the global from
another module (`settings.conn = X`) or through `globals()`.

`pkg.mod.Cls` now resolves through `import pkg.mod`, unless two namespace
imports share the last segment.

Python import mappings also read parenthesized from-imports
(`from x import (\n    A,\n    B,\n)`), which previously yielded the
single name `(` and hid every class imported that way from receiver and
inheritance resolution. Comments and docstrings are stripped first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit 0aab32a18b)

* fix(resolution): account for writes to a Python module global from other files (#2074)

The module-global receiver type was read from the global's own module only,
so `settings.conn = Decoy()` in another module, or `globals()["conn"] = X`,
left a stale type and a wrong edge.

- A production write `<module>.<name> = Cls(...)` from another file joins
  the type set (resolved in the writing file); any other production write
  (another value, a tuple target, `setattr`/`patch.object`) makes the type
  unknown. The module is matched through each file's imports, including
  aliases and relative imports.
- Test files install doubles (`settings.conn = MagicMock()`,
  `monkeypatch.setattr(settings, "conn", ...)`): they do not change the
  production type, but a ref inside such a test resolves nothing.
- `globals()[...] = ...` with the global's name or a computed key, and
  `globals().update(...)`, in the global's module make the type unknown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit 2055711226)

* fix(resolution): match a module global's writers by file, not dotted suffix

Review follow-up to the cross-module write scan.

- A write now lands on the file its import names: relative imports resolve
  exactly, absolute ones by path suffix; when a spelling could name another
  file sharing the tail (`x/settings.py` and `y/settings.py` for
  `import settings`), a write through it makes the type unknown instead of
  feeding or clearing the wrong module.
- `import a.b` binds `a`: the module is spelled `a.b`; the mapping's
  last-segment name is not treated as an alias of it.
- Test doubles are recognised by the narrow test-suite set plus any
  `conftest.py`; examples, fixtures and benchmarks are production writers.
- Writes inside `if __name__ == "__main__":` are script code, not module
  state, in the global's module and elsewhere.
- Namespace-dict writes: `globals()`, `vars()` and `sys.modules[__name__]`
  are read per statement (continuations joined, strings ignored); any use
  other than a literal-key read or `.get`, or a literal-key write of the
  name, makes the type unknown. `<module>.__dict__[...]` / `.update(` from
  another file does too.
- `settings.conn: Store = Store()` and `settings.conn = (Store())` are
  plain constructor writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit 7aab29269a)

* fix(resolution): explicit dotted aliases, one-line __main__ guards, scoped vars()

Review follow-up.
- `import pkg.settings as settings` binds `settings` even though it equals
  the last segment; the import mapping cannot tell it from a plain
  `import pkg.settings`, so the source line decides.
- `if __name__ == "__main__": stmt` on one line is script code, and a
  `globals()` write inside a `__main__` block no longer counts.
- `vars()` is the module dict only at module scope; inside a function it
  is the locals, so `return vars()` there no longer makes the type unknown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit 0a5fb69797)

* fix(resolution): explicit-alias check matches the exact module, outside strings

Review follow-up: `import other.pkg.settings as settings` or a string
`"import pkg.settings as settings"` no longer marks a plain
`import pkg.settings` as explicitly aliased, which attached a write to the
wrong module.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
(cherry picked from commit a5569a07ea)

* test(resolution): give the Python module-global adversarial table its own timeout

It indexes one project per case, which takes about nine seconds on macOS,
past vitest's five-second default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(changelog): Python module globals and multi-line imports (#2074)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Josh66 <info@aska-systems.de>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:47:36 +00:00
Colby Mchenry a4bd890ec6 fix(python): a call on self is never resolved through a same-named import (#2290)
The Python extractor records `self.get_ip(request)` by its bare name, so the
import strategy matched it to a function the file imports as `get_ip` and
the call never reached the class's own (or inherited) method. A bare-named
Python call written on `self` now skips import resolution; the method
strategies then find it. A plain `get_ip(request)` still binds to the import.

Across allauth, DRF, netbox and mealie this retargets 16 calls, all from an
imported helper to the class's own method; no edge is added or lost.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:42:23 +00:00
Colby Mchenry a5184ed5d4 fix(pascal): Delphi .inc include files are indexed as Pascal, not PHP (#2279) (#2289)
* fix(pascal): Delphi .inc include files are indexed as Pascal, not PHP (#2279)

`.inc` maps to PHP (Drupal), so a Delphi/Free Pascal include — a
`{$IFDEF}`/`{$DEFINE}` block or a declaration fragment pulled in with
`{$I defs.inc}` — was parsed as PHP (untagged text = inline HTML) and
contributed nothing.

detectLanguage now decides `.inc` by content: a PHP open tag (`<?php`,
`<?=`) anywhere keeps it PHP; otherwise a Pascal-only line shape (a
compiler directive, a `;`-closed routine header, `unit`/`uses`, a
const/var/type section, a begin/end; pair, Lazarus `{%MainUnit}`) makes
it Pascal; anything else keeps the PHP routing so C / asm / POV-Ray /
SourcePawn / Makefile includes are not handed to the Pascal grammar. A
leading BOM is skipped. An explicit codegraph.json `.inc` mapping wins.
The rule is per file, so a full index and a sync always agree.

The grammar preload set adds Pascal whenever an `.inc` is present (an
include-only tree otherwise had no Pascal parser), and the kernel-parity
script re-detects `.inc` like the indexer does.

Checked on 875 real `.inc` files: 0 of 436 non-Pascal ones (Drupal 7,
php-src, LLVM, FreeBSD mk, POV-Ray, SourceMod, edk2) flip; 433 of 439
Pascal ones (FPC, Lazarus, Castle, mORMot2, JCL) are detected — the rest
are statement-only or bare-literal fragments with nothing to extract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(changelog): Pascal include files (#2279)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:28:02 +00:00
Colby Mchenry e28ac71048 fix(sync): same-named symbols keep their own cross-file callers across a re-index (#2276) (#2288)
* fix(sync): same-named symbols keep their own cross-file callers across a re-index (#2276)

Re-storing a file re-attaches the edges other files had into it by moving
each edge to the re-indexed node that replaces its target. That pairing
keyed new nodes by (kind, name) with the last one winning, so in a file
defining a name twice — the same method on two classes, a method's
overloads — any edit, even a body-only one, moved every incoming caller
of those symbols onto one of them. A body-only edit leaves the sync's
definition delta empty, so nothing re-resolved them afterwards.

The re-store now reads the file's old node identities alongside the edge
snapshot and pairs old nodes with new ones by (kind, name), then
qualified name, then signature, then position within a same-sized group
of otherwise identical nodes. A target no tier can pair one-to-one is
resurrected as its original unresolved reference, so resolution rebinds
it instead of the store guessing.

The common in-memory re-store path also now deletes the old rows, stores
the new ones and re-attaches incoming edges in one transaction. Committed
separately, a failure between the steps left the file looking new or
already current, and other files' edges into it were lost until a full
re-index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(changelog): same-named symbols keep their callers across a sync (#2276)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:26:51 +00:00
Colby Mchenry 455175da67 fix(mcp): a projectPath in a nested repo the ancestor index leaves out isn't answered from it (#2110) (#2287)
* fix(mcp): a projectPath in a nested repo the ancestor index leaves out isn't answered from it (#2110)

An explicit projectPath resolves to the nearest .codegraph/ walking up,
and that walk crosses git boundaries. Inside an independent repository
nested under an indexed parent that excludes it (typically gitignored),
every call silently answered from the parent's code.

After resolving the index root, ToolHandler now asks whether the path
sits in a different git repository strictly below that root (git
toplevel + common dir, memoized per path and root) and, if so, whether
the index holds any file under it (one primary-key range probe per
call). None means the success-shaped "isn't indexed" guidance. Nested
repos the parent does index (submodules, gitlinks, embedded clones),
ordinary subdirectories, linked worktrees of the same repository (the
when git can't run, behavior is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(changelog): nested repositories the index leaves out (#2110)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:24:34 +00:00
Colby Mchenry 5271c89f08 fix(php): a class written with a namespace in its name resolves to that class (#2256) (#2286)
* fix(php): a class written through a namespace alias resolves to its class (#2256)

`use App\Fields as Field;` aliases a namespace, so `new Field\FirstName()`
names `App\Fields\FirstName`. Expand the first segment through the file's use
map and look the class up by its qualified name, before the pre-filter that
drops names without a `.` or `::`.

(cherry picked from commit 3917de431cbe8d8bbba32d9f4c739458c36e3fed)

* fix(php): resolve every qualified class name the way PHP reads it (#2256)

Extends the namespace-alias fix beyond `new`: extends, implements, static
calls (`Alias\X::make()`), names relative to the current namespace and fully
qualified `\Ns\X` now all resolve by their exact qualified name. A name
with no single project class is outside the project, so it no longer falls
through to a same-named guess; a static method the class only inherits is
left to the strategies that walk supertypes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 12c742a917ebd455840c148db1e37c895b9587ad)

* docs(changelog): one entry for the PHP qualified class names fix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: drakeo338 <paranoyouz@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:20:59 +00:00
Colby Mchenry fdc7754a72 fix(mcp): return status and stale refusals as text only (#2088) (#2284)
* fix(mcp): return status and stale refusals as text only (#2088)

Claude Code shows the model a tool result's structuredContent in place
of its content text, under every protocol version. codegraph_status and
explore's stale-index refusal both set structuredContent.freshness, so
the model saw a JSON object instead of the refusal, its retry guidance
or the status report. The text already carries every field, and nothing
in the codebase reads structuredContent, so both results drop it.

The tests now assert that the field is absent and that the text keeps
the refusal line and the stale file list.

(cherry picked from commit 18d65f8e10)

* fix(mcp): list every unverified file in the stale refusal (#2088)

(cherry picked from commit f1b0ec7f56)

* fix(mcp): keep the stale refusal's unchecked-file list bounded

The text-only refusal now names the first 20 files it could not verify and
counts the rest, as it did before; an impact answer over a hub symbol can
leave thousands unchecked, and every one of them would land in the agent's
context.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit c4513a66c9ae6bb10ede80d102d4122ed7f0508d)

* docs(changelog): one entry for the text-only results fix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Aaron Queen <bompus@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:16:48 +00:00
Colby Mchenry 637fb0fac8 fix(mcp): release an idle explicit project and its writer lock (#2087) (#2283)
* fix(mcp): release an idle explicit project and its writer lock (#2087)

A daemon that answered a `projectPath` query for another indexed project
opened it in-process and, with no owner there, took its writer lock. The
project cache only evicted over its LRU bound or on shutdown, so the lock
stayed held for the daemon's whole life: the project's own daemon could not
become its writer and `codegraph index` there was refused.

Release a cached explicit project once it has gone unused for 10 minutes
(CODEGRAPH_PROJECT_IDLE_TIMEOUT_MS; 0 never releases), through the same
trim path as LRU eviction, so an active call or a running catch-up still
defers it. The next call reopens the project and catches it up (#1835).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 092d49d3db)

* docs(changelog): credit the idle project release

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:15:24 +00:00
Colby Mchenry 49248e25eb fix(mcp): answer server/discover locally in the stdio proxy (#2084) (#2282)
* fix(mcp): answer server/discover locally in the stdio proxy (#2084)

Clients that probe `server/discover` before the legacy `initialize`
(Antigravity 2.5) wait for its answer. The proxy forwarded it to the shared
daemon, so no reply was written until the daemon connected: a client that
closed stdin first got nothing, and with the daemon unavailable the reply
came ~6s later as -32603 "daemon unavailable". Answer it in the proxy with
-32601 Method not found, which is what sends such a client on to
`initialize`. The direct and daemon sessions already answer unknown methods
with -32601; the new test pins that too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 77db6c659c)

* docs(changelog): credit the server/discover fix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:13:42 +00:00
Colby Mchenry 96ba880556 fix(prompt-hook): skip Claude Code <agent-message> subagent hand-backs (#2184) (#2281)
* fix(prompt-hook): skip Claude Code <agent-message> subagent hand-backs

Claude Code delivers a subagent's report to the parent session as a
UserPromptSubmit prompt wrapped in <agent-message from="…">…</agent-message>.
The prompt hook treated it as user input and ran a full codegraph_explore
on the whole report, which is slow on a multi-KB prose query (past the
30 s hook timeout in the report) and injects context unrelated to the
user's question.

Add isAgentMessage next to isTaskNotification (#1832) with the same rule:
only a prompt that is entirely the envelope is skipped, so a user question
that mentions the tag still goes through the gate.

Fixes #2184

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 240022db70)

* docs(changelog): credit the prompt-hook hand-back fix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:12:11 +00:00
Colby Mchenry 404e7827bc fix(windows): hide the git calls that flash console windows (#2094) (#2280)
* fix(windows): hide the git calls that flash console windows (#2094)

The two git calls added for exclude-standard scope parity (#1728),
`git config --get core.excludesFile` and
`git ls-files -o -i --exclude-standard --directory`, ran without
windowsHide. Inside the detached, console-less MCP daemon each one got a
fresh visible console, so a window flashed several times on daemon start
and again on every auto-sync. With Windows Terminal as the default
terminal each flash is a full Windows Terminal window. `git config
user.name` in the viewer's trails API had the same gap.

Add windowsHide: true to all three, and replace the per-file regex guards
with an AST guard over every child_process spawn in src/: options passed
through a variable or a function parameter are traced back to the object
literal that defines them, through every call site.

Supersedes #2095 (same fix, rebased on current main). Closes #2094,
closes #2096.

(cherry picked from commit dd2db41f1b)

* docs(changelog): credit the Windows console-window fix

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit cf93d497fd1b38fd9214945eeb55b6b0be9e2007)

---------

Co-authored-by: Suharaz <minesuhara@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 04:09:56 +00:00
Colby Mchenry ec738ec7a3 fix(viewer): a Steps picture with nothing past its anchor says why (#2274)
Steps from a helper that only computes — the most-depended-on symbol of
most libraries — drew one box and no explanation (179 of 304 projects in the
browser pass). The side panel now says what the walk looked for, that plain
calls fold into the lines, and links to the symbol's callers and callees.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 22:52:47 +00:00
Colby Mchenry 911fcf6033 fix(vapor): a closure route's calls are the route's (#2273)
A Vapor route whose handler is a trailing closure had no handler symbol and
linked to nothing (vapor's own repo: 76 of 80 routes bound to nothing in the
viewer browser pass). The closure is the handler: its body's calls, each once
with its receiver, are referenced from the route, as an Express inline
handler's are.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 22:52:43 +00:00
Colby Mchenry f416357b93 fix(cobol): a file ending inside the sequence area no longer hangs the parser (#2272)
* fix(cobol): a file ending inside the sequence area no longer hangs the parser

The vendored COBOL grammar's external scanner skips the fixed-format
sequence area (columns 1-6) with `while (get_column() <= 5) advance()`.
At end of input advance() is a no-op, so a file whose last line stops in
that area (`    .`, `X\n    .`, a sentence closed by a short `    .` line)
never reached column 7 and the scanner spun forever inside wasm. Indexing
hit the parse worker's hard timeout three times (~93 s) and stored the
file with zero symbols; the viewer's highlighter froze on the same text.

The loop now also stops at eof(). It is upstream code (present at
e99dbdc3), so the change is a standalone upstreamable fix; inputs that
parsed before are unaffected (412 NIST + ocesql test sources give
byte-identical trees with the old and new wasm, and the upstream corpus
keeps its single pre-existing failure).

Regenerates docs/grammars/tree-sitter-cobol.patch, rebuilds the wasm per
docs/grammars/tree-sitter-cobol.md, and adds an out-of-process regression
test under a hard deadline (a regression is an uninterruptible wasm loop).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(viewer): force the highlight deadline instead of relying on a grammar bug

The bounded-highlight test used the COBOL `    .` slice as its slice that
never finishes; the grammar fix makes it parse, so the deadline is now
forced through tokenizeBounded's deadline parameter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:47:52 +00:00
Colby Mchenry 104b8de3e6 fix(laravel): a string controller resolves without a Controller suffix (#2271)
Only `XController@action` was claimed and resolved, and the written
namespace was stripped, so akaunting's 'Common\\Uploads@inline' (and a
Route::resource with a string controller plus options) bound 304 of 313
routes to nothing. Any `Class@action` is claimed; the namespace path under
App\\Http\\Controllers is kept and picks between same-named controllers;
a resource reads its first argument and resolves its controller class in
the Laravel resolver (no `use` brings a string-named class into scope).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:40:38 +00:00
Colby Mchenry e12f5bbb92 fix(nuxt, astro): a file-routed page is bound to its component (#2267)
A Nuxt pages/x.vue or Astro src/pages/x.astro route linked to nothing, so
the viewer's Steps drew a page alone and the routes list never named what
serves it. Each page route now references its file's own component (never a
same-named one — every index.vue is a component named index), an Astro
endpoint its exported verb handlers, and the routing manifest accepts a
component as what serves a route, which also lists Vue Router screens.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:33:41 +00:00
Colby Mchenry 41cfc8356f fix(viewer): highlighting runs in a worker the server can stop (#2266)
The viewer's server classifies a code slice with the engine's tree-sitter
grammars on its one thread. The COBOL grammar's scanner loops forever on a
line like `    .`, which a cobolcraft Flow card's window ends with, so the
whole server froze — /api/stats included — and a parse inside WebAssembly
cannot be interrupted from JavaScript. Slices are now classified in a
worker that is terminated past a 2 s deadline; the slice is served plain
and the next one gets a fresh worker. Request-time parses also carry a
progress-callback budget.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:33:37 +00:00
Colby Mchenry c0d3285b55 fix(rails): only:/except: are read as %i[], %w(), a string or :only => (#2269)
Only a bracketed list (and the scoped reader's bare :sym) was read, so
maybe's `resources :family_exports, only: %i[new create index]` drew all
seven RESTful routes — four to actions the controller lacks, listed by the
viewer as routes bound to nothing. Both route readers now share one option
reader for every form Rails accepts.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:31:06 +00:00
Colby Mchenry c04cb5c629 fix(viewer): the Map opens on a picture, not a single box (#2270)
pickDefaultRoot ignored files loose in the repository root, so git's
top-level .c files made builtin/ the program's root. And a source folder
whose files all sit in one folder (Express lib/, R's R/, Erlang src/)
drew one box at any depth; pickDefaultView opens the whole repository
then, when it draws more.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:30:46 +00:00
Colby Mchenry d6a2bdb0d6 fix(sfc): a Vue/Svelte/Astro component owns its script (#2268)
The single-file-component extractors kept the delegated script's file node
and made the component contain it and every node, so the hierarchy ran
file-inside-component, members had two parents, and a file with no script
had no file node. And a per-instance script's top-level calls stayed on the
file, so a walk from the component found nothing. Now: one file node (the
whole file) holds the component; the component holds what the script holds
at top level, nested symbols keep their parent; <script setup>, a Svelte
instance script and Astro frontmatter give their top-level calls — a
top-level constant's initializer's included — to the component, while
imports and module-level scripts stay with the file. Svelte 5's
`<script module>` is a module script too.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:24:06 +00:00
Colby Mchenry c4babfce6a fix(js): a CommonJS require and a module path import the file they name (#2263)
* fix(js): a CommonJS require and a module path import the file they name

A `require('./application')` was only a call, so a CommonJS file depended
on nothing at file level: Express's lib/express.js showed no imports and
impact missed the files it loads. Local require specifiers are now read
after extraction (both the wasm extractor and the kernel, including its
deferred-decode transport) as `imports` refs from the file, and a JS/TS
module path resolves to its file the way the runtime finds it —
extensions, index files, aliases — which also lands an extensionless
`import './polyfills'` on its file instead of its own import node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(js): read require imports inside each extractor, so kernel parity holds

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:37:37 +00:00
Colby Mchenry 95f6f0f4a5 fix(viewer): a directed Flow looks up both ends by their exact names (#2262)
The Flow strip's from/to were run through explore's free-text token filter,
which drops an Objective-C selector (`initWithFrame:`), a Ruby predicate
(`valid?`) and any name under three letters (`ok`) — then reported the
OTHER end as naming nothing in the index. Directed mode now takes the two
names as written; explore's named mode is unchanged.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:32:07 +00:00
Colby Mchenry 81e08b76ed fix(viewer): pages that went blank — repeated ids, and Steps on a function full of checks (#2264)
* fix(viewer): a repeated id no longer blanks Entry points or a component's Symbol view

The viewer keys its lists by id and a repeat stops the page drawing. The
routes list was a row per (route, edge), so an inline handler came back once
per call in its body; it is now one row per route — its bound handler, or
the route itself as an inline handler. A Vue/Svelte/Astro component's
members listed its script's symbols twice, plus the component and its file;
each member is now listed once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(viewer): Steps reads a function full of checks in one pass

The in-order reading kept every way forward through an `if` with no
`else` twice — under its condition and without — so eighty checks that
draw nothing (jsoup's `parse`) made 2^80 ways and the page died on a
stack overflow. Ways waiting at the same place are merged, keeping the
conditions they all share.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:23:31 +00:00
Colby Mchenry d45edca3fd fix(express): a function-expression handler is the route's body, like an arrow (#2261)
An Express handler written inline as `function (req, res) {…}` — the form
Express's own examples use — fell to the named-handler branch, so the route
linked to nothing and Steps drew a lone box for `POST /login`. The handler
is now the registration's LAST argument, inline as an arrow or a function
expression, bare or inside a wrapper call, past a trailing comma; an inline
middleware before a named handler no longer stands in for it.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:11:26 +00:00
Colby Mchenry 34ede4de88 fix(python): a module member follows the package's re-exports too (#2248)
resolvePythonModuleMember (`mod.member` after `import mod` / `from pkg import
mod`) looks the member up with pythonModuleSymbol, so a package's
__init__.py re-exports lead to the definition.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 04:34:57 +00:00
Colby Mchenry 6d8802cef8 fix(python): an imported name follows the package's re-exports to its definition (#2247)
pythonModuleSymbol: a name imported from a module is its top-level
definition, or one the module re-exports by name (`from .tokens import
Token`) or through a star import (`from .users import *`, read from source),
three packages deep, memoized.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 04:29:55 +00:00
Colby Mchenry c38aa9c973 fix(nestjs): the provider convention stays in the reference's feature (#2246)
In a TS/JS module the *Service/*Controller convention picks the file's own
class or the convention file beside it (users.controller.ts → users.service.ts),
never a same-named class elsewhere preferred for its file name; anything
farther is the import resolver's or name matching's.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 04:15:09 +00:00
Colby Mchenry b2afa75f08 fix(astro): the component name heuristic applies to .astro files only (#2245)
Astro components are used in Astro markup; a .ts / .d.ts type name sharing a
component's name (Playwright's Page, a declaration file's Image) is no
component.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 04:05:02 +00:00
Colby Mchenry 000c986276 fix(express): a middleware candidate is a declaration, never an import node (#2244)
#2243 put the calling file's candidates first, which let resolveMiddleware
pick the file's own `import cors from 'cors'` node; candidates are now
functions, methods, values and classes only.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 03:56:54 +00:00
Colby Mchenry 3343646446 fix(express): name patterns pick only the calling file's own declaration (#2243)
The middleware/controller/service heuristics took the first same-named node
anywhere; a JS/TS module reaches another file's only through an import or
require (the import resolver's), so they now keep a same-file pick only.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 03:52:28 +00:00
Colby Mchenry 8ca4433502 fix(objc,swift): a class conforming to its namesake protocol implements the protocol (#2242)
The SwiftUI/UIKit/Vapor resolvers apply to Swift refs only; the shared name
pick never returns the declaring type for an inheritance ref; and the
supertype re-choice prefers the declaring file, then a protocol/interface for
`implements`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 03:45:49 +00:00
Colby Mchenry a5da8daf6f fix(solidity): a call reaches the overload its argument count fits (#2241)
Solidity joins OVERLOADING_LANGUAGES, so retargetSelfOverload moves a call
whose argument count the settled overload cannot take to the one sibling
that can.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 03:37:32 +00:00
Colby Mchenry f976a050a0 fix(react): hook and context heuristics pick only the file's own in JS/TS (#2240)
A JS/TS module reaches another file's hook or context only through an import
(already the import resolver's), so resolveHook/resolveContext pick from the
reference's own file alone there; an optional call `f?.(…)` is a bare call.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 03:31:22 +00:00
Colby Mchenry a925fa0920 fix(r): a call never reaches a data binding that shadows a base function (#2239)
R looks a call up among functions only; a calls ref named after a base R
function (c, list, df, …) is refused a variable/constant target that is not
bound to a function literal.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 03:10:36 +00:00
Colby Mchenry 31c5153d62 fix(swift): an overloaded call reaches the overload its argument labels spell (#2238)
retargetSelfOverload for Swift matches the call's argument labels against
each same-owner overload's external parameter labels (defaulted and variadic
ones optional), instead of the argument count alone.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 03:02:05 +00:00
Colby Mchenry 8651adbcd9 fix(dart): an unnamed extension is not its on-type and applies only in its library (#2237)
The extractor names `extension on X` after X; such a node is never a target,
and its members are out of reach from other files (Dart scopes unnamed
extensions to their library) — before ranking in Strategy 3 and as a veto.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 02:56:43 +00:00
Colby Mchenry ef62f0236f fix(java): a bare type name is a type in reach by package, import or nesting (#2236)
isJavaTypeVisible (before ranking and as a veto): a top-level type from its
package or a single-type/on-demand import; a nested type from inside its
owner, a subtype (anonymous classes by their $anon supertype), an import, or
written through its owner; constructors follow their type; enum constants
only in their enum, a case label, a static import or through the enum.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 02:49:34 +00:00