Skip to content

test(cluster): pin cluster() output across PYTHONHASHSEED (closes #2817) - #3761

Open
snandan93 wants to merge 1 commit into
Graphify-Labs:v8from
snandan93:test/cluster-cross-hashseed-determinism
Open

snandan93 wants to merge 1 commit into
Graphify-Labs:v8from
snandan93:test/cluster-cross-hashseed-determinism

Conversation

@snandan93

@snandan93 snandan93 commented Sep 22, 2026 •

Copy link
Copy Markdown

#2817 reported that cluster() output changed with PYTHONHASHSEED even though _partition on the full graph did not. On one corpus the same input gave anywhere from 273 to 508 communities.

2709681 (v0.9.51, "canonicalise edge endpoints before sorting in _partition") fixed the underlying cause. The only test added with it checks _partition orientation invariance directly. Nothing checks the symptom the issue actually describes: the whole cluster() result, including the oversize and cohesion split passes, running in separate processes with different hash seeds.

This PR adds that test.

What the test does

  • Builds a graph of about 800 nodes with string IDs, 10 dense blocks and a doc hub. The largest community goes past 25% of nodes, and the hub pulls a low-cohesion community above 50 nodes, so both split passes run.
  • Inserts nodes and edges by iterating over a set, so insertion order and endpoint orientation follow each process's string-hash order, the same way real extraction builds the graph.
  • Runs cluster() in subprocesses with PYTHONHASHSEED 0–3 and asserts that all four SHA-256 digests match.

Checking that the test catches the regression

cluster.py backend result
2709681^ (pre-fix) graspologic-native Leiden fails: 4 different digests
2709681^ (pre-fix) networkx Louvain fallback fails: 4 different digests
HEAD graspologic-native Leiden passes
HEAD networkx Louvain fallback passes

End-to-end check on HEAD (v0.9.65, macOS, Python 3.14)

graphify update . with PYTHONHASHSEED 0–3. Node, edge and community hashes were identical on every seed:

  • graphify's own package: 4050 nodes, 7672 edges, 287 communities.
  • zod packages/ (TypeScript, the language of the 0.9.56 report): 6408 nodes, 10073 edges, 388 communities.

Closes #2817

The endpoint canonicalisation in 2709681 fixed the hash-seed drift reported
in Graphify-Labs#2817, but only _partition orientation invariance is tested. Add a
cross-process test that runs the full cluster() - oversize and cohesion
split passes included - under PYTHONHASHSEED 0-3 and asserts identical
output. Fails on 2709681^ with both Leiden and the Louvain fallback.

@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.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).


Graphify review — findings

Adds a subprocess-based regression test that runs cluster() on a fixed 10-block graph with a bridging doc hub under four different PYTHONHASHSEED values and asserts all four SHA-256 digests of the sorted result are identical. This pins down determinism through the oversize and cohesion re-split passes, which previously drifted with hash seed even though _partition alone was stable.

No blocking issues surfaced. 1 lower-confidence candidate did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 31 functions depend on the 31 functions this change touches.

Health — grade A; no new coupling hotspots.

Verification — 31 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: 31 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

1 of 290 test file(s) selected (0%) via static blast radius.

  • tests/test_cluster.py — impact, changed-test

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

This branch has not been deployed

No deployments
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.

cluster() community-splitting pass is nondeterministic across PYTHONHASHSEED (_partition itself is not; edge-count loss appears fixed since 0.9.6)

1 participant