Commit Graph
2132 Commits
Author SHA1 Message Date
safishamsiandClaude Opus 4.8 5c7b84792f release: 0.9.77
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v0.9.77
2026-10-05 20:13:41 +01:00
brunovima83 031c58ee18 fix(skill): run Step B3 when every semantic file is cached
The split-host runbook told the agent to skip to Part C when every doc,
paper and image hit the semantic cache. Part C reads
.graphify_semantic.json unconditionally and only the Step B3 merge writes
it, so a second run on an unchanged mixed corpus failed with
FileNotFoundError; writing an empty file instead dropped every cached node.

The all-cached case now skips B1/B2 but still runs B3. Step B0 also clears
.graphify_chunk_*.json before dispatch: B3 merges every chunk on disk, and a
leftover from an interrupted run would otherwise be merged as fresh.

The aider and devin monoliths keep the old sentence; they are pinned to the
v8 baseline by --monolith-roundtrip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit bab1bb2775)
2026-10-05 20:12:34 +01:00
Mr-Neutr0n 2ce4a20764 Fix #3690: benchmarks: code-intelligence result inaccessible; BENCHMARK
Signed-off-by: Mr-Neutr0n <64578610+Mr-Neutr0n@users.noreply.github.com>
(cherry picked from commit c7bbf6c834)
2026-10-05 20:12:26 +01:00
akshit af83bc00aa test: cover untouched good-first regressions
(cherry picked from commit cd49739c92)
2026-10-05 20:12:06 +01:00
Huanyi Xie 3f712fe309 fix(build): honor disabled same-file semantic deduplication
Pass dedup=False into graph construction so repeated labels do not collapse distinct non-AST identities. Preserve existing AST and document-file twin reconciliation. Fixes #4019.

Assisted-by: OpenAI Codex (GPT-6)
(cherry picked from commit 1f3805f16e)
2026-10-05 20:11:30 +01:00
Huanyi Xie 28675a191c fix(rust): omit anonymous constants from graph symbol identity
Assisted-by: OpenAI Codex (GPT-6)
(cherry picked from commit 99159f362c)
2026-10-05 20:11:30 +01:00
Huanyi Xie c3d54bc52b fix(extract): keep cross-drive diagnostic paths from aborting extraction
Assisted-by: OpenAI Codex (GPT-6)
(cherry picked from commit 8a98287926)
2026-10-05 20:11:30 +01:00
rajatnagda45 76576865b6 fix(powershell): record method calls ($this.M(), [Type]::M())
The call walker only visited `command` nodes, so every method invocation
was dropped from the call graph. A method call parses as an
invokation_expression (callee in the member_name child, args in
argument_list); a bare property read ($this.Name) is a separate
member_access node and correctly produces no call.

Handle invokation_expression and resolve the member name against a
method-only label map so a member call binds to a method, never to a free
function that merely shares the name (fail-closed on unknown receivers).

Fixes #3992

(cherry picked from commit 1e6a9029e4)
2026-10-05 20:11:30 +01:00
raditha dissanayake 5eeb037929 fix(export): preserve stored edge direction when reloading graph.json (#4066)
graph.json is written "directed": false and carries direction in arc order
(#563), or in _src/_tgt markers on legacy files (#2309). A plain undirected
node_link_graph load re-orders endpoints by node-list position, so every
link whose target precedes its source in the node list came back reversed
(79% of links on graphify's own graph).

query, path/explain, affected, merge-graphs and the MCP server already
restore direction. The remaining reloaders did not:

- export html / neo4j / falkordb (cypher.txt and --push) / obsidian canvas
- graph.html re-rendered by update, watch and the git hooks
- the git merge driver, which wrote the reversal into the committed
  graph.json, even when merging three identical copies

Add paths.restore_arc_direction, the inline idiom query and merge-graphs
already use, and apply it in load_node_link_graph and the export loader.
to_cypher, to_canvas and push_to_neo4j/falkordb now read _src/_tgt as
to_html already does. The merge driver writes direction back into arc
order before saving, as to_json does, so the committed file keeps the
post-#563 convention.

global add has the same bug and is fixed separately.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 5a461c99d7)
2026-10-05 19:40:13 +01:00
harshaygadekar 79b7a8450f fix(detect): scope incremental manifest anchoring to prevent false deletions (#3785)
(cherry picked from commit 1c161995bf)
2026-10-05 19:40:13 +01:00
Sourya Prabaharan 674338b924 fix(extract): terminate trailing Astro script comments
Preserve subsequent script blocks and byte offsets when a script ends in a line comment. Fixes #4072.

Co-authored-by: Codex <noreply@openai.com>
(cherry picked from commit fc48f659c4)
2026-10-05 19:40:12 +01:00
Huanyi Xie b182659519 test(cpp): distinguish union methods from data fields
Assisted-by: OpenAI Codex (GPT-6)
(cherry picked from commit 0a7c77cb63)
2026-10-05 19:40:12 +01:00
Huanyi Xie 5ac6a3c934 test(extract): preserve cross-language JVM inheritance
Assisted-by: OpenAI Codex (GPT-6)
(cherry picked from commit 1575f867f2)
2026-10-05 19:40:12 +01:00
Huanyi Xie 9a1d8c06ca test(kotlin): isolate annotation class literal boundaries
Assisted-by: OpenAI Codex (GPT-6)
(cherry picked from commit 42dc0a7fee)
2026-10-05 19:40:12 +01:00
Jarvis-J-Jacob d07c91cba9 test(csharp): assert bare this?.M() null-conditional call resolves
#3976 made recv?.M() resolve through the receiver-typed path but only
tested field receivers. Add a test that `this?.Save()` inside a class
resolves to the enclosing class's Save() like `this.Save()`, and not to
an unrelated class's Save().

Fixes #4077

(cherry picked from commit 6ce8348026)
2026-10-05 19:40:12 +01:00
harshaygadekar 5c5ce7fb53 fix(js): extract methods on exported objects to resolve CommonJS/ESM calls (#3778)
(cherry picked from commit 65f2da519f)
2026-10-05 19:40:12 +01:00
Huanyi Xie d2b5e19682 fix(php): resolve builtin-named methods on known self receivers
Assisted-by: OpenAI Codex (GPT-6)
(cherry picked from commit aca5651bc8)
2026-10-05 19:40:12 +01:00
Mahaboob pasha 1f078a3ee9 fix(extract): don't emit L1 for zero-byte files
A 0-byte file has no line 1, so the file node's source_location=L1 was an
anchor that can never resolve. Leave it None (how other location-less file
nodes already look) in the shared tree-sitter path, and keep the node: an
empty __init__.py is still a module other files import.

Closes #4041

Co-Authored-By: Grok Bot <noreply@x.ai>
(cherry picked from commit 29597adec8)
2026-10-05 19:40:11 +01:00
Mahaboob pasha ee292729ae feat(scala): extract class-level context bounds
`class Foo[A: Ordering]` (and the same on case classes, traits and enums)
now emits a `references` edge with the `type_bound` context from the type
to each bound, reusing the method-level path from #2046.

Closes #4080

Co-Authored-By: Grok Bot <noreply@x.ai>
(cherry picked from commit d1257efb7d)
2026-10-05 19:40:11 +01:00
CLOCKZW 438a050e08 test(elixir): assert defguardp private guards are extracted
#4027 taught the Elixir extractor defmacro, defmacrop, defguard and
defguardp, but the regression test only exercised the first three. Add a
defguardp clause to the fixture and assert its node is extracted, so
dropping defguardp from the extractor's keyword list fails this test.

Closes #4076

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 345b66b01f)
2026-10-05 19:40:04 +01:00
Jarvis-J-Jacob 9f6c0b9721 test(zig): assert a tagged-union nested-struct payload's fields are not minted
#4050 emits a node + case_of edge per `union(enum)` variant but
deliberately does not recurse into a variant's nested-struct payload.
Extend the tagged-union test to pin that: `rectangle: struct { w, h }`
is minted as a variant, while its `w`/`h` fields are not, and
`rectangle` owns no case_of edges of its own.

Fixes #4074

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 994bb2e534)
2026-10-05 19:40:04 +01:00
MalikHaroonKhokhar eb283ca58b test(pascal): cover the valued enumerated form (#4071)
Enum extraction (#4056) is only tested with the plain form,
`TColor = (clRed, clGreen, clBlue)`. The valued form nests an explicit
ordinal under declEnumValue -> defaultValue, beside the value's identifier,
so a change to how the value's name is read could leak the literal into the
label, or emit it as a node, without any test noticing.

Add a test for `TColor = (clRed = 1, clGreen = 2)` asserting the type node,
a `case_of` edge to each bare value name and to nothing else, and that
neither literal becomes a node.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 1b05d1593c)
2026-10-05 19:40:04 +01:00
rajatnagda45 e4c48bf97e fix(objc): extract C-style enum declarations
Objective-C is an object-oriented extractor that already emits @interface,
@implementation and @protocol type nodes, but plain `enum` and
`typedef enum` definitions were dropped entirely: both the enum type and all
of its enumerators were invisible in the graph.

Handle `enum_specifier` (and the `typedef enum { ... } Name;` form, where the
name is the typedef alias), emitting a type node plus a node and `case_of` edge
per enumerator — the same shape every other language with enums uses (Java
#1719, C++ #3939, Swift). A nameless enum and a bodyless `enum X y;` reference
are skipped so no phantom node is minted.

NS_ENUM/NS_OPTIONS is deliberately out of scope: it is a macro call that
tree-sitter-objc parses into an ERROR subtree, so there is no clean AST to
read. Documented in the test.

Add regression tests for the plain, typedef, and skip cases.

(cherry picked from commit 2d30c413d3)
2026-10-05 19:40:03 +01:00
rajatnagda45 e444d5ac37 fix(sql): link a trigger to the function it executes
A trigger exists to run a routine, but the create_trigger branch only linked
the trigger to its ON table and ignored the EXECUTE FUNCTION/PROCEDURE clause
entirely. The routine a trigger fires — its whole reason to exist — was never
represented in the graph.

Register function/procedure node ids in a routine_nids map (mirroring
table_nids) and, in create_trigger, read the object_reference after EXECUTE and
emit an `executes` edge to that routine. Resolution is name-based against
routines defined in the same file (a trigger's function is declared before it);
when the routine is not in this file the edge is skipped rather than guessing a
cross-file target or minting a bare-name stub that could never rewire onto a
`name()` function node.

Add regression tests for the resolved case and the fail-closed case.

(cherry picked from commit ea39929459)
2026-10-05 19:40:03 +01:00
rajatnagda45 282e2bbc56 fix(powershell): link enum members with case_of instead of contains
A PowerShell enum member is a discriminant case, not a declared field, so it
should hang off its enum with a case_of edge like every other language that
has enums (Java #1719, C#, Swift, Rust, VB.NET). PowerShell was routing enum
members through the same contains path used for class members.

The relation is not cosmetic: case_of targets are excluded from constructor
binding, so an enum member named like a type could previously be mistaken for
one.

Update the existing enum test to expect case_of and add a focused regression
test asserting enum members get case_of (and not contains) while the file
still contains the enum type via contains.

(cherry picked from commit 011dda9b0f)
2026-10-05 19:40:03 +01:00
rajatnagda45 4f0eb679bf fix(solidity): link enum values with case_of instead of contains
A Solidity enum value is a discriminant case, not a declared member, so it
should hang off its enum with a case_of edge like every other language that
has enums (Java #1719, C#, Swift, Rust, VB.NET). Solidity was the lone
remaining outlier, routing enum values through the same contains path used
for struct fields.

The relation is not cosmetic: case_of targets are excluded from constructor
binding, so an enum value named like a type could previously be mistaken for
one. Struct fields keep contains, since a field is a real declaration.

Add a regression test asserting enum values get case_of (and not contains)
while a struct field keeps contains.

(cherry picked from commit fdd99502d7)
2026-10-05 19:40:03 +01:00
safishamsiandClaude Opus 4.8 b57cf9108e docs: add GraphGuild community-program banner
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-05 17:46:04 +01:00
safishamsiandClaude Opus 4.8 35adf432b9 docs(readme): shrink the Translations section to a one-liner
The top-of-README language switcher already lists every language; keep
the bottom section as a short pointer to docs/translations/ and the
PR-to-contribute call, instead of duplicating the full table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-04 22:28:19 +01:00
safishamsiandClaude Opus 4.8 61f610d550 docs(readme): add a Translations section
List all 32 README languages in a dedicated Translations section (a
#translations anchor), like other large OSS READMEs, with a pointer to
docs/translations/ for improving or adding one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-04 22:19:38 +01:00
safishamsiandClaude Opus 4.8 0010e25d0d release: 0.9.76
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v0.9.76
2026-10-04 21:02:57 +01:00
Syed Fahad c37be6169c chore(packaging): point the PyPI homepage at graphify.com
The PyPI page listed the GitHub repo as both Homepage and Repository, so
nothing on PyPI linked to the project's website or docs. Homepage is now
graphify.com, docs.graphify.com is listed as Documentation, and Repository
still points at GitHub.

(cherry picked from commit 25a73bcaa6)
2026-10-04 21:02:36 +01:00
safishamsiandClaude Opus 4.8 76d3b88aee docs: correct two stale resolver comments
Follow-ups on #3975 and #4043:
- the PHP language-construct set cited _GO_PREDECLARED_FUNCS, which does
  not exist; the real analog is _LANGUAGE_BUILTIN_GLOBALS.
- _EXTERNAL_STUB_RELATIONS said `calls` to an external target is always
  suppressed (#3156); after #4043 an imported module does receive a
  `calls` edge, so clarify the actual invariant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-04 20:41:11 +01:00
Alex Tumanov 140cb590e7 test(extract): preserve isolation with external module calls
Require exact coarse calls to unresolved absolute imports while retaining
package and cross-directory local target isolation.

AI-Assisted-By: OpenAI Codex
(cherry picked from commit e1eeede9b5)
2026-10-04 20:40:34 +01:00
Alex Tumanov 33edd89b43 fix(extract): preserve Python import bindings across sibling cases
Use existing plain-import provenance to distinguish separate and same-line from-imports. Reject type aliases and dynamic namespace references, and protect changed and unchanged external callers through incremental CLI extraction.

Fixes #3793

AI-Assisted-By: OpenAI Codex
(cherry picked from commit 5e240c8bd3)
2026-10-04 20:40:34 +01:00
Alex Tumanov 6868fff846 fix(extract): track calls to external Python modules
AI-Assisted-By: OpenAI Codex
(cherry picked from commit 3464399d4f)
2026-10-04 20:40:34 +01:00
berce ea1f158545 fix(path): resolve path::symbol and node-id endpoints before scoring (#3913)
`graphify path` and the MCP `shortest_path` tool picked endpoints by token
scoring only, so the forms `explain` already honours were misread:

- a bare label shared by symbols in several files was routed to one of them
  silently instead of being refused with the candidate ids;
- `src/b.ts::.nonce()` scored the path half and resolved to the file node;
- a full node id tokenized to its containing class.

Both entry points now share `_resolve_path_endpoint`: an exact
`_find_node` hit (path::symbol, node id, exact label or source path) is used
as-is and refused with the candidate list when it spans several files; only
queries without an exact hit fall through to `_score_nodes`.

Two same-named symbols in one file are refused as well, listing their
locations and ids, since `path::symbol` cannot tell them apart. A plain
file path still resolves to the file node. The ambiguity hint now suggests
`<path>::<label>` with the node's own label instead of echoing the query,
and `explain` prints the same shared message.

(cherry picked from commit c2d558aff7)
2026-10-04 20:40:34 +01:00
Agnik47 aa448fbb71 fix(extract): end a Svelte script block's trailing comment and report read errors
Review follow-ups on #3928:

- A `//` comment closing one `<script>` block swallowed a second block on
  the same line, since masking leaves them on one line. Terminate each
  block with U+2028 then `;`: the line terminator ends the comment and
  the `;` ends a statement that had none. Line numbers and byte offsets
  are unchanged.
- An unreadable file returns the `error` key again instead of an empty
  result, matching the behavior before the masking change.

(cherry picked from commit 5de47e3df3)
2026-10-04 20:40:34 +01:00
Agnik47 f9b42e8d23 fix(extract): parse only Svelte script blocks in the AST pass
extract_svelte fed the whole .svelte file to the JS grammar. The template
is not JS, so every component reported a syntax error at line 1 and no
symbol declared inside <script> was ever reached — only imports survived,
via the regex rescue pass.

Blank everything outside the <script> bodies (keeping newlines so
locations still match) and parse with the grammar the first block's lang
implies: js/jsx -> JS, ts or unset -> TS, a superset of JS and Svelte's
own default. <script module> and <script context="module"> are parsed
alongside the instance block. Scripts with a non-JS type
(application/ld+json, ...) are blanked too, and a script region is
terminated in place of the following `<` so two blocks on one line do not
run together. The existing regex import rescue is unchanged; an import
both passes resolve yields one edge after build.dedupe_edges, as on the
Astro path.

The masker mirrors _astro_mask_non_script and shares the script-tag and
non-JS-type patterns with it instead of duplicating them.

Fixes #3928. Covers the Svelte half of #3942 (markup is blanked, so a
template {#if} no longer mints a spurious if() node).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit b64806924e)
2026-10-04 20:40:34 +01:00
Cintu07 8629f02ff0 fix(php): stop language constructs binding to same-named methods (#3830)
empty(), isset(), eval() and die() parse as an ordinary
function_call_expression, so the call pass resolved them by bare name.
A reserved word has been a legal method name since PHP 7, so a class
that declares empty() collected every empty($x) in the corpus:
EXTRACTED from its sibling methods, INFERRED from every other file
through the case-insensitive fold.

Drop the callee for these constructs in the PHP branch, before the
in-file lookup and before raw_calls, the same way _GO_PREDECLARED_FUNCS
handles Go builtins. $bag->empty() is a member call and still resolves.

(cherry picked from commit 94574eb239)
2026-10-04 20:40:34 +01:00
nothariharan 762cfd33ad fix(hooks): refuse a core.hooksPath that leaves the repository
hook install followed git's hooks path even when core.hooksPath resolved
outside the checkout, then created that directory and wrote post-commit
there. The bytes are Graphify's own hook, not repository-chosen code, but
the write still escapes the repo. Keep in-repo paths such as .husky, and
git's own hooks directory (including a linked worktree's shared .git/hooks).
Anything else falls back to that default.

Fixes #3869

Co-Authored-By: Grok 4.7 <noreply@x.ai>
(cherry picked from commit ee35087aea)
2026-10-04 20:40:34 +01:00
azizur100389 bb20ef7234 fix(analyze): diversify suggested questions across signal types
Round-robin the existing question categories before truncating the result. Preserve within-category order, existing small-limit priority, candidate schema, and no-signal behavior. Fixes #3849.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
(cherry picked from commit 560b88d86f)
2026-10-04 20:40:34 +01:00
Deepanshu PalandClaude Opus 4.8 b8fcd29cb1 fix: snap cross-repo resolver confidence scores to the INFERRED rubric (#4045)
Snap the off-rubric INFERRED confidence scores emitted by the cross-repo
call/type resolvers and interface dispatch (0.8 and 0.9) to the nearest
canonical rubric tier (0.85), so every INFERRED edge carries one of the
documented discrete scores. Label-only change: no edge flips
EXTRACTED<->INFERRED and no edge is produced or dropped. Replaces the
substring-matching guard test with an AST-based one that scans every
module for off-rubric scores.

Squashed from #4045 (authorship preserved).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-04 20:23:44 +01:00
SrijanSriv 7e7de7d08f fix(dedup): keep unstamped document nodes apart across files
The exact pass joined equal labels without calling
_crossfile_fileanchored_blocked, so repeated headings collapsed
across source files. The fuzzy pass already had that block.

Fixes #3094

(cherry picked from commit 6a7409c06d)
2026-10-04 20:23:14 +01:00
Mahaboob pasha 7e8ad53e03 fix(detect): also skip graphify's single-file installs
The skill-folder rule from the previous commit left the files graphify
writes whole into a project still indexed: the always-on rules, steering
and workflow files (.agents/rules/graphify.md, .agents/workflows/graphify.md,
.cursor/rules/graphify.mdc, .kiro/steering/graphify.md,
.windsurf/rules/graphify.md) and the opencode/kilo hook plugins
(.opencode/plugins/graphify.js, .kilo/plugins/graphify.js). With every
platform installed they still added 12 nodes on top of the user's code.

List them in detect.py as a hidden holder dir plus the exact relative
path, the same paths install.py writes, and never match a bare
graphify.md/graphify.js name. detect(), ignored_predicate() and
collect_files() all check the same helper.

Files graphify only adds a section or entry to (AGENTS.md, CLAUDE.md,
.claude/CLAUDE.md, GEMINI.md, CODEBUDDY.md, .github/copilot-instructions.md
and the merged settings/hooks/plugin JSON configs) are still left alone.

The new test runs every project install in install.py plus the kilo,
codebuddy and vscode installers, so a new platform that writes a new file
fails it.

Refs #4057

Co-Authored-By: Grok Bot <noreply@x.ai>
(cherry picked from commit 102f4bca1e)
2026-10-04 20:23:14 +01:00
Mahaboob pasha c75bc16d2a fix(detect): skip graphify's own installed skill folder when scanning
`graphify install --project` copies graphify's SKILL.md and its
references/ bundle into the project (.claude/skills/graphify/,
.agents/skills/graphify/, ...). detect() treated those files as project
documents, so a small repo's graph was mostly graphify's own docs: in the
#4057 repro, 66 of 69 nodes came from the installed skill and the
always-on files, and only 3 from the user's code.

Prune the folder in _is_noise_dir, next to the .claude/worktrees rule, by
its full path shape as install.py writes it: <hidden dir>/skills/graphify/,
plus .pi/agent/skills/graphify/, .config/kilo/skills/graphify/ and
.aider/graphify/. The bare names "skills" and "graphify" are not matched on
their own (#2479), so graphify's own source tree (graphify/skills/<host>/),
a top-level skills/graphify/ and the user's other skills stay indexed.
Because the rule lives in _is_noise_dir, detect(), ignored_predicate() and
collect_files() all agree on it.

AGENTS.md, CLAUDE.md and .claude/CLAUDE.md are left as they are; those are
the user's files and how to treat graphify's section in them is still an
open question on the issue.

Fixes #4057

Co-Authored-By: Grok Bot <noreply@x.ai>
(cherry picked from commit 0d7087ea5c)
2026-10-04 20:23:14 +01:00
SrijanSriv ac6ab9f2bf fix(extract): keep an unresolved base off a class in another language
The unique-stub rewire copied a same-label class onto every edge, so a
Python base could inherit a TypeScript class. Refuse that write when the
language families differ. A same-language match still rewires.

Fixes #2207

(cherry picked from commit 48cdc8f484)
2026-10-04 20:23:14 +01:00
Faisal-Fayaz 856649270f fix(extract): stop walking JSON Schema files as config manifests (#2255)
`_is_config_json()` decides whether a `.json` file is worth AST-walking. It
matches by filename first, then falls back to a root-key probe. `$schema` was
in that probe's key set -- correctly, since configs legitimately carry it --
but it is also the *defining marker* of a JSON Schema, so every schema
document satisfied the probe and got walked in full. That re-opened the
keyword-node explosion #1224 closed for data JSON: one 160 KB contract
contributed 362 nodes labelled with bare schema keywords (`description` x113,
`type` x83, `$ref` x53, ...) plus ~12 schema-only communities, polluting
clustering, god-node analysis and GRAPH_REPORT.md.

Two changes, both ahead of the existing probe:

- Drop `$ref` from the probe keys. A root-level `$ref` is a schema construct
  and never a config signal.
- Return False when the root object carries `$schema` *plus* a
  schema-definition marker (`$defs`, `definitions`, or `$id`). This is what
  separates "this file IS a schema" from "this config POINTS AT a schema":
  the latter points `$schema` at its own tool's schema (biomejs.dev,
  docs.renovatebot.com) and never carries these markers.

The blast radius is smaller than it looks. The filename branches run first, so
biome.json / renovate.json / package.json / tsconfig.json never depended on the
probe at all; only arbitrarily-named files did. I confirmed this against a
control matrix before and after -- every config shape keeps byte-identical node
counts.

The root keys are now collected once into a set so the schema check and the
config probe agree on the same read of the file, rather than walking the root
twice.

Documented boundary, pinned by a test: a hand-written schema carrying only
`$schema` + `properties` (no `$defs`/`definitions`/`$id`) is still walked.
Closing that gap needs a keyword-density heuristic, which would risk skipping a
real config whose keys overlap schema vocabulary -- the worse error, since it
drops structure silently. Left for a deliberate change rather than guessed at.

Verified:
- uv run pytest tests/test_json_schema_config.py -q    (14 passed; 5 fail pre-fix)
- uv run pytest tests/ -q -> 28 failed, 6262 passed, 101 skipped
- baseline on a clean v0.9.75 checkout: 28 failed, 6248 passed, 101 skipped
  The 28 failures are byte-identical between the two (missing tree-sitter
  grammars for erlang/R/solidity/vbnet, plus ollama retry tests) and are diffed
  test-id-by-test-id, not compared by count. Passing delta is exactly +14.
- uv run ruff check . -> clean
- uv run pyright -> 636 errors, identical to the clean v0.9.75 baseline

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit f45ea17288)
2026-10-04 20:23:14 +01:00
Ayushraj06-bit 48de61551a fix(elixir): scope import/use to the declaring module, not the file
The unqualified-call scope added for #4001 collected every `import` and
`use` in a file into one list, so an import in one module leaked into a
sibling module defined in the same file: `MyApp.Sibling.go/1` calling
`fmt(x)` still bound to `MyApp.Helpers.fmt/1` because `MyApp.Importer`
imported it. Elixir scopes `import`/`use` to the module body it appears
in and to the modules nested in it.

Record targets per enclosing module, with the file's top level as its
own scope, and build each call's scope from its own module, the modules
enclosing it, and the top level. Each raw call now gets its own list
rather than sharing one mutable list with every other call in the file.
A module nested in a same-named module shares its node id, so the walk
up the enclosing chain stops at a module it has already visited.

Follow-up to #4015. Refs #4001

(cherry picked from commit e508142dac)
2026-10-04 20:23:14 +01:00
rajatnagda45 b46263123a fix(pascal): extract enumerated types and their values
(cherry picked from commit 8cf55d37be)
2026-10-04 20:23:14 +01:00
rajatnagda45 67a96aa08f fix(vbnet): link enum members with case_of instead of contains
(cherry picked from commit 6ee9624c22)
2026-10-04 20:23:14 +01:00