Skip to content

research(nightly): direct MinCutBuilder bridge detection — ADR-345 follow-up (ADR-346) - #985

Draft
ruvnet wants to merge 4 commits into
mainfrom
claude/focused-darwin-nhc5k9
Draft

ruvnet wants to merge 4 commits into
mainfrom
claude/focused-darwin-nhc5k9

Conversation

@ruvnet

@ruvnet ruvnet commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Hypothesis

ADR-345 (docs/adr/ADR-345-mincut-gated-forgetting.md) rejected MincutGatedForgetting on two grounds: no measurable bridge-protection benefit, and catastrophic latency/non-determinism (~1,800-2,700x slowdown vs a 100x gate; 50% empty-result rate across repeated calls) traced to RuVectorGraphAnalyzer::from_knn(...).partition(). It left an explicit open question ("Next Research item 1"): does calling ruvector-mincut's lower-level DynamicMinCut/MinCutBuilder API directly avoid this?

This PR answers that question, scoped narrowly to latency + determinism only (the separate, already-rejected "does the signal help" hypothesis is not re-litigated).

Architecture

Adds ruvector_agent_memory::graph_forget::BoundaryMethod (WrapperPartition | DirectBuilder) as a new field on MincutGatedForgetting, defaulting to the existing WrapperPartition behavior (purely additive, no existing behavior change). DirectBuilder calls ruvector_mincut::MinCutBuilder::new().with_edges(...).build() — a single spanning-forest + tree-edge-cut pass — instead of RuVectorGraphAnalyzer::partition()'s MinCutWrapper, which replays every edge into up to 100 geometrically-scaled instances per call.

Files changed

  • crates/ruvector-agent-memory/src/graph_forget.rsBoundaryMethod enum, boundary_from_one_partition_direct, 3 new unit tests
  • crates/ruvector-agent-memory/src/lib.rs — export BoundaryMethod
  • crates/ruvector-agent-memory/Cargo.toml — register new example
  • crates/ruvector-agent-memory/examples/mincut_scaling_probe.rs, mincut_determinism_probe.rs — extended to measure both methods side by side (original mincut_gated_forgetting_bench.rs left untouched as ADR-345's historical artifact)
  • crates/ruvector-agent-memory/examples/mincut_direct_builder_bench.rs — new, re-runs ADR-345's exact 84-entry corpus/seed with both methods
  • docs/adr/ADR-346-direct-mincut-bridge-detection.md, docs/adr/INDEX.md (regenerated via scripts/adr-index.mjs)
  • docs/research/nightly/2026-09-15-direct-mincut-bridge-detection/{README.md,gist.md,raw-runs.txt}

Benchmark commands & real results

cargo run --release -p ruvector-agent-memory --example mincut_scaling_probe --features mincut-forget
cargo run --release -p ruvector-agent-memory --example mincut_determinism_probe --features mincut-forget
cargo run --release -p ruvector-agent-memory --example mincut_direct_builder_bench --features mincut-forget
  • Scaling (ring k-NN, n=19→400): DirectBuilder is ~45x–189,000x faster per call than WrapperPartition (0.36-29ms vs 71ms-69.7s), scaling near-linearly vs. WrapperPartition's super-linear blowup. Reproduces ADR-345's original scaling table within run-to-run noise.
  • Determinism (fixed 19-vertex bridge graph, 30 trials × 2 runs): WrapperPartition empty/degenerate 27-50% of calls (exact reproduction of ADR-345's 50% figure in one run); DirectBuilder 0/60 empty, 100% correct bridge detection, ~4,000x lower avg latency.
  • Main benchmark (ADR-345's 84-entry corpus, 6 repeated runs): WrapperPartition reproduces ADR-345's 2,163x-2,800x slowdown (6/6 FAIL vs ≤100x gate). DirectBuilder: 65x-106x slowdown, 10/12 individual measurements PASS the inherited ≤100x gate (the 2 borderline failures are attributable to the ~30µs baseline making the ratio metric noisy — absolute DirectBuilder latency is a stable 2.2-3.6ms across all 6 runs). Speedup vs WrapperPartition: 25.9x-33.7x, stable across every run.

Two real implementation bugs were found and fixed during this experiment (documented in full in the README's "Failure modes" and raw-runs.txt): a missing distance→weight inversion (caught by failing unit tests) and a missing reverse-edge dedup in the probe scripts (caught by an implausible 0.0ms/100%-empty reading).

Open/unresolved finding, reported honestly rather than smoothed over: DirectBuilder deterministically finds a different (smaller) boundary set than WrapperPartition on this corpus — bridge survival 50.0%/58.3% vs. 66.7% for baseline/candidate A, reproducible across all 6 runs. This is why the ADR does not change MincutGatedForgetting's default despite DirectBuilder's decisive performance win — see ADR-346's "Alternatives" and "Next research" for the proposed follow-up using ruvector-mincut's canonical (deterministic-by-construction) min-cut variant to investigate.

Acceptance result

ACCEPT (narrow scope — latency + determinism per the pre-registered hypothesis). MincutGatedForgetting overall remains not promoted (ADR-345's verdict unchanged).

Darwin / Flywheel / MetaHarness

npx metaharness --help is installed (v0.4.16, project-scaffolding tool, not applicable to this in-repo experiment). npx ruvector harness {doctor,darwin,flywheel,status} are not installed in this environment — verified, not assumed. No automated Darwin evolution or Flywheel recording was performed; this PR's README/ADR/raw-runs.txt serve as the manual evidence record instead.

Security review

No new cryptographic primitive, no witness-chain change, no MCP surface change. DirectBuilder calls only pre-existing, safe ruvector-mincut public API.

Main limitations

  • The inherited ≤100x latency gate is noise-sensitive at this corpus's microsecond-scale baseline (see README "Limitations").
  • The cut-selection divergence (bridge survival) is measured but not yet explained.
  • Only one synthetic corpus/topology was tested; generalization to real embeddings is untested.

Production recommendation

BoundaryMethod::DirectBuilder is available and recommended for any future latency-sensitive use of the still-experimental MincutGatedForgetting, but the crate's default (WrapperPartition) is unchanged pending resolution of the cut-selection divergence (see "Next research" in the README).

Test plan

  • cargo test --release -p ruvector-agent-memory --features mincut-forget — 66/66 passed (34 lib incl. 3 new DirectBuilder tests + 32 integration)
  • cargo fmt -p ruvector-agent-memory -- --check — clean
  • cargo clippy -p ruvector-agent-memory --features mincut-forget --examples --tests — 0 warnings
  • cargo build --release -p ruvector-agent-memory --features mincut-forget --examples — clean
  • All 3 benchmark/probe examples run to completion with real (non-fabricated) output, repeated 6/2/3 times respectively; raw output preserved verbatim in raw-runs.txt

🤖 Generated with claude-flow

https://claude.ai/code/session_01Sve7McEmXZX1PEvxHF5AfB


Generated by Claude Code

claude and others added 4 commits September 15, 2026 07:42
…346)

Add BoundaryMethod::DirectBuilder to MincutGatedForgetting as an opt-in
alternative to RuVectorGraphAnalyzer::from_knn(...).partition()
(ADR-345's original, still-default WrapperPartition), following up on
ADR-345's "Next Research item 1". Uses ruvector_mincut::MinCutBuilder's
one-shot construction instead of MinCutWrapper's up-to-100-instance
replay loop, with the same distance-to-weight inversion and
unordered-pair edge dedup RuVectorGraphAnalyzer::from_knn applies
internally.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01Sve7McEmXZX1PEvxHF5AfB
… methods

Extend the ADR-345 scaling and determinism probes to measure
BoundaryMethod::DirectBuilder alongside the existing WrapperPartition
path on identical inputs, instead of duplicating them. Add a new
mincut_direct_builder_bench example that re-runs ADR-345's exact
84-entry corpus/seed with both methods side by side, leaving the
original mincut_gated_forgetting_bench untouched as ADR-345's
historical artifact.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01Sve7McEmXZX1PEvxHF5AfB
…ridge detection

Document the direct-MinCutBuilder experiment (ADR-345 follow-up item
1): full methodology, raw benchmark output across repeated runs
(including two implementation bugs found and fixed during the
experiment), the ADR recording the accepted-narrow-scope decision, and
a standalone technical gist. Regenerate docs/adr/INDEX.md via the
repo's own scripts/adr-index.mjs.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01Sve7McEmXZX1PEvxHF5AfB
The Security audit CI check (cargo audit) started failing on this PR
after RUSTSEC-2026-0285 (TLS 1.3 handshake messages incorrectly
accepted across encryption level boundaries) was published against
rustls 0.23.41, one day before this PR was opened. Confirmed this is
not caused by this PR's diff: Cargo.lock was byte-identical to main
before this commit, and main's own last supply-chain audit run
predates the advisory. `cargo update -p rustls --precise 0.23.45`
(and its rustls-webpki dependency) via cargo's own tooling clears the
vulnerability; `cargo audit` now exits 0 (only the 3 pre-existing
allowed warnings remain, as before). No source code depends on
rustls directly; ruvector-agent-memory's tests remain green against
the updated lockfile.

Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01Sve7McEmXZX1PEvxHF5AfB

ruvnet commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

CI status: "Security audit" failure — not caused by this PR's diff, fixed and pushed.

The cargo audit check failed on the first push with RUSTSEC-2026-0285 (rustls TLS 1.3 handshake vulnerability), published 2026-09-14 — one day before this PR was opened. Verified this wasn't introduced by this PR: Cargo.lock was byte-identical to main before this fix (this PR never touches Cargo.lock, rustls isn't a direct dependency of any crate touched here), and main's own last supply-chain workflow run (2026-09-08) predates the advisory, so main would fail the same audit today.

Applied and pushed the direct fix rather than waiting: cargo update -p rustls --precise 0.23.45 (its rustls-webpki dependency also bumped along with it; a few unrelated crates' windows-sys entries deduplicated onto a version already present elsewhere in the lockfile — no new major version introduced). cargo audit now exits 0 (only the same 3 pre-existing allowed warnings remain). ruvector-agent-memory's full test suite (66 tests) stays green against the updated lockfile. No source code change.


Generated by Claude Code

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.

2 participants