Skip to content

Resync Rust port to graphify-py v0.8.44 (dce54a0)#23

Merged
rblaine95 merged 7 commits into
masterfrom
resync/graphify-py/dce54a0
Jun 20, 2026
Merged

Resync Rust port to graphify-py v0.8.44 (dce54a0)#23
rblaine95 merged 7 commits into
masterfrom
resync/graphify-py/dce54a0

Conversation

@rblaine95

@rblaine95 rblaine95 commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

Resyncs the Rust port with graphify-py at dce54a0 (v0.8.39 -> v0.8.44),
porting the new behavior from the upstream delta and auditing every changed
module for parity.

Commits

  • f04dab4 Update graphify-py submodule to dce54a0
  • eb5e8c9 Bump hk to 1.48.0
  • 4d9363b Resync with graphify-py @ dce54a0 (the port)
  • 63bb519 Persist manifest on no-cluster extraction (audit fix)
  • df01382 Fix string community rendering and dedup keys (review fixes)

Ported behavior (highlights)

Extraction:

  • Node-id unification across extract, bash, and MCP ingest (#1378)
  • JS member-assignment targets (#1323) and workspace / pnpm globs (#1352)
  • Java records, object_creation, and type resolution (#1373)
  • Swift member calls and module anchors (#1356)
  • Markdown link resolution (#1376)
  • PowerShell .psd1 / .psm1 manifest handling (#1331 / #1341)

Build / dedup / detect:

  • dedupe_nodes / dedupe_edges for the --no-cluster and update raw
    write paths (#1317 / #1327)
  • source_file backfill (#1279) and build_merge source pruning
    (#1344 / #1361 / #1366)
  • Fuzzy-merge guards: numeric-token divergence, cross-file file-anchored
    block, Jaro tiebreak (#1284 / #1243)

LLM:

  • Custom OpenAI-compatible endpoints (#1273)
  • 16k output-token cap across backends (#1365)
  • Non-dict response guard (#1357), label split-and-retry (#1278), and
    oversized-document slicing (#1369)

Serve / export / hooks:

  • community_name display with numeric fallback (#1305)
  • find_node tokenized matching (#1353) and the --graph flag (#1304)
  • Hooks reject Windows hooks paths resolved outside the repo (#1385)

Audit fixes

  • Manifest on --no-cluster: the no-cluster branch returned before
    persist_manifest, so repeat --no-cluster / update runs fell back to a
    full rescan. It now writes the manifest like graphify-py; re-extraction
    output stays byte-identical.
  • String community rendering: community_label JSON-serialized the
    value, quoting a string community id ("7" instead of 7); it now mirrors
    Python str() via an as_i64 -> as_str -> to_string fallback.
  • Dedup keys: switched the internal dedup keys from Value::to_string to
    as_str (identical dedup classes for the string ids that always occur, no
    surprising quoted keys).
  • Label split test: tightened to assert the exact 3-call split path
    (1 failed full batch + 2 successful halves).

Documented divergences (not gaps)

  • tree_html escapes </, U+2028, U+2029 (security-equivalent to Python
    ensure_ascii=True; renders identically).
  • normalize_id / affected use to_lowercase vs Python casefold
    (consistent codebase convention).
  • serve / mcp is --graph-flag-native (no positional graph path).

Verification

  • cargo nextest run --workspace: 2066 passed, 2 skipped (network-gated
    net_ tests).
  • cargo clippy --all-targets --all-features --workspace: clean.
  • cargo fmt --check: clean.
  • CodeRabbit (--base master): two rounds; the second returned 0 findings.

Summary by CodeRabbit

  • New Features

    • Detect package manifests (APM, Python, Go, Maven) and extract dependency relationships; also extract PowerShell .psd1 module dependencies.
    • Add reference edges from Markdown links.
    • Export human-readable community names in generated graphs.
    • Automatically slice large text inputs for LLM processing.
  • Enhancements

    • Improve PowerShell import/dot-sourcing parsing.
    • Enhance Swift imports/member-call and Java type resolution across files.
    • Support self-hosted OpenAI/Anthropic endpoints via environment variables.
    • Reduce duplicate nodes/edges during incremental/no-cluster rebuilds; improve Unicode label matching.
  • Bug Fixes

    • Strengthen HTML escaping and provide clearer errors for Windows-style hooks paths.
  • Documentation

    • Update README/USAGE with manifest/link semantics and environment variable details.

Update the pinned `hk` version in `mise.toml` and the `amends`/`import`
package URLs in `hk.pkl` from `1.46.0` to `1.48.0` so the pre-commit
hook runner and its config schema stay in lockstep on the upstream
release.

Glory to the Omnissiah
Port the v0.8.40-0.8.44 behavior changes from the `graphify-py`
submodule (`c4689a2..dce54a0`) across the Rust workspace, preserving
behavioral parity with the Python reference.

Ports:

- extract: JS/TS assignment-form symbols, package.json workspace
  imports, Java records + `object_creation` constructor calls +
  cross-file type-reference resolution, Swift module anchors +
  cross-file member-call resolution, Markdown link edges, PowerShell
  `.psm1`/`.psd1` imports, package-manifest ingestion, and node-id
  unification via `build::normalize_id`
- build: `dedupe_nodes`/`dedupe_edges`, ambiguous ghost-merge skip,
  edge `source_file` backfill, `build_merge` stale-source pruning
- dedup: plain-Jaro scoring for cross-file long labels, numeric-token
  and cross-file file-anchored merge guards
- llm: `OPENAI_BASE_URL`/`OPENAI_MODEL` and `ANTHROPIC_BASE_URL`/
  `ANTHROPIC_MODEL` endpoints, openai output-token cap, non-dict
  `parse_llm_json` guard, `label_communities` split-and-retry, and
  `file_slice` oversized-document slicing
- detect: `.psm1`/`.psd1` extensions, package-manifest classification,
  and merged `.gitignore` + `.graphifyignore` loading
- export: `community_name` in `to_json`, `to_canvas` fallback community
- serve: `community_name` preference in node and subgraph rendering
- hooks: reject Windows-style git hooks paths
- affected: NFC-normalize `resolve_seed`
- watch: dual-root changed-path resolution, no-cluster dedup
- html: escape U+2028/U+2029 in the tree-html script island
- cli: `explain`/`cluster-only` `community_name`, custom-endpoint help

Bump the workspace version to 0.8.44 and reconcile README.md and
USAGE.md.

Glory to the Omnissiah
`graphify extract --no-cluster` returned before `persist_manifest` ran,
so `manifest.json` was never written and every later `--no-cluster` or
`update` run fell back to a full rescan instead of the incremental path.
graphify-py saves the manifest in this branch too (`__main__.py:4492`).

Call `persist_manifest` in the `no_cluster` branch. Output stays
byte-identical: the incremental re-extract walks the same
deterministically sorted changed-plus-unchanged union as a full scan, so
a no-op re-run reproduces graph.json exactly. The no-op parity test now
also asserts `manifest.json` is created.

Glory to the Omnissiah
CodeRabbit review findings on the resync diff.

`community_label` fell back to `to_string` on the `community` value,
which JSON-serializes it: a community stored as a string rendered with
surrounding quotes instead of matching Python's `str(...)`. Fall back
through `as_i64`, then `as_str`, then `to_string` so numeric and string
community ids both render unquoted, and add a parity test for the
string case.

`dedupe_nodes` and `dedupe_edges` built their internal dedup keys with
`to_string`, yielding quoted keys. Node ids and edge endpoints are
always strings, so switch to `as_str`: identical dedup classes and
byte-identical output, without the surprising keys.

Tighten the label split-retry test to assert exactly 3 calls (one
failed full batch plus two successful halves) instead of `>= 2`, so a
regression that skipped the split would now fail.

Glory to the Omnissiah
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 036dcfca-5684-434b-a618-d938ac742382

📥 Commits

Reviewing files that changed from the base of the PR and between df01382 and babd875.

📒 Files selected for processing (15)
  • .github/workflows/test.yml
  • crates/graphify-affected/src/lib.rs
  • crates/graphify-affected/tests/parity.rs
  • crates/graphify-detect/src/ignore.rs
  • crates/graphify-export/src/json.rs
  • crates/graphify-extract/src/extractors/markdown.rs
  • crates/graphify-extract/src/extractors/multi.rs
  • crates/graphify-extract/src/generic/js_extra.rs
  • crates/graphify-extract/src/workspace.rs
  • crates/graphify-extract/tests/id_normalization_contract.rs
  • crates/graphify-extract/tests/js_workspace_resolution.rs
  • crates/graphify-extract/tests/markdown_links.rs
  • crates/graphify-extract/tests/powershell_imports.rs
  • crates/graphify-hooks/src/git.rs
  • crates/graphify-hooks/tests/parity.rs
💤 Files with no reviewable changes (1)
  • crates/graphify-extract/tests/id_normalization_contract.rs
🚧 Files skipped from review as they are similar to previous changes (12)
  • crates/graphify-extract/tests/markdown_links.rs
  • crates/graphify-extract/tests/powershell_imports.rs
  • crates/graphify-affected/tests/parity.rs
  • crates/graphify-hooks/tests/parity.rs
  • crates/graphify-detect/src/ignore.rs
  • crates/graphify-export/src/json.rs
  • crates/graphify-extract/src/extractors/markdown.rs
  • crates/graphify-hooks/src/git.rs
  • crates/graphify-affected/src/lib.rs
  • crates/graphify-extract/src/generic/js_extra.rs
  • crates/graphify-extract/src/workspace.rs
  • crates/graphify-extract/src/extractors/multi.rs

📝 Walkthrough

Walkthrough

This PR updates graph extraction, merge/export, LLM processing, hooks validation, HTML escaping, docs, tests, and version metadata.

Changes

Platform metadata and docs

Layer / File(s) Summary
Release metadata and docs
Cargo.toml, README.md, USAGE.md, mise.toml, graphify-py, src/cli/args.rs
Workspace and tool versions were updated, the Python submodule pointer changed, and docs/help text now describe manifest ingestion, document links, and OpenAI/Anthropic-compatible backend variables.

Graph core, export, serving, and rebuild behavior

Layer / File(s) Summary
Graph normalization and deduplication
crates/graphify-affected/..., crates/graphify-dedup/..., crates/graphify-detect/...
Unicode-normalized seed matching, numeric and cross-file dedup guards, package-manifest classification, and merged ignore-file semantics were added with regression tests.
Merge, export, serving, and rebuild updates
crates/graphify-build/..., crates/graphify-export/..., crates/graphify-serve/..., crates/graphify-watch/..., src/cli/{cluster_only,query}.rs, tests/{cli,cli_commands,cli_export}.rs
Build and watch flows now dedupe nodes and edges, replace stale contributions for re-extracted sources, preserve ambiguous ghost cases, export community labels, and render them in CLI/server output.

Extraction coverage and normalization

Layer / File(s) Summary
Manifest, Markdown, and PowerShell extraction
crates/graphify-extract/src/extractors/{manifest_ingest,markdown,powershell,mod,multi}.rs, crates/graphify-extract/tests/{manifest_ingest,markdown_links,powershell_imports}.rs
Extraction now ingests package manifests, emits Markdown document references, parses PowerShell imports and .psd1 manifests, and routes those inputs through the multi-extractor pipeline.
Java, Swift, and JS cross-file resolution
crates/graphify-extract/src/{generic/*,import_handlers.rs,lang_configs.rs,extractors/multi.rs}, crates/graphify-extract/tests/{java_type_resolution,swift_imports,swift_member_calls,js_assignment_forms}.rs
Java records and constructor calls, Swift module anchors and member-call inference, and JS assignment-form method extraction were added or expanded with cross-file resolution tests.
ID normalization, raw calls, workspace cache, and extractor caching
crates/graphify-extract/src/{ids.rs,types.rs,workspace.rs,postprocess.rs,extractors/*}, crates/graphify-extract/tests/{id_normalization_contract,js_workspace_resolution,parity_postprocess}.rs
Raw calls now carry an optional receiver, ID generation uses shared normalization, workspace package caching uses manifest-aware keys and is cleared per run, and JS/TS AST cache bypass rules were added.

LLM pipeline

Layer / File(s) Summary
Backend defaults and parse recovery
crates/graphify-llm/src/{backends,openai,claude,call,parse,labeling}.rs, crates/graphify-llm/tests/{custom_endpoint,labeling,parity}.rs
OpenAI and Claude backends now honor additional base URL/model env vars, default model lookup was centralized, top-level non-object JSON is ignored, and label generation retries by splitting batches on parse failures.
Unit slicing and unit-aware extraction flow
crates/graphify-llm/src/{file_slice,extract,parallel,read,retry,tokens,vision,lib}.rs, crates/graphify-llm/tests/file_slice.rs
Oversized text files can be split into units and those units now flow through reading, token packing, vision partitioning, adaptive retry, direct extraction, and parallel extraction paths.

Safety fixes

Layer / File(s) Summary
Hooks path validation and HTML escaping
crates/graphify-hooks/..., crates/graphify-html/...
Git hook installation now rejects Windows-style hook paths on POSIX/WSL paths, and embedded tree HTML escapes </, U+2028, and U+2029 in inline script JSON.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • bunkerlab-net/graphify#12: Also changes crates/graphify-build/src/build_fn.rs merge behavior and source-file normalization paths.
  • bunkerlab-net/graphify#21: Also touches resolve_seed behavior in crates/graphify-affected and build ghost-duplicate handling.

Poem

🐇 I hopped through manifests and links,
and tucked new nodes where Markdown thinks.
Swift and Java joined the trail,
while LLM slices kept their scale.
The hooks stood firm, the scripts stayed tame—
a tidy graph by rabbit name.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: resyncing the Rust port to graphify-py v0.8.44 with explicit version numbers, making the primary objective immediately apparent.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as resolved.

Resolve the still-valid CodeRabbit findings from the resync review;
the rest were verified as parity-intentional and left in place.

Add the accented-query assertion to the accent-distinction parity
test (`resolve_seed_preserves_distinct_accents`) so both sides of the
distinction are covered, not just the unaccented query.

Correct the `.gitignore` plus `.graphifyignore` merge comment in
`ignore.rs`. It claimed a `.graphifyignore` can only ever exclude
more and never re-enable a `.gitignore`-excluded file, which
contradicts the documented `!`-negation last-match-wins behavior:
a negation does re-enable, subject to the parent-directory
exclusion rule.

Mark the pure owned-returning helpers `normalize_label`, `bare_name`,
`build_node_link_nodes`, `resolve_markdown_link`, `lexical_normalize`,
and `js_member_assignment_target` `#[must_use]`.

Drop the blanket `expect_used`/`unwrap_used` allows from the
`id_normalization_contract`, `js_workspace_resolution`,
`markdown_links`, and `powershell_imports` extract tests (none are
`parity.rs`). The first two had no `unwrap`/`expect` left; convert
the others to `?`.

Glory to the Omnissiah
Resolve two genuine bugs surfaced by review and document one
non-issue in the code.

`find_workspace_root` accepted any present `workspaces` key via
`.is_some()`, but `workspace_globs` only consumes a string array or a
`{ packages: [...] }` object. A nested `package.json` with a malformed
`workspaces` (null, a string, or an object without `packages`) thus
shadowed a real workspace root higher up the tree and resolved to zero
globs, so the package import silently fell back to a bare-module hash.
Validate the shape in `find_workspace_root` so the walk only stops at a
manifest `workspace_globs` can actually use. Add a regression test.

`reject_windows_path` unconditionally rejected drive-letter and
backslash paths, but on native Windows those are valid absolute paths
that `create_dir_all` resolves. Gate the check with
`#[cfg(not(windows))]` so it still fails loudly on POSIX/WSL (where the
path cannot resolve) but accepts valid paths on Windows. Gate the
matching parity test (and its `walk_all` helper) to non-Windows.

Document in `multi.rs` why the Swift AST `receiver` field needs no
cache bypass or schema-version check: the AST cache is namespaced by
crate version, so pre-`receiver` entries are never loaded.

Glory to the Omnissiah
@rblaine95 rblaine95 force-pushed the resync/graphify-py/dce54a0 branch from dc288e5 to babd875 Compare June 20, 2026 18:23
@rblaine95 rblaine95 merged commit 15287c5 into master Jun 20, 2026
14 checks passed
@rblaine95 rblaine95 deleted the resync/graphify-py/dce54a0 branch June 20, 2026 18:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant