Skip to content

[pull] v8 from safishamsi:v8#95

Merged
pull[bot] merged 10 commits into
miqdigital:v8from
safishamsi:v8
Jun 29, 2026
Merged

[pull] v8 from safishamsi:v8#95
pull[bot] merged 10 commits into
miqdigital:v8from
safishamsi:v8

Conversation

@pull

@pull pull Bot commented Jun 29, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

safishamsi and others added 10 commits June 29, 2026 09:24
These were committed before .gitignore included the .DS_Store rule, so
gitignore never removed them from tracking. Untrack them (they remain
on local disk, just leave git) — the existing .gitignore rule keeps
them out going forward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#1499)

Resolve Ruby `obj.method()` calls by the inferred type of the receiver
instead of by globally-unique method name. `p = Processor.new; p.run`
now emits a `calls` edge to `Processor#run` and survives name collisions
with unrelated `Worker#run` definitions, where the old name-based match
either resolved by luck or dropped the edge as ambiguous.

Introduces graphify/resolver_registry.py, a behavior-identical
formalization of the existing tail-of-extract() language resolution
passes (Swift #1356, Python #1446 become registered entries), and
graphify/ruby_resolution.py, its first new consumer. Receiver type is
inferred only from unambiguous local `var = ClassName.new` bindings;
ambiguous or unknown receivers resolve to nothing (no false positives).

Note: Ruby member calls are now excluded from name-based cross-file
resolution and resolved by inferred type only. This is an intentional
precision-over-recall change scoped to Ruby: a cross-file `var.method`
whose receiver type cannot be proven from a local `X.new` binding no
longer resolves by name-luck (it produces no edge rather than a possibly
wrong one), matching the project's confidence model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_call_llm (used by the dedup LLM tiebreaker) built its Anthropic and
OpenAI-compatible clients with max_retries but no timeout, so requests
on this path silently ignored GRAPHIFY_API_TIMEOUT — unlike the primary
extraction paths (_call_openai_compat / _call_claude) which already pass
both. Add timeout=_resolve_api_timeout() to both constructors.

The PR branch self-neutralized: a v8 merge resolved the conflict in
favor of the max_retries-bearing line and dropped the original one-line
fix, so it is re-applied here on top of current v8 with max_retries
preserved. Adds regression coverage for both _call_llm branches, which
were previously untested.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le (#1502)

Two cross-platform fixes salvaged from #1502:

- to_graphml: nx.write_graphml raises ValueError on None attribute
  values, so a node/edge carrying a null field crashed the export.
  Coerce None -> "" for node and edge attributes before writing.

- save-result: add --answer-file as an alternative to --answer so long
  or multiline answers can be passed via a file instead of a fragile
  inline shell arg (notably Windows/PowerShell quoting). Exactly one of
  --answer / --answer-file is required.

The rest of #1502 (a version downgrade and a hand-edited generated
skill-windows.md that fails skillgen --check, plus duplicated
windows-scripts) is left for rework on the PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generated install/skill guidance told agents to invoke a literal `skill`
tool with `skill: "graphify"`, which is host-specific and not valid in
every environment. The always-on AGENTS fragment, packaged artifact,
expected snapshot, and _skill_registration() output now use host-generic
wording: "use the installed graphify skill or instructions". Also decodes
skillgen git blob reads as UTF-8 for Windows and replaces stale English
code-block examples in the translated READMEs.

The always-on roundtrip guard deliberately freezes the v8 baseline, so an
intentional wording change would otherwise fail it. Rather than only
patching the pytest mirror (which left the blocking CLI guard
--always-on-roundtrip red, as the original PR did), this adds an explicit,
reviewable ALWAYS_ON_SANCTIONED_EDITS registry: the guard applies the
approved old->new substitution to the baseline before the byte-for-byte
compare, so this exact sentence is allowed while any other drift still
fails. CLI guard and pytest test now agree and CI passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bot)

Resolve two Dependabot alerts in transitive deps:

- msgpack 1.1.2 -> 1.2.1 (HIGH, GHSA-6v7p-g79w-8964): out-of-bounds
  read / crash on Unpacker reuse after a caught error. Pulled only via
  cachecontrol -> pip-audit (dev group), so not in the published wheel's
  closure, but a fix is available so we take it.
- pydantic-settings 2.14.1 -> 2.14.2 (MEDIUM, GHSA-4xgf-cpjx-pc3j):
  NestedSecretsSettingsSource follows symlinks outside secrets_dir.
  Pulled via mcp (the [mcp]/[all] extra); graphify does not use the
  affected secrets-dir source, but the fix is free.

Lockfile-only; both are transitive. Full suite green (2537 passed),
MCP/serve tests pass on the bumped versions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`safety` was declared in the dev group but never invoked — the CI
security-scan job only runs bandit and pip-audit, and pip-audit already
provides the same dependency-CVE scanning. Its only practical effect was
pulling in nltk, which carries an unpatched HIGH path-traversal advisory
(GHSA-p4gq-832x-fm9v) with no fix available.

Removing safety drops nltk (and safety-schemas/typer/tenacity/tomlkit)
from the lockfile entirely, closing the alert with no loss of coverage.
Updated the stale CI comment that referenced safety. Full suite green
(2537 passed); pip-audit and bandit unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fallbacks (#1529, #1531)

#1529 (regression from the 0.9.0 full-repo-relative node-ID migration):
relative JS/TS imports resolve to repo-relative paths and ride the
extract() id-remap to canonical node IDs, but tsconfig path-alias and
workspace-package imports resolve to ABSOLUTE paths (their bases are
.resolve()'d), so the import-target ID baked in the on-disk prefix and
never matched the repo-relative definition node — the edge was dropped at
build (common on Next.js/SvelteKit `@/`-alias codebases). The id-remap
post-pass now also registers the absolute-resolved form of each input
path (file-level edges) and both the input-form and absolute-form symbol
prefixes (named-import edges), so alias/workspace import targets remap to
the canonical ID. Verified the built graph has no orphan nodes or
dangling edges.

#1531: tsconfig `paths` values are ordered fallback lists (tsc tries each
target until one resolves), but only targets[0] was kept. The alias map
now stores all targets in order, and a single _resolve_tsconfig_alias
helper (replacing six duplicated inline loops) returns the first target
whose candidate exists on disk, falling back to the first candidate when
none exist (no false edge). Wildcards, baseUrl, and array `extends` are
preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

The AST cache is version-swept but the semantic/LLM cache had no pruning,
so it grew unbounded: it is content-hash-keyed, so every content change
or file deletion leaves a permanent orphan entry (reporter saw 152
entries for 124 live docs). This matters for the committed-cache workflow
where the semantic cache is published for warm CI rebuilds.

Adds prune_semantic_cache(root, live_hashes) and wires it into the end of
the extract path, sweeping cache/semantic/*.json entries whose hash is not
in the live set. The live set is computed from the FULL detected document
set (not the incremental changed-subset, which would delete valid
entries), using the same file_hash recipe save_semantic_cache uses.
Best-effort (unlink guarded), only touches cache/semantic/ (.tmp and
cache/ast/** untouched), and keeps the semantic cache unversioned so
releases never re-bill LLM extraction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orts map (#1308)

Workspace imports with subpath exports (e.g.
`import { x } from "@scope/pkg/browser"`) now resolve through the
package's `exports` map instead of falling back to a bare path. Supports
string values, condition objects, nested conditions, and single-`*`
wildcard patterns (`"./*": "./src/*.js"`), falling back to the existing
bare-path/index resolution when there is no exports map or no match.

Adapted from #1541, taking only the exports-map resolver and not that
PR's competing import-node-ID normalization (current v8 already resolves
the node-ID mismatch via the #1529 id-remap post-pass, and the PR's
_file_stem approach regressed the relative-input alias case). Two
hardening changes over the original:
- `default` is consulted LAST in the condition priority (it is Node's
  catch-all), so a matching `import`/`module`/`svelte` condition wins.
- Export targets that escape the package directory are rejected
  (`_contained_in_package`), so a malicious `exports` value like
  `"./x": "../../../etc/..."` cannot resolve to a file outside the package.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Jun 29, 2026
@pull pull Bot added the ⤵️ pull label Jun 29, 2026
@pull pull Bot merged commit e8dabad into miqdigital:v8 Jun 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants