graphify 0.9.104
- Security: skill the
/graphifyrunbook no longer substitutes the scan path into Python code. Every generated code block (detect, AST and semantic extraction, build, diagnose, label, manifest, and--update) now reads the resolved scan root from the trustedgraphify-out/.graphify_rootsidecar that Step 1 writes through a quoted heredoc, instead of pasting the agent-supplied path into a string literal. A directory whose name carried a quote or$(...)could previously break out ofPath('INPUT_PATH')and run as code; it is now read as inert data. Covers the assembled hosts and the Aider/Devin monoliths (#4762, thanks @danikdanik). - Fix: solidity a call on a receiver of a contract or interface type (
IERC20 token; token.transfer(),IERC20(a).transfer(),token().balanceOf()) binds by name and arity through that type's linearization to the type's own declaration, instead of producing no edge; gated to a single visible contract/interface and fail-closed on an unknown or ambiguous type (#5060, thanks @rohit-jsfreaky). - Fix: solidity a call attached by a
using A for Tdirective (using SafeCast for uint256; x.toUint48()) binds to the library or free function it attaches, matched by the receiver's type and an arity one greater than the call; fail-closed when the receiver type is unknown, the library is ambiguous, or two functions fit (#5062, thanks @rohit-jsfreaky). - Fix: solidity members, free functions and types in one scope whose names differ only by a leading
_or by case (_grantRole/grantRole) get separate node ids, so the_symbol no longer vanishes into its twin and its calls land on the right node (#5027, thanks @rohit-jsfreaky). - Fix: csharp a constructor (instance, static or primary) is its own node owned by its type, with its body and
: base(...)/: this(...)calls credited to it;new X(...),: base(...)and: this(...)additively link the arity-correct overload, and two fitting overloads or an unresolved base give no constructor edge (#5054, thanks @rohit-jsfreaky). - Fix: csharp calls inside a property or indexer accessor, an expression body, or an operator/conversion body are credited to that member instead of being lost; an indexer becomes a
this[]node and an operator a.operator +()node (#5056, thanks @rohit-jsfreaky). - Fix: query a same-label node that is the only match for a query term is kept as a seed instead of being dropped by the per-label cap, so every distinct term keeps at least one seed while generic-label flooding stays capped (#5027, thanks @Vaibhav2824).
- Fix: watch read-only events are kept out of the inotify mask via a change-only
event_filter, so a large tree no longer drives watchdog into a self-sustaining queue-overflow loop; falls back with a warning on watchdog versions withoutevent_filtersupport (#5033, thanks @Deepjyoti-Sarmah). - Fix: cache the
\\?\long-path spelling is kept out of cache identity, so the same file reached through\\?\C:\...andC:\...shares one entry; also fixes empty stat-index writes under UNC shares, a spurious "stat index switched" warning on Windows, and a junction/symlink alias wrongly sharing its target's digest (#5035, thanks @Bortlesboat). - Fix: cache stat-index keys stay root-relative under a Windows long-path root, so a moved or cloned corpus keeps the portable-key fastpath (#5035, thanks @Vaibhav2824).
- Fix: tests the TypeScript unicode fixture is written as UTF-8 on every platform, so byte offsets match the extractor on Windows (cp1252) hosts (#5064, thanks @ayushcodes10).
- Fix: tests the hook-freshness source mock is normalized through
os_long_path, so the read-error/stale branch is actually exercised on Windows (#5065, thanks @ayushcodes10). - Fix: tests the watch pending-queue test compares
Pathobjects so/and\separators compare equal on Windows (#5039, thanks @Yi-111-a). - Fix: extract an ambiguous Python import's placeholder node id is hashed from checkout-independent data (module name, scan-root-relative source file, location) instead of the absolute path, so the same project at a different path or a moved cache gets the same ids (#5045, thanks @Fardin7798).
- Fix: yaml a template using CloudFormation intrinsic tags (
!Ref,!GetAtt,!Sub) no longer fails to parse: a scoped permissive loader rebuilds each!-tagged node's shape without evaluating it, while!!python/...tags still raise and never execute (#5077, thanks @ayushcodes10). - Fix: watch a
--watchincremental update rebuilds the full corpus whengraph.jsonis missing, instead of writing a partial graph from the manifest alone (#5020, thanks @azizur100389). - Fix: watch a change to a JS/TS resolution input (
tsconfig.json,jsconfig.json, a lockfile) triggers a full rebuild so importers pick up the new resolution, instead of leaving staleimports_fromedges (#5020, thanks @azizur100389). - Fix: ingest two concurrent
graphify addcaptures for the same URL no longer clobber each other: the capture file is created exclusively (O_EXCL) and a collision retries a fresh name, with the payload fetched once (#5020, thanks @azizur100389). - Fix: reflect a malformed entry in the learning overlay is skipped instead of crashing the whole load, and a legacy null-source entry is preserved as a source-less annotation (#5020, thanks @azizur100389).
- Fix: global a malformed repo entry in the global manifest is dropped on its own, keeping the other tracked repos, and only a non-object root or repos map is backed up and reset (#5020, thanks @azizur100389).
- Fix: query a graph freshly built on a subfolder is no longer flagged as a pre-#1504 build (which nagged a no-op
extract --force): the legacy-id probe strips the.graphify_rootoffset before deriving file stems, and a genuine legacy graph is still caught (#5019, thanks @neumannpeter1231-lang). - Fix: tree
graphify export treerecognises thesrcnode alias (andfile/path/filepath) so a graph carrying those keys renders a populated tree instead of an empty one; a concept-only graph still reports empty (#5030, thanks @Adityakk9031). - Fix: cli
graphify provider addaccepts--pricing-input=VALUE/--pricing-output=VALUEequals-syntax and rejects a non-numeric, non-finite or negative price with a clean error instead of a traceback or a poisoned cost estimate (#5031, thanks @Adityakk9031).
The AST cache schema is bumped to 40; warm caches re-run the affected Solidity and C# extractions. The Python and YAML fixes above need no bump (placeholder ids are resolved after the per-file cache, and previously-failing YAML was never cached).