use std::sync::Arc;
use agentplane::blob::{BlobStore, MemoryBlobs, ScopedBlobs};
use agentplane::case::CaseStore;
use agentplane::core::{CorrelationKey, LegalHold, Timestamp, erasure_scope};
use agentplane::prelude::*;
fn operator(actor: &str) -> agentplane::core::Operator {
agentplane::core::Operator::asserted(actor).expect("a fixture names its operator")
}
fn at(secs: i64) -> Timestamp {
Timestamp::from_unix_timestamp(secs).expect("representable")
}
const OPENED: i64 = 1_551_657_600;
const ORDERED: i64 = 1_788_998_400;
const CUTOFF: i64 = 1_568_419_200;
const SWEPT: i64 = 1_789_344_000;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let store = Arc::new(RedbStore::open_in_memory()?);
let cases: Arc<dyn CaseStore> = store.clone();
let blobs: Arc<dyn BlobStore> = Arc::new(MemoryBlobs::new());
let tenant = agentplane::core::TenantId::default();
let mut opened = Vec::new();
for (key, bytes) in [
("DISP-1", &b"evidence in a live dispute"[..]),
("INV-7", &b"a routine attachment"[..]),
] {
let case = cases
.correlate_or_open(
"matter",
&[CorrelationKey::new("document", key)],
at(OPENED),
)
.await?
.case_id();
let scoped = ScopedBlobs::new(
Arc::clone(&blobs),
erasure_scope(&tenant, &case.to_string()),
);
let digest = scoped.put(bytes).await?;
cases.link_blob(case, digest, at(OPENED)).await?;
cases.close(case).await?;
opened.push((key, case, scoped, digest));
}
let (held_key, held, held_blobs, held_digest) = &opened[0];
let (_, _, routine_blobs, routine_digest) = &opened[1];
println!("1. two closed matters, both older than the window");
cases
.place_hold(
*held,
&LegalHold {
placed_at: at(ORDERED),
reason: "preservation order 2026-114".to_owned(),
by: operator("compliance"),
},
)
.await?;
println!("\n2. a hold is placed on {held_key}");
let plan = agentplane::retention::plan(cases.as_ref(), at(CUTOFF)).await?;
println!(" dry run → would erase {}", plan.due.len());
println!(" preserved {}", plan.held.len());
let stores = agentplane::retention::Stores {
cases: &cases,
blobs: Some(&blobs),
#[cfg(feature = "keyring")]
keys: None,
tenant: &tenant,
disclosures: None,
};
let report = agentplane::retention::retain(&stores, at(CUTOFF), at(SWEPT), "7 years").await?;
println!("\n3. the pass");
println!(" erased → {}", report.erased);
println!(" failures → {:?}", report.failures);
for line in &report.held {
println!(" held → {line}");
}
println!(
" held bytes → readable: {}",
held_blobs.get(*held_digest).await.is_ok()
);
println!(
" swept bytes → readable: {}",
routine_blobs.get(*routine_digest).await.is_ok()
);
println!("\n4. what is still being kept, and on whose instruction");
for (case, hold) in cases.holds(None, 50).await? {
println!(" {case} — {}", hold.reason);
}
let plane = Runtime::builder(store.clone() as Arc<dyn agentplane::journal::JournalStore>)
.cases(Arc::clone(&cases))
.build();
let released = plane
.release_hold(*held, &operator("ops-dave"), at(SWEPT))
.await?
.expect("the matter was held")
.record;
println!("\n released, recorded in run {released}");
let after = agentplane::retention::retain(&stores, at(CUTOFF), at(SWEPT), "7 years").await?;
println!("\n5. the hold is lifted and the same pass runs again");
println!(" still held → {}", after.held.len());
println!(
" held bytes → readable: {}",
held_blobs.get(*held_digest).await.is_ok()
);
println!(
"\nA hold outranks the calendar, and lifting it puts the matter back \
under it.\nThe sweep never guessed which was which — somebody said so, \
and the record says who."
);
Ok(())
}