research(nightly): structural-time-gated memory compaction scheduling — REJECT, evidence retained - #996
Draft
ruvnet wants to merge 4 commits into
Draft
research(nightly): structural-time-gated memory compaction scheduling — REJECT, evidence retained#996ruvnet wants to merge 4 commits into
ruvnet wants to merge 4 commits into
Conversation
MemoryStore::insert assigned id = entries.len(), which is only correct while a store never receives an insert after it has been compacted (every existing benchmark's usage pattern). Once compaction shrinks the store and a later insert reuses a length-derived id, it can silently collide with a still-surviving older entry's id, breaking id-based identity (recall/search comparisons in particular). Switch to a monotonic next_id counter, independent of entries.len(). Behavior is unchanged for any single-terminal-compaction call site; full crate test suite (all feature combinations) passes unchanged. Found while building a streaming compaction-trigger benchmark (nightly research 2026-09-18) that is the first usage pattern in this crate to insert after compacting. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01W9AzJk52mCWmwLy4tkHtVd
Nightly research, 2026-09-18. Adds a CompactionTrigger trait — an axis this crate has never had: *when* to run compaction, as opposed to CompactionPolicy's *what* survives it. Three implementations: - FixedIntervalTrigger: fires every N writes (baseline). - CapacityTrigger: fires once the store exceeds a size ceiling. - StructuralGateTrigger: fires once accumulated emergent_time::structural_clock::StructuralProperTime (an existing, independently-tested workspace crate's arc-length-through-state- manifold clock, reused unmodified) over a bounded sliding window crosses a calibrated threshold. Feature-gated (`structural-gate`, off by default) behind a new optional path dependency on `emergent-time`. Deliberately O(window * dims) per write, not O(store.len() * dims), in direct response to the prior nightly's (2026-09-05, mincut-gated-forgetting) rejection for an O(n)-or-worse structural signal. 6 unit tests cover all three triggers. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01W9AzJk52mCWmwLy4tkHtVd
Deterministic, seeded 1,400-write comparison of FixedIntervalTrigger,
CapacityTrigger, and StructuralGateTrigger against a synthetic
quiet/burst agent-memory write stream, with a pre-registered
Given/When/Then hypothesis and four numeric acceptance thresholds
(compaction-call reduction, excess-size-integral reduction, recall
gap, wall-clock ratio) evaluated before the run.
Result: REJECT. StructuralGate over-fires during quiet regimes (100
total calls vs FixedInterval's 24) despite a real, large discriminative
signal (70 of its 100 fires land on the 200 writes, 14.3% of the
stream, that are genuine bursts). Root cause and full evidence in
docs/adr/ADR-346 and the nightly research report.
Run:
cargo run --release -p ruvector-agent-memory --features structural-gate \
--example structural_gated_compaction_bench
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01W9AzJk52mCWmwLy4tkHtVd
…action) Adds ADR-346 (Rejected, evidence retained), the full nightly research report, and a standalone technical gist for the 2026-09-18 experiment: reusing emergent-time's StructuralProperTime clock as an agent-memory compaction scheduling trigger. Regenerates docs/adr/INDEX.md via its own generator script (node scripts/adr-index.mjs) to register ADR-346 and advance the next-available counter to 347. Co-Authored-By: claude-flow <ruv@ruv.net> Claude-Session: https://claude.ai/code/session_01W9AzJk52mCWmwLy4tkHtVd
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.
Nightly RuVector Research — 2026-09-18
Topic: Structural-Time-Gated Memory Compaction Scheduling
Slug:
structural-time-gated-memory-compactionAcceptance: REJECT (for production use as calibrated) — real measured evidence retained, per the nightly process's own rule that a well-characterized falsified hypothesis is a successful run.
Hypothesis
ruvector-agent-memoryhas threeCompactionPolicyimplementations that decide what survives a compaction pass, but nothing in the crate has ever decided when to run one — every existing benchmark compacts a store exactly once, on demand. This experiment adds aCompactionTriggertrait and asks whetheremergent-time's existing, independently-testedStructuralProperTimeclock ("time = arc length through a system's own state manifold"), reused unmodified, can gate compaction scheduling better than a naive fixed-interval or capacity-ceiling trigger — staying quiet through near-duplicate writes and firing promptly on bursts of genuinely new material.Full Given/When/Then and four pre-registered numeric acceptance thresholds: ADR-346.
Architecture
crates/ruvector-agent-memory/src/structural_gate.rs(new, feature-gatedstructural-gate, off by default):CompactionTriggertrait +FixedIntervalTrigger,CapacityTrigger,StructuralGateTrigger(boundedO(window*dims)per write, notO(store.len()*dims)— a direct response to the prior nightly's, 2026-09-05 mincut-gated-forgetting, rejection for anO(n)-or-worse structural signal).emergent-time(existing workspace crate, reused as-is — no reimplementation).examples/structural_gated_compaction_bench.rs: the full deterministic, seeded comparison benchmark.MemoryStore::insertassignedid = entries.len(), which collides with a surviving entry's id once compaction and further insertion interleave (every prior call site only ever compacted once, terminally). Fixed to a monotonic counter — pure correctness fix, independent of which trigger wins, full existing test suite passes unchanged.Benchmark
3 repeated release-mode runs: algorithmic columns bit-identical (fully deterministic, seeded), wall-clock varied 6.2–6.3ms (fixed) / 22.2–23.5ms (structural) — REJECT is robust to run-to-run timing noise, not a single unlucky measurement.
Root cause (full writeup in the ADR/report):
StructuralProperTime's coherence channel accumulates only on loss, which is correct for genuine irreversible drift but means a small sliding-window coherence estimate's sampling noise — half of which is downward fluctuation — reads as monotone drift. A threshold calibrated from the quiet baseline's mean tick was still within that baseline's own variance. The diagnostic shows the signal is real, not noise-only (70 of 100 fires land on the 14.3% of writes that are genuine bursts — a ~14x fire-density skew), but the tested calibration wasn't conservative enough to also win on absolute call count.Darwin / Flywheel / MetaHarness
Per this run's tool-discovery pass (Step 0 of the nightly process):
npx metaharness --helpresolves to an installed package that scaffolds new harness projects — not an in-repo research-orchestration layer usable against this repo.npx ruvector harness doctor --jsondoes not resolve to any executable in this environment. No Darwin/Flywheel tool output is fabricated; the research → hypothesis → implementation → measurement → critique → promotion-or-rejection loop was carried out directly in this session, with the diagnostic fire-location breakdown serving as the adversarial root-cause pass. No Darwin evolutionary sweep was run this session — a single pre-registered calibration was tested and rejected clearly enough that a same-session parameter retune would have violated the "don't move the goalposts" rule; a follow-up with an independently-registered calibration hypothesis is the correct next step (see ADR-346 §Next Research).Security review
No new attack surface: the trigger only reads
MemoryEntryvectors already resident in the store and compares a scalar accumulator to a scalar threshold — no untrusted parsing, no new serialization format, no witness/signature involvement.structural-gateis an additive, opt-in Cargo feature (off by default) with no default-path exposure.Main limitations
compact()calls — not decomposed.graph, prediction error) left at 0.0 rather than fed a fabricated signal.Production recommendation
Do not promote as calibrated. Keep the
CompactionTriggertrait and theMemoryStoreid fix (unconditionally useful); do not wireStructuralGateTriggerinto any default path. Next attempt should calibrate from both quiet and burst reference data (not quiet alone) and isolate whether the loss-only coherence asymmetry or the entropy-histogram noise is the larger contributor before re-testing against the same four thresholds.Docs
Build/test
cargo fmtclean,cargo build --releaseclean,cargo clippy --features structural-gate --examples --tests -- -D warningsclean,cargo test(all feature combinations:structural-gate,mincut-forget,proof-gate) — 71 tests, 0 failures.🤖 Generated with claude-flow
https://claude.ai/code/session_01W9AzJk52mCWmwLy4tkHtVd
Generated by Claude Code