1958 Commits
Author SHA1 Message Date
safishamsiandClaude Opus 4.8 4139885a12 release: 0.9.69
Five language-extractor enrichments (OCaml/Elixir/Fortran/Julia methods,
protocols, type-bound procs, macros/@enum, Kotlin annotations+ctor props),
tsconfig references alias resolution, spawn-safe process-pool skip,
self-loop-preserving dedup, host-based URL classification, incremental
cache_root forwarding, deterministic manifest tie-break, and a
contributor-guide/community-health docs overhaul.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v0.9.69
2026-09-26 14:02:32 +01:00
safishamsiandClaude Opus 4.8 0115e43122 docs: align #3845 contributor guide with maintainer policy
Follow-up edits on #3845 to match the settled maintainer decisions:
- CODE_OF_CONDUCT.md: set the enforcement/reporting contact to
  safi@graphify.com (was an unspecified 'email the maintainer if known').
- README team-graph section: add the machine-local never-commit list
  (.graphify_root, .graphify_python, .graphify_analysis.json, the AST
  cache, needs_update) and the re-extract-to-update note. manifest.json
  stays committable since #3781 made its keys portable.
- Add RELEASING.md (maintainer-facing): version bump + changelog +
  uv.lock, test on 3.10/3.13, push v8, gh release create -> PyPI via
  trusted publishing (no twine/token), verify with uvx --refresh.
- CONTRIBUTING Further Reading: drop the paid Gumroad link, point at
  RELEASING.md instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-26 13:57:39 +01:00
nikhil2004 a30bcfaf50 docs: overhaul GitHub issue and pull request templates
(cherry picked from commit 3388311881)
2026-09-26 13:55:08 +01:00
nikhil2004 910a4d7ab1 docs: establish contributor guidelines and code of conduct
(cherry picked from commit c7fb720429)
2026-09-26 13:55:08 +01:00
nikhil2004 d5916e6a20 docs: correct factual drift in architecture and security policies
(cherry picked from commit a61eeebb29)
2026-09-26 13:55:08 +01:00
nikhil2004 98d73fe3a8 docs: clarify repository orientation and team graph sync rules
(cherry picked from commit 9d2592ea50)
2026-09-26 13:55:08 +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 007844e0c8 Recognize a foreign platform absolute key before re anchoring it
Path.is_absolute() only recognizes the current platform's own path
syntax, so a manifest key using a different platform's absolute form,
a POSIX /abs/path loaded on Windows, or a C: or UNC path loaded on
POSIX, was wrongly judged relative and joined onto the scan root,
producing a nonsense path like root plus C: colon Users colon x colon
foo dot py instead of being left alone. A manifest genuinely can move
between platforms, which is this whole module's own stated scope for
tolerating format mismatches.

A new helper checks for a leading slash or backslash or a drive
letter pattern in addition to the native is_absolute check, so a
foreign absolute key is recognized and passed through unchanged on
any platform instead of only the one that produced it.

Fixes review finding on PR 3781.

(cherry picked from commit 7f47a5fef4)
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 82514fc534 Normalize dot segments when re anchoring a manifest key
_to_absolute_from_storage joined a relative key onto the resolved
root with a plain path join, which never collapses a parent segment
the way resolve does. A relative key such as sub/../foo.py, the kind
of format mismatch this function exists to tolerate across a mix of
call sites and versions per its own docstring, then canonicalized to
a different string than the plain absolute key for the same file, so
the duplicate collapse this function exists for silently missed it.

The joined result is now run through normpath, which purely
lexically collapses dot segments without touching the filesystem or
following symlinks, matching the sibling relativize function's own
choice not to resolve the key.

Fixes review finding on PR 3781.

(cherry picked from commit e558ed93c5)
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
ayushcodes10 45edd77b71 Break manifest key collapse ties by seen time, not iteration order
A manifest written across a mix of versions or call sites, some
passing root to relativize keys and some not, an outdated installed
skill runbook for one, can end up carrying both an absolute and a
relative key for the same file, each with different data. Both
load_manifest and the relativize step inside save_manifest already
canonicalize every key through a comprehension, so the two forms do
collapse into one entry, but a plain dict comprehension keeps
whichever raw key happens to iterate last, an artifact of on disk
JSON key order that has nothing to do with which entry is actually
current. A fresher hash could be silently discarded in favor of a
stale one purely because of how the keys happened to accumulate,
letting the incremental change detector call a genuinely changed file
unchanged.

Reproduced directly: a manifest with a stale absolute entry and a
fresh relative entry for the same file returns the stale one when it
happens to be written second, and the fresh one when the order is
reversed, confirming the collapse really is order dependent today.

Both call sites now go through one small helper that breaks a
collision by each entry's own seen timestamp when both sides have one
and they disagree, since that field exists specifically to record
when an entry was last confirmed current. A legacy or partial entry
without that field falls back to the existing last one wins behavior
unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit fc7dc25a0a)
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 2b8a2972c5 fix(extract): remove fully-qualified fallback for Kotlin annotations
(cherry picked from commit 4f198dfc72)
2026-09-26 13:39:55 +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
ayushcodes10 bbb127e5f4 Forward cache_root through the incremental extract detection path
extract with an out destination outside the scan root stayed clean on
a fresh scan, since that branch already passes cache_root to detect,
but leaked the word count stat index cache file into the scan root on
the very next incremental run against the same destination.
detect_incremental had no cache_root parameter at all, so there was
nowhere for the caller to pass it even if it wanted to, and the word
count cache fell back to anchoring at the scan root instead of the
requested out directory.

detect_incremental now accepts cache_root and forwards it into its
own internal call to detect, and the incremental branch in cli.py
passes cache_root equal to out_root, matching what the fresh scan
branch a few lines below it already does.

Fixes issue 3847.

(cherry picked from commit 9553cae7d9)
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
safishamsiandClaude Opus 4.8 4000de1546 release: consolidate unreleased 0.9.69 into 0.9.68
0.9.68 was bumped locally but never published to PyPI (latest published
is 0.9.67), so fold the second triage round's five PRs into a single
contiguous 0.9.68 release rather than skipping the number. No PyPI gap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v0.9.68
2026-09-25 16:33:01 +01:00
safishamsiandClaude Opus 4.8 636f2fe08a release: 0.9.69
Complete the skillgen --watch INPUT_PATH injection fix in the add-watch
reference (#3742), preserve cross-file edges on incremental update
(#3812), stop C# type references resolving to same-named non-type nodes
(#3815), prefer a real source location over richness in dedup (#3786),
and resolve Maven inherited groupId + ${...} properties in pom.xml
(#3823).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-25 16:22:25 +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
safishamsiandClaude Opus 4.8 8595749021 security(skillgen): neutralize the --watch INPUT_PATH sink in add-watch reference
Completes #3742: the Step 1 fix closed the .graphify_root shell line, but
the progressive-disclosure add-watch reference still passed the raw,
agent-substituted INPUT_PATH placeholder unquoted into a bash command
($(cat .graphify_python) -m graphify.watch INPUT_PATH), the same
injection class - a scan root like $(...) / ; rm ... would execute.

The watcher targets the folder graphify already extracted, so read the
trusted graphify-out/.graphify_root that Step 1 resolves (the same
sidecar pattern this reference already uses for .graphify_python)
instead of re-substituting the untrusted placeholder. Regenerated all
14 host add-watch artifacts + expected/ snapshots; monolith-roundtrip
and always-on-roundtrip stay green (cores untouched).

The identical sink in the aider/devin monolith cores is tracked
separately (editing a core requires a gen.py sanctioned-diff).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-25 16:07:51 +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 0dfcd7fdd9 Regenerate skill artifacts for the Step 1 injection fix
Ran the generator, then the bless command, with no manual edits.
Confirmed clean with the check, audit coverage, monolith roundtrip,
and schema singleton verification commands.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit 2b41299b89)
2026-09-25 16:01:53 +01:00
ayushcodes10 c8e5bfe2bb Stop substituting INPUT_PATH into an interpreted shell command in Step 1
Step 1's own bash and PowerShell fragments both built a command whose
literal text was the resolved scan path, substituted verbatim by the
agent following the instructions before that line ever ran. The bash
form, echo dollar paren cd INPUT_PATH and pwd close paren, still
expands a command substitution even inside the outer double quotes,
and the cd itself was entirely unquoted; the PowerShell form passed
INPUT_PATH as a bare unquoted argument to Resolve Path, exposed to the
same class of problem through a stray semicolon or pipe. A path drawn
from an untrusted source, a malicious readme's suggested command, a
copied value from an untrusted page, executed as code the moment this
line ran, before any Python was ever reached.

Both now capture INPUT_PATH through a construct their own interpreter
guarantees performs no expansion at all: a quoted bash heredoc for the
posix form, a single quoted PowerShell here string for the windows
form. The raw text reaches Python (respectively Resolve Path) only as
inert data on standard input, never as source the shell itself
parses. Verified for the posix form by actually executing the
extracted Step 1 block with a malicious substituted value and
confirming no injected command runs; the PowerShell form could not be
executed in this environment (no interpreter available to install
without an interactive credential prompt), so it was written using
well established, unambiguous here string syntax and reviewed
carefully rather than run.

As a side effect of no longer building the path through an unquoted
cd, a legitimate path containing a space is now handled correctly
too, and a nonexistent path now fails the whole step loudly instead
of silently continuing past a swallowed cd error.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit 9a7e5d0a51)
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 9bc077b907 Gate the source_location tiebreak on a real source_file
A stray source_location with no source_file, a location pointing at
an unstated file, which _merge_missing_attributes can produce by
backfilling one field but not the other when a survivors own
source_file is an empty string rather than None, was still granted
an edge over a fully bare candidate by the location tiebreak, even
though neither side actually has real provenance. The tiebreak now
only counts source_location when source_file is present too, so a
location with no file falls through to richness like any other bare
field would.

Fixes review finding on PR 3786.

(cherry picked from commit 3b3cc81541)
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 f7092b45d5 Extend the provenance tiebreak to source_location too
source_location is richness ignored the same way source_file already
is, so two candidates that both carry a source_file could still be
ordered by field count alone, letting a record with no real location
out score one that also knows exactly where in the file it lives. The
codebase genuinely emits source_location as None on some records, so
this is a real distinction, not a hypothetical one. The tiebreak now
checks source_location as a second provenance step, after source_file
and before richness, and only changes the outcome when the two sides
disagree on having one.

Fixes review finding on PR 3786.

(cherry picked from commit 1d33a488e0)
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
ayushcodes10 02b32f4cfe Give a real source location priority over richness in pick winner
source_file and source_location are both in the set of keys the
richness score deliberately ignores, since #3372 added that score to
compare actual content, not placement. That leaves richness with no
way to tell a real, located declaration apart from a source less
stub that happens to carry a couple of incidental bookkeeping keys,
letting the stub out score and replace the genuine record purely on
field count.

Provenance is now checked ahead of richness in the survivor scoring
tuple, so a node with a real source location always wins over one
without. This only changes the outcome when the two sides actually
disagree on provenance; every case where both, or neither, side
carries a source file keeps the exact ordering the richness fix
already established.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qfdzgbA5KedGEjD1AayNh
(cherry picked from commit a9180c0da7)
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
safishamsiandClaude Opus 4.8 d197ae36fa release: 0.9.68
Windows hash-seed re-exec wait (#3816/#3799), Terraform secret-named
variable-default/output redaction (#3817), COBOL fixed-format
sequence-number detection (#3813) and PERFORM...THRU both-endpoint
linking (#3814), and gate the GRAPH_REPORT undocumented-components
reason on a real semantic layer (#3828/#3801).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-25 15:54:48 +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
ayushcodes10 6b6778aede Gate the undocumented components reason on a real semantic layer
GRAPH_REPORT.md's Knowledge Gaps section always offered undocumented
components as a possible explanation for an isolated node, regardless
of whether the graph could ever actually have one. That phrase only
means anything when a semantic layer exists, document, paper or image
nodes an LLM extracted meaning from, where an isolated node genuinely
could be mentioned but never explained further. A code only graph has
no such nodes at all, so offering it as a live possibility on every
report is misleading.

The reason now checks whether any node in the graph carries a
document, paper or image file_type before including that clause,
using the same VALID_FILE_TYPES distinction validate.py already
draws between the semantic layer and code/rationale/concept nodes, so
no new build time flag is needed.

Fixes issue 3801.

(cherry picked from commit 8a49e1f38a)
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 8e09034743 docs: standardize the Discord invite to discord.gg/XDnKVpzdXB
Point the README and he-IL translation at the single current invite (the old 2DDrEgvZb4/598Ad9zQZ links are retired). All Discord references now resolve to one canonical invite.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-25 13:52:21 +01:00
safishamsiandClaude Opus 4.8 fe566710cc docs: add community banner for the Discussions welcome post
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-25 13:29:51 +01:00