Commit Graph
1436 Commits
Author SHA1 Message Date
safishamsiandClaude Opus 4.8 e5d662eb63 test(js): cover dynamic-require skip and no-double-count for lazy requires (#2700)
Adds the two invariants the deep-dive flagged: require(variable) must not
fabricate an edge, and a module-scope require still yields exactly one
imports_from edge (guards the module-vs-body pass partition against future
double-counting). Also adds the CHANGELOG entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-15 16:46:04 +01:00
rajanpanthandClaude Opus 4.8 259bb6acfb fix(js): retain lazy CommonJS require dependencies (#2700)
A require(...) written inside a function body (the canonical lazy-require idiom
for breaking circular deps) produced no edge at all, while the identical require
at module scope resolved as EXTRACTED imports_from/imports edges. walk_calls now
feeds nested require declarations to the same _require_imports_js routine,
attributing the edge to the enclosing callable; dynamic require(var) is still
skipped and no bare local node is minted (#1077 scope guard).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-15 16:44:34 +01:00
safishamsiandClaude Opus 4.8 94c2050f93 test(js): cover external-import-shadow vs same-named local callable (#2757)
Adds the collision case the fix must survive: a name both imported externally
and defined as a callable in another corpus file. The external use must not
fabricate a cross-file indirect_call while a genuine local by-name reference
still binds. Also adds the CHANGELOG entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-15 16:43:11 +01:00
phudayyyandClaude Opus 4.8 ceeafb05ce fix(js): an import from outside the corpus shadows indirect_call resolution (#2757)
An identifier bound by an import whose target resolves OUTSIDE the scanned
corpus (e.g. a lucide-react icon) is now shadowed within the file, so using it
as a value no longer fabricates an INFERRED indirect_call onto an unrelated
same-named callable elsewhere in the corpus. The internal-vs-external decision
is delegated to the existing import resolver, so a relative/in-corpus import
still resolves to its real target. Same shadow family as #2241/#2568/#2685.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-15 16:42:12 +01:00
safishamsiandClaude Opus 4.8 774b12fe9e docs(readme): add YouTube channel badge to the social links
Adds a YouTube badge linking to https://www.youtube.com/@graphifylabs in both
the header badge row and the footer social block, alongside Discord/LinkedIn/X.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-15 16:39:46 +01:00
safishamsiandClaude Opus 4.8 9e2387f3e8 fix(ocaml): don't bind a qualified external call to a same-named local def
A qualified call `M.f` where `M` is not a module defined in the same file is
an external-library call (e.g. Hardcaml's `Reg_spec.create`, `Scope.create`).
Resolving it by bare last name bound it to a same-named local `let f`,
producing a false `calls` edge and a `create -> create` self-loop when the
caller was that local `f`. Now: track locally-defined module names; a
qualified call whose root module is not local and whose bare name collides
with a local def is kept as a distinct external target (stub labelled by the
full path), so it neither self-loops nor collapses onto the local def.
Unqualified calls and calls into a locally-defined module still resolve
locally, and cross-file `Geo.area` still collapses onto another file's `area`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 21:09:32 +01:00
safishamsiandClaude Opus 4.8 7281f27eac chore: bump to 0.9.43
Cuts a 0.9.43 section (OCaml extractor + #2652/#2653/#2596/#2597/#2655) and
dates the released 0.9.42.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v0.9.43
2026-08-14 15:36:55 +01:00
safishamsiandClaude Opus 4.8 3429264799 feat(js): extend nested-function extraction to arrow components/callbacks (#2653)
#2705 fixed `function` nested in a `function`, but the React idiom that
motivated the issue -- a function declared inside an arrow-defined component
(`const Panel = () => { function handleClick(){} }`) or an arrow callback
(`useEffect(() => { function h(){} })`) -- was still missed: the main walk
never recurses into arrow bodies and the scan bailed at the arrow boundary.

Refactors the inline scan into a module-level _scan_js_nested_function_
declarations that also descends through arrow / function-expression bodies
(attributing nested declarations to the nearest enclosing named scope), and
invokes it from the const-arrow branch of _js_extra_walk. Nested bodies join
function_bodies, so the central _tracked_body_ids guard prevents double-walk.
Adds tests for both arrow idioms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 15:02:15 +01:00
himanshupatro-334andClaude Opus 4.8 b401e8c29f fix(js): extract nested function declarations (#2653)
A named `function`/`generator_function` declaration nested inside another
function body now gets its own node, a `contains` edge from the enclosing
function, and its own call-attribution scope, so calls made from inside such a
function are no longer dropped as dangling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:49:56 +01:00
safishamsiandClaude Opus 4.8 f52b8dbc69 harden(bash): stop .. source paths escaping the corpus tree (#2596)
The #2690 form-3 (`$(dirname …)`) branch had no `..` guard and the tracked
form-4 branch let `..` walk past the base to an arbitrary host path, so a
hostile corpus could make the extractor stat and record an out-of-tree file
(source "$(dirname "$VAR")/../../../../etc/passwd") — a corpus-side info leak,
since resolve_bash_source_edges only filters *resolved* cross-file edges, not
the extractor's own edge/probe. Adds a lexical _within_tree gate: form 3
rejects `..` outright (its base is a guess), and a tracked form-4 base may
reach a sibling via $VAR/../lib but cannot escape past base.parent. Adds two
traversal-rejection tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:48:56 +01:00
Josh HudsonandClaude Opus 4.8 b345dc4993 fix(extractors/bash): resolve dirname cmdsubst and dotdot suffix in source paths (#2596)
Extends variable-built `source` resolution to two path-construction forms
that were silently dropped: `source "$(dirname "$VAR")/lib/x.sh"` (command
substitution in the source argument) and `source "$VAR/../lib/x.sh"` (a
`..` suffix when the leading var is a tracked var_bases entry).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:48:35 +01:00
safishamsiandClaude Opus 4.8 d79520198d harden(export): widen dedup reserve to 5 and add multibyte budget test (#2655)
Widens _SLUG_SUFFIX_RESERVE/_DEDUP_SUFFIX_RESERVE from 4 to 5 so a four-digit
collision suffix (_1000..) can't push a truncated stem past MAX_PATH; the
suffix is technically unbounded but 5 chars covers ~10k identical stems. Adds
an end-to-end test that CJK labels at a tight budget stay within the window,
keep their non-ASCII characters, and produce links that resolve on disk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:26:12 +01:00
abhay-codes07andClaude Opus 4.8 b7c709e13d fix(export): budget export filenames against the destination path, not just NAME_MAX (#2655)
Adds paths.stem_filename_budget(output_dir, *, reserve, limit=200) and threads
it through the Obsidian and wiki exporters so a filename stem is budgeted
against the whole Windows MAX_PATH window (drive + dirs + name + NUL), not
just the per-component 200-char NAME_MAX cap. On POSIX the helper returns the
limit unchanged, so existing vaults stay byte-identical; on Windows a long
output directory no longer pushes the total path over MAX_PATH and aborts the
export mid-write.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:24:01 +01:00
safishamsiandClaude Opus 4.8 6c29d988bd test(wiki): make the bracketed-label parity case non-vacuous (#2597)
The parity check keyed on the whole [display](target) pattern, so a link
whose display text contains brackets (Array[T] Models) never matched and the
bracket case asserted nothing. Key on the ](target) boundary instead — wiki
targets contain no ) or whitespace — so bracketed labels are actually checked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:21:34 +01:00
abhay-codes07andClaude Opus 4.8 fc00f673c6 fix(wiki): make a link target the article filename verbatim, not its percent-encoded twin (#2597)
The wiki exporter wrote each article as {slug}.md but emitted the link as
quote({slug}.md), so any label with ( ) & # or non-ASCII produced a
percent-encoded target that names no file on disk. Removes the quote() fork
and hardens _safe_filename so the slug is URL-safe by construction; the link
and the on-disk filename are now the same string.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:20:04 +01:00
safishamsiandClaude Opus 4.8 bd1ede9584 test(extract): cover per-symbol fan-out and module-top-level drop for #2652
Adds two regression tests on top of #2684: each referencing symbol gets its
own INFERRED uses edge (guarding against the old every-class fan-out and
against source collapse), and a true module-top-level reference emits no edge
(the deliberate drop). Also adds the CHANGELOG entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:18:54 +01:00
Ousama Ben YounesandClaude Opus 4.8 c08d9afa93 fix(extract): attribute cross-file INFERRED uses edges to the referencing symbol (#2652)
Rewrites Pass 2 of the Python cross-file import resolver so an INFERRED
`uses` edge anchors on the symbol whose body actually references the
imported name (a class as a unit, or a module-level function) at the real
reference line, instead of fanning out from the import statement line to
every class in the importing file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:17:45 +01:00
safishamsiandClaude Opus 4.8 0302bfa7af feat(ocaml): add OCaml .ml/.mli extractor (optional tree-sitter-ocaml extra)
New graphify/extractors/ocaml.py handles both the implementation grammar
(language_ocaml, .ml) and the interface grammar (language_ocaml_interface,
.mli). Emits nodes for modules, top-level/module-level values and functions,
types and their variant constructors; edges for defines/contains, open ->
imports_from, and application -> calls. Qualified paths (Geo.area) resolve to
the final value name, not the module qualifier; local let ... in bindings do
not mint nodes or steal call attribution. Cross-file open/call targets are
sourceless stubs so the corpus rewire collapses them onto the unique real
definition (no #1402 sourced-stub leak).

Wired into detect.py (CODE_EXTENSIONS), extract.py (dispatch +
_EXTRA_FOR_EXTENSION), pyproject.toml ([ocaml] extra + all + dev dep), and
README. Adds tests/test_ocaml.py (behind importorskip).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 14:17:07 +01:00
safishamsiandClaude Opus 4.8 7fe58b0b0f docs(changelog): add #2463/#2466/#2465/#2453/#2449/#2408 to the 0.9.42 section
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v0.9.42
2026-08-13 14:33:56 +01:00
safishamsiandClaude Opus 4.8 40316d19e7 docs(detect): cross-link _MTIME_COARSE_S to cache.py's granularity constant (#2466/#2612)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-13 14:21:56 +01:00
Kai a2a9137d05 fix(detect): re-queue a same-tick same-length rewrite in incremental runs (#2466) 2026-08-13 14:21:22 +01:00
Kai c1f39954e3 fix(detect): skip non-regular files so a FIFO can't hang extraction (#2463) 2026-08-13 14:20:36 +01:00
Aryan 48fbe30ebc fix(build): exclude global MCP ids from legacy-id detection (#2408) 2026-08-13 14:17:42 +01:00
JAESOL SHIN a4e8446479 fix(html): trace hyperedge perimeter in convex-hull order (#2449) 2026-08-13 14:17:42 +01:00
Benjamin S. Leveritt 613c45cc7e fix(install): make the staged skill bundle writable so a read-only package installs (#2453) 2026-08-13 14:17:42 +01:00
Kai 5e4ab1dfa0 fix(manifest): capture package version in the apm.yml fallback parser (#2465) 2026-08-13 14:17:41 +01:00
safishamsiandClaude Opus 4.8 ded1feb88a chore: bump to 0.9.42
Correctness (#2685 loop-binding shadow, #2699 provenance, #2707 affected
seed, #2688 py subpackage imports, #2602 sql grammar, #2683 cache
integrity, #2682 report basename) + Windows portability/docs batch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-13 13:36:32 +01:00
Ousama Ben Younes b3ca490408 fix(report): use a portable basename in the GRAPH_REPORT header (#2682) 2026-08-13 13:30:24 +01:00
Ousama Ben Younes 5d8d6113db fix(cache): surface corrupt semantic cache entries instead of silently missing (#2683) 2026-08-13 13:30:24 +01:00
Ousama Ben Younes a30b56e2df fix(sql): distinguish a broken tree-sitter-sql grammar from a missing one (#2602) 2026-08-13 13:30:24 +01:00
Ousama Ben Younes 51cf1481b6 fix(python): resolve relative subpackage imports to their __init__ (#2688) 2026-08-13 13:30:24 +01:00
phudayyy a05b4084d9 fix(affected): resolve a seed given as ./relative or absolute path form (#2584 follow-up) 2026-08-13 13:30:24 +01:00
C0KERNEL cc0ee60c40 fix(export,cli): stamp graph provenance from the analysed repo, not the shell cwd (#2534 family) 2026-08-13 13:30:24 +01:00
Ousama Ben Younes a995921026 fix(js): shadow for...of / for...in loop bindings from indirect_call args (#2568 family) 2026-08-13 13:30:24 +01:00
rajashidattapy c1e41ea90e docs: refresh ARCHITECTURE.md module table + add a doc-parity test (keeps the #2558 'an' fix) 2026-08-12 20:57:39 +01:00
nelsondeleonc-source 39beeb9b4b docs: fix article typo (an extract_<lang>) in ARCHITECTURE.md 2026-08-12 20:56:28 +01:00
Redzwan Mutalib 28aaf20197 docs: document Windows test prerequisites in the README 2026-08-12 20:56:28 +01:00
Redzwan Mutalib 6b40338d96 docs: document CI parity checks in the README 2026-08-12 20:56:28 +01:00
rajashidattapy 5cc20a4811 test: skip the unreadable-dir detect test on non-POSIX / as root 2026-08-12 20:56:28 +01:00
rajashidattapy cdf1f65656 test: probe-and-skip symlink tests where symlink creation is unavailable (#2642) 2026-08-12 20:56:28 +01:00
rajashidattapy 243f3e32c1 test(hooks): stop argv mangling the shell-arg verdict test on Windows (#2126) 2026-08-12 20:56:28 +01:00
rajashidattapy 0df2a701a5 fix(paths): clear read-only bit before unlinking the atomic-write temp on Windows (#2622) 2026-08-12 20:56:28 +01:00
rajashidattapy 1aab181d15 test: Windows path portability in tests; llm emits POSIX source_file to the model (#2620) 2026-08-12 20:56:28 +01:00
safishamsiandClaude Opus 4.8 e4bfd2ad1a docs(changelog): add #2663/#2601/#2661/#2457/#2674 to the 0.9.41 section
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v0.9.41
2026-08-12 14:22:46 +01:00
Arthuro0103 ee2fbf954b fix(benchmark): guard against a node with a None label (#2674) 2026-08-12 14:20:21 +01:00
rohit-jsfreaky 8be72ef7bf fix(js): stabilize unresolved local import target ids (#2457) 2026-08-12 14:20:21 +01:00
Ben Younes c285a94d45 fix(extract): resolve prefixed PHP use-imports to their target (#2661) 2026-08-12 14:20:21 +01:00
Ben Younes b645a3a7f1 fix(serve): suppress the query truncation banner when no nodes were cut (#2601) 2026-08-12 14:20:21 +01:00
Ben Younes 4730ed9abb fix(watch): refuse a shrink caused by an extractor failure during update (#2663) 2026-08-12 14:20:21 +01:00
safishamsiandClaude Opus 4.8 26c034a696 docs(changelog): add #2627/#2632/#2635/#2634 to the 0.9.41 section
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-11 20:11:19 +01:00