1162 Commits
Author SHA1 Message Date
rajatnagda45 aa2584c455 fix(r): resolve R6 self$ and private$ intra-class method calls
An R6 method reaches a sibling only through self$method() or private$method(),
never as a bare name, but walk_calls only handled a bare identifier callee. So
every intra-class call inside an R6 class was dropped, leaving methods that
clearly call each other disconnected in the graph.

Handle an extract_operator callee whose receiver is self or private: resolve
the method against the enclosing class scope, which is already reachable from
the caller via scope_parent. super$ is deliberately excluded — it dispatches to
a parent class this single-file pass cannot see, so a local binding would be
wrong.

Added a regression test covering both self$ and private$ calls.

(cherry picked from commit 4e00eaf105)
2026-09-28 09:14:38 +01:00
rajatnagda45 a4c6323910 fix(r): recognise namespace-qualified class constructors (R6::R6Class)
R6::R6Class(...) is the idiomatic, library()-free way to define an R6 class,
but call_parts returns the qualified text 'R6::R6Class', which never matched
_CLASS_CONSTRUCTORS. The binding therefore fell through to a plain variable
node and the entire class body — every method — was dropped. The same applied
to methods::setClass / methods::setRefClass in the statement path.

Strip the namespace qualifier before the constructor check in both the binding
path and process_call_declaration, so a qualified constructor is treated
exactly like its bare form. Unqualified declarations are unaffected.

(cherry picked from commit 513bea43c2)
2026-09-28 09:13:29 +01:00
abhirupone 57a263ce8f fix(markdown): respect ignore rules when building wikilink index (#3822)
(cherry picked from commit 48a8da896b)
2026-09-28 09:13:29 +01:00
rajatnagda45 4536c5cdc0 fix(groovy): extract enum declarations and their constants
enum_declaration was missing from the Groovy config's class_types, so a Groovy
enum and every constant it declares were dropped from the graph — a consumer
could not see which value a branch selects. tree-sitter-groovy exposes the same
enum_constant shape (a name field, optional class_body) that Java uses, so the
enum type now joins class_types and the existing Java enum-constant handler is
reused to emit a node per member with a case_of edge.

Added a regression test asserting the enum type and its constants are present,
attached to the enum rather than the file.

(cherry picked from commit 2c386de21a)
2026-09-28 09:13:29 +01:00
rajatnagda45 d7e463e476 fix(sql): extract triggers and link them to their table
Two defects left CREATE TRIGGER under-extracted:

- The create_trigger AST branch read the subject table off keyword_for, but the
  table follows ON ('... AFTER INSERT ON users'); FOR EACH ROW carries no table.
  So even a cleanly-parsed trigger got a node with no link to the table it fires
  on. Read the table after keyword_on instead.

- A trigger with a procedural body ('FOR EACH ROW BEGIN ... END') has no grammar
  production, so the statement lands in an ERROR node and only the whole-file
  routine-recovery scan can save it — but that scan's pattern matched only
  FUNCTION/PROCEDURE, so the trigger and its table were dropped entirely. Add a
  dedicated trigger-recovery pattern that mints the trigger node (label without
  (), since a trigger is not callable) and a triggers edge to the table named by
  the first ON after the trigger name. A trigger already recovered via the AST
  path is skipped to avoid a duplicate edge.

Added regression tests for both the clean EXECUTE FUNCTION form and the
procedural BEGIN...END form.

(cherry picked from commit a28de74a52)
2026-09-28 09:13:29 +01:00
Daksh 1e7531fb25 fix(detect): keep foreign manifest keys in their own path syntax
_to_absolute_from_storage normalized a foreign-platform absolute key
with os.path.normpath, which applies the current platform's rules: on
Windows "/home/u/foo.py" became "\home\u\foo.py", a string POSIX cannot
read back. Collapse dot segments under the key's own syntax instead
(ntpath for a drive letter or leading backslash, posixpath otherwise).

test_save_manifest_relativize_step_collapses_seeded_duplicates never
reached save_manifest's own collapse: load_manifest already removes the
duplicate first, so the test passed with the save side reverted to
last-wins. Stub load_manifest to hand over the un-collapsed rows.

Also annotate _collapse_manifest_duplicates like its sibling helpers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 9db2cfe2eb)
2026-09-28 09:13:29 +01:00
Daksh c2fb556919 fix(ingest): rewrite only the host when normalizing a tweet URL for oEmbed
_fetch_tweet did url.replace("x.com", "twitter.com") over the whole URL,
so "x.com" in the path or query was rewritten too (a ?next= link, or a
handle like dropbox.com_fan becoming dropbotwitter.com_fan), and an
uppercase X.COM host was missed. Match and rewrite the host only, the
same way _detect_url_type classifies it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3ec4fdcfca)
2026-09-28 09:13:29 +01:00
harshaygadekar e4a6f5098e fix(watch): serialize _rebuild_lock on Windows via msvcrt
Closes #3881.

On Windows, _rebuild_lock falls back to yield True when fcntl cannot be
imported, leaving concurrent rebuilds completely unserialized and causing
file collisions on .graph.tmp.json.

Implement Windows file locking using Python's standard library msvcrt module.
Lock a byte range at offset 4096 so external readers can still read the owning
PID at byte 0 without hitting Windows mandatory lock PermissionErrors.

Un-skip the 4 rebuild lock tests and 3 pending queue tests on Windows, and
add test_rebuild_lock_blocks_concurrent_process.

(cherry picked from commit d8cd456650)
2026-09-27 18:59:12 +01:00
safishamsiandClaude Opus 4.8 e1d9deed6a security(fortran): strip #include directives before cpp (GHSA-pcc4-rvhr-2pr8)
The Fortran capital-F cpp step relied on -nostdinc -I /dev/null to block
#include-based host-file reads, but cpp always searches the source file's
own directory for quoted includes and always honours absolute paths
regardless of those flags. A malicious .F/.F90 file with
#include "/etc/passwd" or #include "../../../secret" could inline
arbitrary host files into graph.json/GRAPH_REPORT.md and the LLM context
on the default offline path (CWE-22/73/200, high severity).

Strip every #include directive before preprocessing and feed the
sanitized source to cpp on stdin, so cpp never opens the file's directory
or any absolute/traversing include path. Macro expansion (#define/#ifdef,
the actual reason capital-F files need cpp) is preserved; cross-file
include fidelity is traded away to close the arbitrary-read vector.
Feeding stdin also removes the -I/etc/x.F90 argument-injection edge case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-27 18:56:31 +01:00
nikhil2004 c66eebe25f fix(python): resolve nested scan-root imports via namespace projection (#3843)
When the scan root is a sub-directory of a monorepo package hierarchy
(e.g., root = Company/Apps/Jobs/Team/), absolute imports using the full
dotted namespace (from Company.Apps.Jobs.Team.lib import delivery) were
unresolved because the scan root probed root/Company/Apps/Jobs/Team/lib
which doesn't exist inside root.

_infer_scan_root_namespace walks above the scan root collecting ancestor
directory names that contain __init__.py, establishing the root's
namespace prefix. When an absolute import's module name starts with that
prefix, the prefix is stripped and the remainder is re-probed relative
to root.

The existing root/rel fast path, ancestor walk (#2072), ambiguous import
guard (#3729), and phantom-edge retraction (#3784) are all untouched.
Third-party imports cannot false-match because the prefix check requires
a strict dotted prefix plus a remaining local component.

Co-Authored-By: Google Antigravity <noreply@google.com>
(cherry picked from commit 640e39efc4)
2026-09-27 18:40:06 +01:00
Sinan Gümüşkabak 1990b02b00 fix(extract): skip JSX member tags
With a lowercase receiver, <icons.Close /> and <props.Comp /> resolved by the
property name and bound to unrelated local Close() / Comp() functions. None
of the member tags tried produced a correct edge, so only bare identifiers
are handled now.

(cherry picked from commit aa4be46dac)
2026-09-27 18:39:52 +01:00
Sinan Gümüşkabak a3559c2541 test: member JSX tag must not bind to a local function by its last segment
(cherry picked from commit af7ea6adaf)
2026-09-27 18:39:52 +01:00
Sinan Gümüşkabak 3a8db79305 fix(extract): add calls edges for JSX component usage
<Comp /> and <Comp>...</Comp> are parsed as jsx_self_closing_element /
jsx_opening_element with the tag in the `name` field, and neither type was
in call_types, so components that are only rendered got no incoming edge.

Add both types to the JS and TSX call_types and read the callee from
`name`. Tags starting with a lowercase letter are intrinsic elements and
are skipped; for member tags the last part decides, so <div> and
<motion.div> don't bind to a local div(). Namespaced tags and fragments
are ignored.

(cherry picked from commit 2828b55851)
2026-09-27 18:39:52 +01:00
KaiyiQuan cd7aa6cb78 test(csharp): verify user-defined tuple element types stay referenced (#3796)
Per Copilot review: the regression test must prove both halves of the fix —
element names are excluded, AND the real element type references are still
collected. Add a test using user-defined element types `(Mode mode, Label
label)`: asserts Mode/Label nodes and their references edges survive while
the names mode/label are not minted.

(cherry picked from commit 6506c32824)
2026-09-27 18:39:52 +01:00
KaiyiQuan 3c407dcb8c fix(csharp): don't collect tuple element names as type references (#3796)
A named tuple type `(int mode, string label)` is a `tuple_type` whose
`tuple_element` children carry both a `type` and a `name` field.
_csharp_collect_type_refs walked every named child, so the element NAMES
were collected as type references, minted as sourceless placeholder nodes
and emitted `references` edges — one junk type node per element, repeated
in every file declaring such a signature.

Only the `type` field of each tuple element should feed type-reference
collection; the `name` is an identifier, not a type reference. Fix the
collector to descend into the element's type field only.

Regression: tests/test_csharp_tuple_type_refs.py asserts no node/edge is
minted for element names (all existing C# tests pass).

(cherry picked from commit bfcdda97b0)
2026-09-27 18:39:52 +01:00
himanshupatro-334 286000d199 fix(skillgen): prevent INPUT_PATH shell injection
(cherry picked from commit a9551306af)
2026-09-27 18:39:51 +01:00
himanshupatro-334 fa284e9993 fix(skillgen): prevent monolith watch path injection
(cherry picked from commit a898e6890c)
2026-09-27 18:39:51 +01:00
breken-ai cb1016c405 fix(terraform): redact the value paired with a secret-named name in name/value lists
The ECS environment idiom { name = "DB_PASSWORD", value = "hunter2" } names the
secret in the name literal, not in a key, so key-name redaction let the value
reach graph.json and the MCP surface verbatim. When a map's name literal
matches the sensitive pattern, redact its value/valueFrom.

Fixes #3787

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit e11cf947d0)
2026-09-27 18:39:51 +01:00
ayushcodes10 c973b90dea Add a regression test for foreign platform absolute key detection
Covers the review finding directly: a Windows drive letter key, a
UNC key, and a POSIX absolute key must all be recognized as already
absolute regardless of which platform the test runs on, and must not
be joined onto the scan root. Confirmed against pre fix code via git
stash, the test fails there since the recognizing helper does not
exist yet.

(cherry picked from commit 33b3a7a00a)
2026-09-26 13:53:08 +01:00
ayushcodes10 978c8d433b Add a regression test for the dot segment collapse gap
Covers the review finding directly: a relative manifest key with a
redundant dot dot segment must canonicalize onto the same absolute
path as a plain key for the same file and collapse with it, keeping
the more recently seen entry, instead of surviving as a second,
uncollapsed row.

Confirmed against pre fix code via git stash: the test fails there
and passes only with the fix applied.

(cherry picked from commit 7505a29bb3)
2026-09-26 13:53:08 +01:00
ayushcodes10 361b17f21a Add regression tests for the manifest duplicate key collapse fix
One test covers load_manifest directly, checking both on disk
orderings of a stale absolute entry and a fresh relative entry for
the same file, confirming the fresher one wins regardless of which
key iterates last. A companion test covers the write side, seeding a
save through an untouched file's existing duplicate rows and
confirming the relativize step keeps the fresher entry there too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit 4839ae9aba)
2026-09-26 13:53:08 +01:00
L4XB dd65345e98 fix(ingest): classify a URL by its host, not by text it contains
_detect_url_type tested substrings of the whole URL, so any host ending in
x.com (dropbox.com, netflix.com, linux.com, box.com) was treated as a tweet
and saved as an empty oEmbed stub, and a name in the path or query was
enough for the arxiv, github and youtube types. Match the parsed host or
its subdomains instead.

(cherry picked from commit d48ba15fe4)
2026-09-26 13:53:08 +01:00
abhirupone cfac4d096c fix(dedup): preserve pre-existing self-loops during entity deduplication
(cherry picked from commit 80c0d8b1ff)
2026-09-26 13:53:08 +01:00
abhay-codes07 eaa35c229b fix(extract): skip the process pool up front when spawn can't re-import __main__ (#3669)
Under the spawn start method (the Windows default) each worker re-imports the
parent's __main__ by its __file__ path. A stdin (`… | python -`), `python -c`,
or REPL caller has no such file — the path is missing or `<stdin>` — so every
worker dies during bootstrap and the pool raises BrokenProcessPool before any
work is done. The shipped SKILL.md pipes a heredoc into the interpreter, so on
Windows this is the path most users take, not an edge case: every skill-driven
run prints one full worker traceback per core, then a fallback warning that
blames a missing `if __name__ == "__main__":` guard — a fix the caller cannot
apply, because there is no file to put a guard in.

Detect the unusable-__main__ case before creating the pool: when the start
method is spawn (or the platform is Windows) and __main__ has no importable
file, run sequentially and print one note that names the real cause (stdin/-c/
REPL) and the remedy (write the step to a .py file, or pass parallel=False). A
script that DOES have a __main__ file but omits the guard is a different failure
this cannot catch here; it still surfaces via the existing BrokenProcessPool
fallback, whose __main__-guard message is now accurate for that remaining case.

Tests cover the detector (stdin, REPL-without-__file__, a real script, and the
fork start method) and that extract() with >= _PARALLEL_THRESHOLD uncached files
and an unusable __main__ never attempts the pool yet still produces correct
output. All five fail without the guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJbLfztSxm2tH5cJwBbe9q
(cherry picked from commit b475196ed1)
2026-09-26 13:53:08 +01:00
abhay-codes07 ef58341357 fix(js): follow tsconfig references so solution-file path aliases resolve (#3745)
`_read_tsconfig_aliases` walks `extends` chains but never `references`. In the
standard Vite / `tsc -b` layout the root `tsconfig.json` is a solution file —
`"files": []` with `references: [{path: "./tsconfig.app.json"}, …]` — and every
`compilerOptions.paths` block lives in a referenced project config. The loader
finds the solution file, sees no `paths` and no `extends`, and stops, so every
path-alias import in the project silently produces no `imports_from` edge and
`graphify affected` returns a partial consumer set with no warning.

Follow `references` the same way `extends` is followed: merge each referenced
config's aliases like an additional parent (the referencing config's own `paths`
still override), guarded by the existing `seen` set that protects against
cycles. A reference `path` may name a directory (resolved to its
`tsconfig.json`, per `tsc -b`) or a config file directly.

Regression tests cover both the solution-file layout and a directory-valued
reference; both fail on the unpatched loader and pass with the fix. The existing
JS/TS resolution, jsconfig-baseUrl, extension-resolution and Astro suites stay
green (135 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJbLfztSxm2tH5cJwBbe9q
(cherry picked from commit 4e84a23822)
2026-09-26 13:53:08 +01:00
rajatnagda45 6c0636c426 fix(julia): extract macro definitions and @enum types
Two core Julia constructs were dropped by the extractor:

- macro name(...) ... end produced no node, even though macros are first-class,
  heavily used definitions. The grammar gives a macro the same signature shape
  as a function, so it now mints a definition (labelled @name) and its body is
  walked for calls -- with the signature skipped so the macro does not call
  itself.
- @enum Name a b c (and the @enum Name begin ... end block form) is a
  macrocall_expression that was ignored entirely. The first identifier in the
  argument list is the enum type; the rest, including members inside a begin/end
  block, are contained by it. Other macro calls still fall through so
  definitions nested in e.g. an @testset block are walked.

Added tests covering macro extraction with body-call attribution (no self-loop)
and both @enum forms with members contained by their type.

(cherry picked from commit 87edb5a278)
2026-09-26 13:48:37 +01:00
rajatnagda45 1edda3a704 fix(ocaml): extract classes and their methods and instance variables
The OCaml walker had no branch for class_definition, so a class object --
its methods, its instance variables, and the calls made from method bodies --
was dropped entirely. A file made only of classes produced no nodes at all.

Add a class_definition branch that mints the class node (defines/contains),
walks the object body (object_expression in .ml, class_body_type in .mli) for
method and instance-variable members, and attributes calls in each method body
to that method. Method names are deliberately not registered as local defs:
they are reachable only through obj#m, so binding a bare call to a same-named
method would be a false edge.

(cherry picked from commit 63572f0cbe)
2026-09-26 13:45:58 +01:00
safishamsiandClaude Opus 4.8 2cb9743731 test(kotlin): drop dead imports, add plain-param-not-a-field negative test
Polish on #3848: remove the unused mid-file tree_sitter imports (F401)
and add a negative test asserting a bare constructor param without
val/var is not emitted as a field property.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-26 13:43:42 +01:00
nikhil2004 5757fb56e7 fix(extract): extract Kotlin annotations and primary constructor properties
Resolves #3842.

- Adds `_kotlin_annotation_names` helper to correctly extract annotations for Kotlin.
- Emits references edges with context='attribute' for class, function, and property annotations.
- Correctly skips use-site targets like `@field:` when extracting annotation names.
- Correctly parses bracketed annotations with multiple targets (e.g. `@[Inject VisibleForTesting]`).
- Traverses `primary_constructor` to extract `val`/`var` property dependencies as field edges.
- Resolves annotations using simple names to prevent dangling fully-qualified nodes.

Co-Authored-By: Antigravity <noreply@google.com>
(cherry picked from commit 579bce264e)
2026-09-26 13:39:55 +01:00
rajatnagda45 a0c1359154 fix(fortran): link type-bound procedures to their derived type
A derived type's contains section binds procedures as the type's methods
(procedure :: area => circle_area, or plain procedure :: scale), but the
derived_type_definition branch only minted the type node and ignored the
binding list entirely. The type ended up in the graph with no connection to
its own methods, and calls dispatched through the type were unrepresented.

Collect the bindings while walking the type and, after the whole tree is
walked (so the module's internal procedures already have nodes), add a method
edge from the type to each implementing procedure. A binding to a procedure
from another module resolves to a sourceless stub via ensure_named_node, the
same treatment parameter and return types already get, so the corpus rewire
can collapse it and no dangling edge is produced.

(cherry picked from commit 75f8fff533)
2026-09-26 13:39:37 +01:00
ayushcodes10 6cff8d6952 Add a regression test for the incremental cache_root leak
Covers issue 3847 directly: an incremental detect call given a
cache_root outside the scan root must not create anything under the
scan root, and the word count stat index cache file must land under
the requested cache_root instead. Confirmed against pre fix code by
restoring the prior versions of detect.py and cli.py directly, the
call raises a type error there since the parameter did not exist yet.

(cherry picked from commit d745f7b00e)
2026-09-26 13:39:37 +01:00
rajatnagda45 1ebbcdbfb7 fix(elixir): extract defprotocol and defimpl as containers
defprotocol and defimpl were not recognized as definition keywords, so the
walker fell through to generic recursion with no parent module. The protocol
and implementation nodes were never created, and their functions were attached
to the file node instead of their container (two orphaned size() nodes hanging
off the file rather than off the protocol and its List implementation).

Handle both like module-like containers: mint the protocol/impl node, contain
it in its enclosing scope, and walk the do-block so each def becomes a method
of the protocol or implementation. The implementation also gets an implements
edge to its protocol; a cross-file protocol target is filtered by the existing
dangling-edge guard rather than left hanging.

(cherry picked from commit 5f4e979693)
2026-09-26 13:39:37 +01:00
himanshupatro-334 89280317ed fix: preserve cross-file edges during incremental updates
(cherry picked from commit b6f3adffc1)
2026-09-25 16:15:15 +01:00
ayushcodes10 43026db66f Add regression tests executing Step 1 with a hostile substituted path
Extracts the real Step 1 bash block from the committed skill.md
artifact, substitutes INPUT_PATH the way an agent following the
instructions would, and actually runs it, so the fix is checked
against what users receive rather than the fragment source alone. One
test confirms a command substitution embedded in the substituted path
never runs, another confirms a semicolon separated command never
runs, a third confirms a legitimate path with a space in it still
resolves correctly, and a fourth confirms a nonexistent path still
fails the whole step loudly. All four were checked against the
pre fix block first, three failed as expected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit ad98afa9f5)
2026-09-25 16:01:53 +01:00
ayushcodes10 d7e3c6f7f2 Add a regression test for the stray source_location gate
Covers the review finding directly: a candidate with a
source_location but no source_file must not out rank a fully bare,
richer candidate. Confirmed against pre fix code via git stash, the
test fails there and passes only with the fix applied.

(cherry picked from commit f6afc87140)
2026-09-25 16:01:47 +01:00
ayushcodes10 a71ee67d7c Add regression tests for the source_location provenance tiebreak
Covers the review finding directly: a record with a source_file but
no source_location must not lose to a richer, unlocated stub that
also carries a source_file, and the tiebreak must stay inert when
both sides already have a real location, preserving the existing
richness ordering there.

Confirmed against pre fix code via git stash: the direct repro test
fails there and passes only with the fix applied.

(cherry picked from commit 4915270490)
2026-09-25 16:01:47 +01:00
ayushcodes10 699d18f760 Add regression tests for the pick winner provenance tiebreak
One test is the issue's own exact reproduction, a source less stub
that genuinely out scores a real located declaration on field count
alone, checked in both argument orders. A companion test confirms the
provenance tiebreak stays inert when both candidates carry a source
file, so the existing richness then length ordering this file already
established is untouched. The first test was checked against the pre
fix code and failed there as expected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit 0e155019e3)
2026-09-25 16:01:47 +01:00
himanshupatro-334 bb373632d6 fix: prevent C# member nodes from being resolved as types
(cherry picked from commit 25de4ace89)
2026-09-25 16:01:47 +01:00
himanshupatro-334 769851dfae fix: exclude non-types from C# type resolution
(cherry picked from commit dfe5a220b2)
2026-09-25 16:01:47 +01:00
Vladimir Babin cac084cf3d fix(manifest_ingest): resolve inherited groupId and ${...} properties in pom.xml (#3806)
(cherry picked from commit 292b9d8465)
2026-09-25 16:01:47 +01:00
ayushcodes10 88776942ef Add regression tests for the undocumented components gate
Covers issue 3801 directly: a code plus concept only graph (no
document, paper or image nodes anywhere) must not offer undocumented
components as a reason for an isolated node, only possible missing
edges. Adding a single document node elsewhere in the same graph
shape brings the fuller reason back, confirming the gate tracks the
graph's actual content rather than being tied to a particular test
fixture shape.

Confirmed against pre fix code via git stash: the first test fails
there and passes only with the fix applied.

(cherry picked from commit 02e1b4d6c2)
2026-09-25 15:44:21 +01:00
breken-ai 0dd9f8ba5c fix(terraform): redact secret-named variable defaults and output values
A variable or output names its secret in the block label, so the literal
sits under the generic key default/value and the key-name check never
flags it: variable "db_password" { default = "..." } reached graph.json
verbatim. Redact default/value when the label matches the sensitive-key
pattern or the block sets Terraform's own sensitive = true.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 01e417166b)
2026-09-25 15:44:21 +01:00
Sinan Gümüşkabak f3483171b9 fix(cli): wait for the hash-seed re-exec on Windows instead of os.execvpe (#3799)
On Windows os.exec* does not replace the process: CPython spawns a new one
and the caller exits at once, so update/extract/cluster-only/label returned
before graph.json was written, and the exiting parent intermittently died
with an access violation (exit 139). Run the child with subprocess, wait for
it and propagate its exit status there; POSIX keeps the real os.execvpe.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 94a9657e93)
2026-09-25 15:44:21 +01:00
abhay-codes07 45ceb2273a fix(cobol): link both endpoints of a PERFORM ... THRU range
`PERFORM A THRU Z` (and `THROUGH`) runs the whole paragraph range A..Z, but the
PERFORM pattern captured only the first name, so a `calls` edge was emitted to A
and the range-end Z got none. "What performs Z?" then answered nothing even
though this paragraph does, and any reachability walk stopped short of the
range's tail.

Capture the optional `THRU`/`THROUGH` target and enqueue both endpoints for
resolution against the paragraph table. Intermediate paragraphs in the range are
not individually linked (that would need paragraph source ordering); the two
endpoints are the reliable, common signal and both now resolve. A plain
`PERFORM A` is unchanged.

Regression test: `PERFORM A-PARA THRU Z-PARA` now links MAIN to both A-PARA and
Z-PARA (fails on the old single-capture pattern).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJbLfztSxm2tH5cJwBbe9q
(cherry picked from commit abcdde1a65)
2026-09-25 15:44:08 +01:00
abhay-codes07 81afa16bd9 fix(cobol): detect fixed-format source that carries sequence numbers
The fixed/free format detector counted a line as fixed-format only when its
first six columns were blank (`^ {6}[ *\-/ ]`). Legacy mainframe COBOL — the
main reason to have a COBOL extractor — puts a sequence NUMBER in columns 1-6,
so every such file scored zero fixed markers and was classified free-format.

In free mode the code is taken verbatim (no column-8 slice), so the sequence
number stays glued to the statement: `000400 MAIN-PARA.` no longer matches the
paragraph anchor `^NAME .? .$`, and the whole procedure layer disappears. A
seven-line program with two paragraphs and a PERFORM collapsed to just the file
and program nodes — zero paragraphs, zero `calls` edges — silently.

Match a sequence area that is six spaces OR six digits, followed by a valid
indicator column (space = code, `*`/`/` = comment, `-` = continuation, `D` =
debug). Once the file is correctly read as fixed-format the existing
column-8..72 slice strips the sequence number and paragraphs/PERFORMs resolve
as they should. Blank-sequence fixed-format and genuinely free-format source are
unaffected (a 6-digit prefix is not something free-format code begins a line
with).

Regression test: a sequence-numbered program now yields its program, both
paragraphs, and the PERFORM `calls` edge — and fails on the old detector.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJbLfztSxm2tH5cJwBbe9q
(cherry picked from commit 96b9522bd5)
2026-09-25 15:43:14 +01:00
safishamsiandClaude Opus 4.8 793aca6714 test(php): cover file-scope, no-duplicate, and method-scope closures (#3409/#3461 follow-up)
#3461 fixes #3409 (PHP closures produce no nodes / inner calls lost). Adds the
coverage its tests omitted:
- the reporter's exact repro — a FILE-SCOPE argument-position closure — asserting
  the closure node exists AND its inner call resolves to the closure (not the file);
- a no-duplicate-node assertion guarding the walk partition against double-walk;
- a method-scope closure asserting its inner call attributes to the closure, not
  the enclosing method (pins the function_boundary_types behavior).

Verified end-to-end: closure->handler() edges attribute to {closure#N} nodes with
no duplicates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 19:45:40 +01:00
nikhil2004 95dd8cf9a0 fix(php): allow relative prefixes in route groups and correctly fail tests on extractor error
(cherry picked from commit 29ed19f1e4)
2026-09-23 19:42:04 +01:00
nikhil2004 8227c468c2 fix(extract): robust PHP nested routing closure extraction (#3409)
Address edge cases identified in review:
- Nested route closures (e.g., inside group() or prefix()) now correctly compose their full path by walking up the AST across closure boundaries.
- Non-routing closures passed to methods that share verbs (like ->get('user:42')) are no longer misidentified as routes. A route path must begin with '/' to qualify, otherwise it correctly falls back to an ordinal name.

(cherry picked from commit 38861aa1c4)
2026-09-23 19:34:18 +01:00
nikhil2004 2c172e4969 fix(extract): stable closure naming for PHP (#3409)
Address reviewer feedback:
- Replace line-based {closure@N} names with stable ordinal {closure#N}
  names scoped per enclosing class or file. Ordinals are unaffected by
  line insertions/deletions above a closure; only reordering closures
  or inserting one earlier in the same scope shifts later ordinals,
  which is a much rarer edit.
- Route closures passed to routing verbs (get/post/put/patch/delete/
  options/any/match/map) receive a semantic 'VERB /path' label that
  is both stable and directly meaningful to graph queries (the primary
  use-case from the issue).

Note: adding anonymous_function_creation_expression and arrow_function
to function_boundary_types (introduced in the first commit) means calls
inside a closure now attribute to the closure rather than the enclosing
named function. This is the correct behaviour; existing codebases with
closures inside named functions will see those edges move on next
incremental update.

(cherry picked from commit 5400b9cbd7)
2026-09-23 19:34:18 +01:00
nikhil2004 cd3fd9436e feat(extract): support PHP closures (#3409)
The bug:
PHP closures (`anonymous_function_creation_expression` and `arrow_function`)
were invisible to the graph, disconnecting API routes and callbacks from
the backend code.

The fix:
- Added closure syntax node types to _PHP_CONFIG's `function_types`.
- Updated engine.py to synthesize line-bound names (e.g., `{closure@42}`)
  for unnamed closures matching these AST node types, enabling them to be
  extracted as linkable nodes in the graph without ID collisions.

(cherry picked from commit c8c3af1960)
2026-09-23 19:34:18 +01:00