Conversation
…witness partition complement RuVectorGraphAnalyzer::partition() returned different, sometimes empty, results across repeated calls on byte-identical graphs (ADR-345, 2026-09-05 nightly finding). Root-caused to two independent bugs: - BoundedInstance::brute_force_min_cut/search_for_cuts built their vertex/seed enumeration order from HashSet<VertexId> iteration, which Rust's default hasher reseeds on every instance construction, so first-match tie-breaking among equal-cost cuts was nondeterministic. Fixed by sort_unstable() on both vectors before use. - WitnessHandle::materialize_partition() computed the cut's second side as 0..=max(membership) minus membership instead of using the real graph vertex set, silently returning an empty complement whenever the winning side excluded the graph's highest-ID vertex. Fixed at the one production call site (RuVectorGraphAnalyzer::partition()) by computing the complement against self.graph.vertices() instead. 200-trial determinism probe: 44% empty/wrong before, 0% after (100% after fixing only the first bug, confirming both bugs are independent and both needed fixing). 512/512 existing tests unchanged; clippy clean. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01MzSGbyatr2eZwuM4JVeP5g
Now that ruvector-mincut's RuVectorGraphAnalyzer::partition() is deterministic (previous commit), MincutGatedForgetting no longer needs to repeat and union boundary detection across multiple trials to work around nondeterministic tie-breaking. mincut_trials defaults 3 -> 1 in soft()/hard(); the two unit tests' mincut_trials = 10 workaround is removed. Verified stable across 30 repeated runs of the compiled test binary. ruvector-agent-memory lib suite: 31/31 passed in 1.05s, down from ~10.5s at mincut_trials = 10. Doc comments updated to record the root cause and fix, preserving the original 2026-09-05 "Measured limitation" finding rather than deleting it. The underlying mincut-gated-forgetting hypothesis remains rejected at production scale (ADR-345's own, unrelated finding), unchanged by this fix. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01MzSGbyatr2eZwuM4JVeP5g
…sm fix Documents the 2026-09-21 nightly run that answers ADR-345's two filed "Next Research" open questions about ruvector-mincut's non-determinism: root cause, fix, and a three-stage before/after re-run of the unmodified 2026-09-05 benchmark (raw output preserved). Records that the mincut-gated-forgetting REJECT verdict is unchanged by the fix, and files the remaining open items (WitnessHandle constructor-level fix, latency investigation via DynamicMinCut, broader HashMap/HashSet audit) as explicit future work. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01MzSGbyatr2eZwuM4JVeP5g
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hypothesis
The 2026-09-05 nightly run (ADR-345, mincut-gated forgetting) measured
RuVectorGraphAnalyzer::partition()returning different, sometimes empty, results across repeated calls on byte-identical graphs, and filed two open "Next Research" items: find the root cause, and check whether the crate's lower-level API avoids it. This PR is that follow-up: given the same graph, when the two root causes are fixed, repeatedpartition()calls should return byte-identical, correct results — subject to zero regressions in the existing test suite and the original benchmark's verdict changing only if the bugs (not the algorithm's fitness for that task) explain its prior REJECT.Root cause (two independent bugs)
BoundedInstance::brute_force_min_cut/search_for_cuts(crates/ruvector-mincut/src/instance/bounded.rs) built their vertex/seed enumeration order fromHashSet<VertexId>iteration. Rust's default hasher reseeds on everyHashSet/instance construction, so first-match tie-breaking among equal-cost minimum cuts was a function of construction-time entropy, not the graph. Fixed withsort_unstable()on both vectors.WitnessHandle::materialize_partition()(crates/ruvector-mincut/src/instance/witness.rs) computed the cut's second side as0..=max(membership)minusmembership— silently wrong (often empty) whenever the winning side didn't contain the graph's actual highest-ID vertex. Fixed at the one production call site,RuVectorGraphAnalyzer::partition()(crates/ruvector-mincut/src/integration/mod.rs), by computing the complement against the analyzer's real graph vertex set.crates/ruvector-agent-memory/src/graph_forget.rs'sMincutGatedForgettingno longer needs itsmincut_trialsmajority-vote workaround now that the underlying call is deterministic; its default drops3 → 1(unit tests:10 → 1).Architecture
See the mermaid diagram in the nightly report:
docs/research/nightly/2026-09-21-mincut-determinism-fix/README.md.Files changed
crates/ruvector-mincut/src/instance/bounded.rs— determinism fix (bug 1)crates/ruvector-mincut/src/integration/mod.rs— witness complement fix (bug 2)crates/ruvector-agent-memory/src/graph_forget.rs— drop the now-unnecessary retry workaround, doc updatesdocs/adr/ADR-346-mincut-witness-partition-determinism.md(new)docs/adr/INDEX.md— index entry for ADR-346docs/research/nightly/2026-09-21-mincut-determinism-fix/README.md,gist.md(new)Benchmark command
Real benchmark results
Three stages, each re-running both commands unmodified:
main)The middle row is the key intermediate result: fixing only the tie-breaking bug made the outcome fully deterministic and fully wrong (it reliably converges on the tie-broken cut that triggers the complement bug), which is strong independent confirmation both bugs are real and both needed fixing.
Latency is flat (~1.0–1.06s/call) across all three stages — both are correctness bugs, not performance bugs; the crate's separately-documented latency cost is untouched and remains open (see Next Research in the report).
cargo test --release -p ruvector-mincut --lib: 512 passed, 0 failed, 5 ignored (unchanged count from baseline).cargo test --release -p ruvector-agent-memory --features mincut-forget --lib: 31 passed, 0 failed.cargo clippy --release -- -D warningsclean on both crates. 30/30 repeated runs of themincut_trials = 1bridge-detection tests, no flakes.Acceptance result
ACCEPT for the determinism/correctness hypothesis (0% empty, 100% correct, reproducible across repeated runs). The original mincut-gated-forgetting production hypothesis (ADR-345) remains REJECT, unchanged and expected — its rejection was independently attributed to the global min-cut not isolating human-perceived "bridge" memories on this benchmark's synthetic data, orthogonal to both bugs fixed here.
Darwin result
Not run. This is a targeted, root-caused bug fix with one clear correct implementation (sort before first-match; compute the complement against the real vertex set) — no meaningful parameter space to evolve. See the nightly report's "Evolution Results" section for the full reasoning.
Flywheel result
Recorded in
docs/research/nightly/2026-09-21-mincut-determinism-fix/README.md: root cause, fix, before/after evidence, and three explicit future-research items (aWitnessHandleconstructor-level fix, a latency investigation viaDynamicMinCut, and a broader audit offragment//expander//jtree/for the same bug class) are filed so a future session doesn't have to rediscover them.Security review
No new attack surface, no new dependencies, no new unsafe code, no parsing of untrusted input. Determinism is a strict improvement for any downstream witness-verification or replay consumer.
Main limitations
RuVectorGraphAnalyzer::partition()'s one current production caller was fixed and verified;WitnessHandle::materialize_partition()itself is still wrong for any future direct caller until a deeper constructor-level fix lands (filed as Open Question 1 in ADR-346).HashMap/HashSet-heavy modules in the crate (fragment/,expander/,jtree/) were not audited for the same bug class.Production recommendation
Land as-is. Both fixes are minimal, change no public API signature, are covered by the existing test suite plus this PR's three-stage before/after benchmark, and remove a correctness confound from any current or future consumer of
RuVectorGraphAnalyzer/BoundedInstance/WitnessHandle.Research document / ADR / gist
docs/research/nightly/2026-09-21-mincut-determinism-fix/README.mddocs/adr/ADR-346-mincut-witness-partition-determinism.mddocs/research/nightly/2026-09-21-mincut-determinism-fix/gist.md🤖 Generated with claude-flow
https://claude.ai/code/session_01MzSGbyatr2eZwuM4JVeP5g
Generated by Claude Code