Skip to content

feat: NeuG embedded graph DB, Cypher CLI, and GDS Leiden clustering (opt-in) - #2895

Open
BingqingLyu wants to merge 1 commit into
Graphify-Labs:v8from
BingqingLyu:neug-leiden-integration
Open

feat: NeuG embedded graph DB, Cypher CLI, and GDS Leiden clustering (opt-in)#2895
BingqingLyu wants to merge 1 commit into
Graphify-Labs:v8from
BingqingLyu:neug-leiden-integration

Conversation

@BingqingLyu

@BingqingLyu BingqingLyu commented Aug 20, 2026

Copy link
Copy Markdown

Summary

  • Add NeuG as an optional parallel graph storage engine alongside NetworkX, with native Cypher query support via CLI (graphify cypher) and MCP server (cypher_query tool)
  • Native incremental update via Cypher MERGE — O(delta) vs NetworkX's O(full graph) rebuild
  • GDS Leiden community detection via NeuG's native extension framework — runs clustering directly on graph.db
  • Incremental community detection via freeze-assignment Leiden — existing nodes' communities stay frozen, only new nodes get assigned; makes incremental impact visible for targeted wiki regeneration
  • delta-cluster: incremental community analysis command; --baseline seeds from an external clustering
  • Opt-in by design: enabled via GRAPHIFY_NEUG=1 or an existing graph.db; the default extract path is unchanged

Motivation

Graphify currently uses NetworkX + graph.json as its core graph storage. This architecture has bottlenecks:

  • Limited query capability: No declarative graph query language — only Python API traversal
  • Inefficient incremental updates: Every update requires loading full graph.json → merge → rebuild → re-serialize (O(full graph) even for single-file changes)
  • Performance ceiling at scale: Entire graph must be loaded into memory; NetworkX's pure-Python execution becomes a bottleneck on large graphs
  • Limited graph algorithm extensibility: Adding custom graph algorithms requires Python-level implementation with no native acceleration path
  • No incremental community detection: Existing Leiden/Louvain requires full re-clustering on every change, shifting existing nodes' assignments and obscuring what actually changed — forcing expensive full wiki regeneration instead of targeted updates

Why NeuG?

NeuG is a lightweight embedded graph database (C++ core, Python bindings):

  1. Native Cypher support — Declarative graph query language; AI agents can query the knowledge graph directly without custom Python code
  2. Native incremental updates — Cypher MERGE enables O(delta) upserts in-place, no full-graph reload needed; for 10K+ node graphs, single-file updates are near-instantaneous
  3. Battle-tested performance — LDBC benchmark world record holder; lightweight & embeddable (no standalone server, pip install neug is all it takes)
  4. Extensible graph algorithms — Native C++ extension framework for custom graph algorithms; Louvain/Leiden community detection already available, with more algorithms (PageRank, etc.) in development — can replace the current Python-based algorithm layer with significant performance gains
  5. Incremental Leiden via freeze-assignment — NeuG's GDS extension freezes existing nodes' communities and only assigns new nodes, preserving clustering stability and making incremental wiki impact visible: added files → affected communities → chapters to regenerate

Architecture

Dual-engine coexistence, each independently consuming extraction data:

extraction dict ──┬──> NetworkX (build.py)  → graph.json  (existing, default)
                  └──> NeuG (storage.py)    → graph.db    (opt-in)

When GRAPHIFY_NEUG=1 is set (or graph.db already exists), the NeuG pipeline also runs:

  • Ingests data into graph.db via COPY FROM (bulk) or MERGE (incremental)
  • Runs GDS Leiden clustering natively on graph.db
  • Exports graph.json from graph.db (not dual-write) — ensures downstream tools (wiki generation, HTML visualization, community labeling) continue to work unchanged, maintaining full backward compatibility

Changes

File Description
graphify/storage.py New — NeuG adapter layer (init, schema, ingest via COPY FROM/MERGE, query, close, community detection via GDS Leiden)
graphify/cli.py NeuG opt-in probe, GDS Leiden clustering path, delta-cluster subcommand, segfault guard for tiny graphs
graphify/__main__.py graphify cypher CLI command
graphify/serve.py cypher_query MCP tool for AI agents
graphify/llm.py Minor import for NeuG path
pyproject.toml Add neug>=0.1.3 optional dependency (neug extra + all extra)
README.md Document NeuG commands in Full command reference
ARCHITECTURE.md Add storage.py module description
tests/ Unit tests (test_storage.py, test_cypher_cli.py)

Usage

# Install
pip install graphify[neug]

# Extract with NeuG (opt-in)
GRAPHIFY_NEUG=1 graphify extract ./raw

# Once graph.db exists, NeuG stays active (no env var needed)
graphify extract ./raw

# Cypher query
graphify cypher "MATCH (n:code) RETURN n.label, n.source_file LIMIT 10"
graphify cypher "MATCH (a:code)-[e:edge]->(b:code) RETURN a.label, b.label LIMIT 10" --db path/to/graph.db

# Delta-cluster (incremental community analysis)
graphify delta-cluster ./raw
graphify delta-cluster ./raw --baseline communities.json  # seed from external clustering

# MCP server (AI agents query via cypher_query tool)
python -m graphify.serve graphify-out/graph.json

Test Plan

  • pytest tests/test_storage.py tests/test_cypher_cli.py -v — all tests passed
  • Full test suite: 4192 passed (including 7 terraform tests after installing tree-sitter-hcl)
  • MCP server cypher_query tool end-to-end verified
  • Incremental extract → MERGE upsert correct
  • Uninstall neug → graphify extract . runs normally (silent skip)

Note

This PR builds on the NeuG integration proposed in #1056. While #1056 established the core storage layer (graph.db, Cypher queries, MCP tool), this PR adds GDS extension support for native and incremental community detection.

Review Findings Addressed

The following review findings have been fixed:

  1. --allow-partial guard missing in NeuG clustered path — Added shrink guard before _cluster_by_neug call for RT-parity with NetworkX path
  2. Manifest not saved in NeuG clustered path — Added _save_manifest call with clear_ast parameter
  3. clear_ast not propagated in NeuG no-cluster path — Added clear_ast parameter to _save_manifest call
  4. Duplicate neug key in pyproject.toml — Removed duplicate entry

The MCP cypher_query tool executing arbitrary Cypher is by design — it's intended for AI agents to flexibly query the knowledge graph. Since it's a local MCP server, the security risk is limited.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 5 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) tested, no difference found (not proven).


Graphify review — findings

Adds an opt-in NeuG embedded-graph-DB pipeline: introduces graphify cypher and graphify delta-cluster CLI commands, a GRAPHIFY_NEUG=1 path in extract that builds graph.db and runs GDS Leiden clustering, plus a --cluster-on-files flag. Wires up storage.py (init/ingest/export, god-node/god-file/surprising-connection queries, Leiden subgraph clustering, freeze-assign delta analysis) and extends serve.py with NeuG-backed context filtering and graph-stats/query tools. Updates README and ARCHITECTURE docs for the new neug extra and commands, and adds storage tests.

Worth a look

  • --allow-partial guard removed from no-cluster overwrite pathgraphify/cli.py · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review Execution auto-disposal is off for this run; enable it (with sandbox isolation) to have Graphify try to confirm or refute this automatically.
  • NeuG clustered global merge path no longer calls global_addgraphify/cli.py:4004 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review Execution auto-disposal is off for this run; enable it (with sandbox isolation) to have Graphify try to confirm or refute this automatically.
  • --global no longer merges in the Neug clustered extract pathgraphify/cli.py:4237 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review Execution auto-disposal is off for this run; enable it (with sandbox isolation) to have Graphify try to confirm or refute this automatically.
  • MCP tool executes arbitrary client-supplied Cypher against graph.dbgraphify/serve.py:1983 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review Execution auto-disposal is off for this run; enable it (with sandbox isolation) to have Graphify try to confirm or refute this automatically.
  • --clear-ast no longer propagated when saving no-cluster manifestgraphify/cli.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review Execution auto-disposal is off for this run; enable it (with sandbox isolation) to have Graphify try to confirm or refute this automatically.
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 706 functions depend on the 331 functions this change touches.

Health — this change adds coupling hotspots:

  • new: dispatch_command() — 2 callers, 124 callees
  • new: _query_graph_text() — 20 callers, 9 callees
  • new: _score_query() — 15 callers, 5 callees
  • new: _query_terms() — 20 callers, 3 callees
  • new: delta_analyze() — 5 callers, 10 callees
  • new: run_benchmark() — 16 callers, 3 callees
  • new: _stale_graph_sources() — 7 callers, 6 callees
  • new: _build_server() — 2 callers, 18 callees
  • …and 25 more — each is listed as a finding

Verification — 706 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 706 function(s) in the blast radius were not formally verified this run

Formal verification

Could not verify: Could not verify dispatch\_command.

The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

No difference found (not proven): No behavior difference found in \_run\_cli (not a proof).

The verifier ran both versions of \_run\_cli on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify \_build\_server.

The verifier did not have enough to check \_build\_server, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly ImportError — names the real obstacle, not a sampling gap)

· 14 grounded finding(s) anchored inline below; 19 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/storage.py
return node_types


def ingest_extraction(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressioningest_extraction()

12 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/storage.py
shutil.copy2(node_csv, dest_dir / f"{tag}_nodes.csv")


def cluster_on_files(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressioncluster_on_files()

high coupling complexity (Ca·Ce = 25).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/storage.py
# ---------------------------------------------------------------------------


def find_god_nodes(conn: object, top_n: int = 10) -> list[dict]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressionfind_god_nodes()

high coupling complexity (Ca·Ce = 12).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/storage.py
return score, reasons


def find_surprising_connections(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressionfind_surprising_connections()

high coupling complexity (Ca·Ce = 12).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/storage.py
# ---------------------------------------------------------------------------


def cluster_by_neug(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressioncluster_by_neug()

fans out to 9 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
_close(db, conn)


def test_find_surprising_connections(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_find_surprising_connections()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
_close(db, conn)


def test_label_communities_by_hub(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_label_communities_by_hub()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
# --- incremental delta analysis (freeze-assign leiden) ---


def test_run_leiden_freeze_assign(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_run_leiden_freeze_assign()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
_close(db, conn)


def test_run_leiden_freeze_assign_resolution(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_run_leiden_freeze_assign_resolution()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
assert changes["dissolved_communities"][0]["old_size"] == 3


def test_delta_analyze(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_delta_analyze()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

@BingqingLyu
BingqingLyu force-pushed the neug-leiden-integration branch from 21778bb to ca05c66 Compare August 24, 2026 03:07
@BingqingLyu

Copy link
Copy Markdown
Author

Addressing the review findings:

  1. --allow-partial guard removed from no-cluster overwrite path — Fixed. Added the shrink guard to the NeuG clustered path (before _cluster_by_neug call) for RT-parity with the NetworkX clustered path.

  2. NeuG clustered global merge path no longer calls global_add — The global_add call is present in the NeuG clustered path. The actual issue was that _save_manifest was missing — now fixed.

  3. --global no longer merges in the Neug clustered extract path — Same as above: global_add is called; the missing piece was _save_manifest which has been added.

  4. MCP tool executes arbitrary client-supplied Cypher against graph.db — This is by design. The cypher_query MCP tool is intended for AI agents to flexibly query the knowledge graph. Since it's a local MCP server, the security risk is limited.

  5. --clear-ast no longer propagated when saving no-cluster manifest — Fixed. Added clear_ast parameter to the _save_manifest call in the NeuG no-cluster path.

Also fixed a duplicate neug key in pyproject.toml that was causing TOML parse errors.

@BingqingLyu

Copy link
Copy Markdown
Author

Regarding the inline coupling findings:

These are expected given the design of the NeuG adapter layer:

  • ingest_extraction() (12 callers) — This is the main entry point for all ingestion paths (full build, incremental, etc.), so high afferent coupling is by design.

  • cluster_on_files(), find_god_nodes(), find_surprising_connections() — These functions interact with the NeuG connection, execute Cypher queries, and process results, which inherently requires multiple dependencies.

  • cluster_by_neug(), delta_analyze() — These are orchestration functions that coordinate multiple steps (ingest, cluster, export, analyze), so efferent coupling is expected.

  • Test functions — Tests naturally call multiple functions to set up fixtures and verify behavior; coupling metrics are less meaningful for test code.

These coupling metrics reflect the inherent complexity of integrating an embedded graph database with the existing pipeline. The functions are cohesive (each has a single responsibility) even if they have multiple dependencies.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 5 advisory finding(s) below merit a look before merge.

Formal verification. 1 change(s) alter behavior, breaking input(s) attached.

Behavior changes: to\_html changes behavior, here is the input that shows it.

The verifier found a concrete input on which to\_html behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"G":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","communities":"\{'k': 'v'\}","output\_path":"'racecar'","community\_labels":"\{'k': 'v'\}","member\_counts":"\{'a': 1\}","node\_limit":"2","learning\_overlay":"\{'a': 1, 'b…, the old code produced False but the new code produces None. Paste that input straight into a regression test.


Graphify review — findings

Adds an opt-in NeuG embedded graph-database pipeline: new graphify cypher and graphify delta-cluster CLI commands in dispatch_command, a --cluster-on-files extract flag, and GRAPHIFY_NEUG=1 extract handling that builds graph.db and runs freeze-assign Leiden clustering. Introduces graphify/storage.py (init_db, ingest_extraction, ingest_communities, delta_analyze, find_surprising_connections, etc.) with matching tests/test_storage.py coverage. Documents the neug extra and new commands in README and ARCHITECTURE.

Worth a look

  • MCP tool executes caller-supplied Cypher without read-only validationgraphify/serve.py:1984 · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • File-level delta analysis uses fixed temp table namesgraphify/storage.py · Escalate · high
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • --no-cluster no-change fast path prunes only graph_stale_sources, not excluded_filesgraphify/cli.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Default extract no longer writes the manifestgraphify/cli.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
  • Early graph.json prune skips DB graph manifest invalidationgraphify/cli.py · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 707 functions depend on the 332 functions this change touches.

Health — this change adds coupling hotspots:

  • new: dispatch_command() — 2 callers, 124 callees
  • new: _query_graph_text() — 20 callers, 9 callees
  • new: _score_query() — 15 callers, 5 callees
  • new: _query_terms() — 20 callers, 3 callees
  • new: delta_analyze() — 5 callers, 10 callees
  • new: run_benchmark() — 16 callers, 3 callees
  • new: _stale_graph_sources() — 7 callers, 6 callees
  • new: _build_server() — 2 callers, 18 callees
  • …and 25 more — each is listed as a finding

Verification — 707 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 707 function(s) in the blast radius were not formally verified this run

Formal verification

Behavior changes: to\_html changes behavior, here is the input that shows it.

The verifier found a concrete input on which to\_html behaves differently before and after the change. If that change is intended, ship it; if not, this is your bug.

Guarantee: This difference was REPRODUCED, the verifier actually ran both versions on that input and saw them disagree. It is real, not an artifact.

Evidence: On input \{"G":"\(lambda \_g: \(\_g\.add\_nodes\_from\(\[\(1, \{\}\), \(2, \{\}\), \(3, \{\}\)\]\), \_g\.add\_edges\_from\(\[\(1, 2, \{\}\), \(1, 3, \{\}\), \(2, 3, \{\}\)\]\), \_g\)\[\-1\]\)\(\_\_import\_\_\('networkx'\)\.Graph\(\)\)","communities":"\{'k': 'v'\}","output\_path":"'racecar'","community\_labels":"\{'k': 'v'\}","member\_counts":"\{'a': 1\}","node\_limit":"2","learning\_overlay":"\{'a': 1, 'b…, the old code produced False but the new code produces None. Paste that input straight into a regression test.

Could not verify: Could not verify dispatch\_command.

The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

No difference found (not proven): No behavior difference found in \_obsidian\_safe\_stem (not a proof).

The verifier ran both versions of \_obsidian\_safe\_stem on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in to\_graphml (not a proof).

The verifier ran both versions of to\_graphml on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify extract.

The verifier did not have enough to check extract, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `cache_root` is annotated `Path | None` — outside the synthesizable primitive/collection set

Could not verify: Could not verify extract\_cpp.

The verifier did not have enough to check extract\_cpp, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_extract\_generic.

The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify extract\_markdown.

The verifier did not have enough to check extract\_markdown, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_resolve\_markdown\_link.

The verifier did not have enough to check \_resolve\_markdown\_link, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: parameter `source_dir` is annotated `Path` — outside the synthesizable primitive/collection set

No difference found (not proven): No behavior difference found in \_bedrock\_response\_text (not a proof).

The verifier ran both versions of \_bedrock\_response\_text on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Verification did not run: Verification did not run for \_call\_azure.

The verification could not execute (an environment/toolchain issue, not a statement about the code).

Guarantee: No guarantee, the check itself did not complete.

Note: Detail: harness produced no verdict (rc=124): timeout after 30s

Could not verify: Could not verify \_call\_bedrock.

The verifier did not have enough to check \_call\_bedrock, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 200 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly ParamValidationError — names the real obstacle, not a sampling gap)

Verification did not run: Verification did not run for \_call\_claude.

The verification could not execute (an environment/toolchain issue, not a statement about the code).

Guarantee: No guarantee, the check itself did not complete.

Note: Detail: harness produced no verdict (rc=124): timeout after 30s

Could not verify: Could not verify \_call\_claude\_cli.

The verifier did not have enough to check \_call\_claude\_cli, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 200 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly RuntimeError — names the real obstacle, not a sampling gap)

Verification did not run: Verification did not run for \_call\_openai\_compat.

The verification could not execute (an environment/toolchain issue, not a statement about the code).

Guarantee: No guarantee, the check itself did not complete.

Note: Detail: harness produced no verdict (rc=124): timeout after 30s

· 14 grounded finding(s) anchored inline below; 19 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/storage.py
return node_types


def ingest_extraction(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressioningest_extraction()

12 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/storage.py
shutil.copy2(node_csv, dest_dir / f"{tag}_nodes.csv")


def cluster_on_files(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressioncluster_on_files()

high coupling complexity (Ca·Ce = 25).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/storage.py
# ---------------------------------------------------------------------------


def find_god_nodes(conn: object, top_n: int = 10) -> list[dict]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressionfind_god_nodes()

high coupling complexity (Ca·Ce = 12).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/storage.py
return score, reasons


def find_surprising_connections(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressionfind_surprising_connections()

high coupling complexity (Ca·Ce = 12).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/storage.py
# ---------------------------------------------------------------------------


def cluster_by_neug(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressioncluster_by_neug()

fans out to 9 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
_close(db, conn)


def test_find_surprising_connections(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_find_surprising_connections()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
_close(db, conn)


def test_label_communities_by_hub(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_label_communities_by_hub()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
# --- incremental delta analysis (freeze-assign leiden) ---


def test_run_leiden_freeze_assign(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_run_leiden_freeze_assign()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
_close(db, conn)


def test_run_leiden_freeze_assign_resolution(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_run_leiden_freeze_assign_resolution()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread tests/test_storage.py
assert changes["dissolved_communities"][0]["old_size"] == 3


def test_delta_analyze(tmp_db):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regressiontest_delta_analyze()

fans out to 6 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

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