Skip to content

Commit 1f36924

Browse files
committed
feat: Add demo-generator crate for Semantic Drift demonstration
1 parent 2154b4f commit 1f36924

5 files changed

Lines changed: 126 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,4 @@ Thumbs.db
5555
.agent/
5656
*.log
5757
*.log
58+
demo_db/

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ members = [
2121
"crates/persistence",
2222
"crates/cli",
2323
"crates/kernel",
24+
"crates/demo-generator",
2425
]
2526

2627
# Firmware requires abort on panic (no unwinding support in no_std)

crates/demo-generator/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "demo-generator"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
valori-kernel = { path = "../kernel" }
8+
valori-persistence = { path = "../persistence" }
9+
byteorder = "1.5"
10+
crc64fast = "1.0"
11+
anyhow = "1.0"

crates/demo-generator/src/main.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use anyhow::Result;
2+
use byteorder::{LittleEndian, WriteBytesExt};
3+
use crc64fast::Digest;
4+
use std::path::Path;
5+
use valori_kernel::ValoriKernel;
6+
use valori_persistence::{snapshot, wal};
7+
use valori_persistence::snapshot::SnapshotHeader;
8+
9+
fn main() -> Result<()> {
10+
let out_dir = Path::new("demo_db");
11+
if out_dir.exists() {
12+
std::fs::remove_dir_all(out_dir)?;
13+
}
14+
std::fs::create_dir_all(&out_dir)?;
15+
16+
let mut kernel = ValoriKernel::new();
17+
18+
println!("🎬 Generating 'Semantic Drift' Dataset...");
19+
20+
// --- SCENE 1: The "Red" Cluster (ID 1-100) ---
21+
// Center: [1000, 1000]
22+
println!("1. Ingesting 100 'Red' vectors...");
23+
for i in 1..=100 {
24+
let x = 1000 + rand_diff(i);
25+
let y = 1000 + rand_diff(i + 1000); // Different seed
26+
let payload = create_insert_payload(i, vec![x, y]);
27+
kernel.apply_event(&payload)?;
28+
}
29+
30+
// --- CHECKPOINT 1: SNAPSHOT ---
31+
println!("2. Taking Snapshot (Checkpoint 1)...");
32+
let snap_body = kernel.save_snapshot()?;
33+
34+
// Compute Hash
35+
let mut digest = Digest::new();
36+
digest.write(&snap_body);
37+
let checksum = digest.sum64();
38+
let mut state_hash = [0u8; 16];
39+
state_hash[0..8].copy_from_slice(&checksum.to_le_bytes());
40+
41+
let header = SnapshotHeader::new(100, 1700000000, state_hash);
42+
43+
snapshot::write_to(out_dir.join("snapshot.val"), header, &snap_body)?;
44+
45+
// --- SCENE 2: The "Blue" Intrusion (ID 101-200) ---
46+
// Center: [3000, 3000] (Far away from Red)
47+
println!("3. Ingesting 100 'Blue' vectors (Drift)...");
48+
49+
let wal_path = out_dir.join("events.log");
50+
51+
// We will append to WAL directly.
52+
for i in 101..=200 {
53+
let x = 3000 + rand_diff(i);
54+
let y = 3000 + rand_diff(i + 2000);
55+
let payload = create_insert_payload(i, vec![x, y]);
56+
57+
// Append to WAL
58+
wal::append_entry(&wal_path, i, &payload)?;
59+
}
60+
61+
// --- SCENE 3: The "Purple" Influencer (ID 201) ---
62+
// Position: [1500, 1500] (Exact match for the query)
63+
println!("4. Ingesting 1 'Purple' Influencer...");
64+
let x = 1500;
65+
let y = 1500;
66+
let payload = create_insert_payload(201, vec![x, y]);
67+
wal::append_entry(&wal_path, 201, &payload)?;
68+
69+
// Create a dummy metadata index
70+
let idx_path = out_dir.join("metadata.idx");
71+
valori_persistence::idx::append_metadata(&idx_path, 100, None, "snapshot".to_string())?;
72+
valori_persistence::idx::append_metadata(&idx_path, 150, None, "blue_wave".to_string())?;
73+
valori_persistence::idx::append_metadata(&idx_path, 201, None, "purple_event".to_string())?;
74+
75+
println!("✅ Demo Database generated at: {:?}", out_dir.canonicalize()?);
76+
println!("📊 Story: Red (0-100) -> Blue (101-200) -> Purple (201)");
77+
println!(" Try: valori diff --dir demo_db --from 100 --to 201 --query '[1500, 1500]'");
78+
79+
Ok(())
80+
}
81+
82+
fn create_insert_payload(id: u64, values: Vec<i32>) -> Vec<u8> {
83+
let dim = values.len() as u16;
84+
let mut wtr = Vec::new();
85+
wtr.write_u8(1).unwrap(); // CMD_INSERT
86+
wtr.write_u64::<LittleEndian>(id).unwrap();
87+
wtr.write_u16::<LittleEndian>(dim).unwrap();
88+
for v in values {
89+
wtr.write_i32::<LittleEndian>(v).unwrap();
90+
}
91+
wtr
92+
}
93+
94+
// Deterministic Pseudo-Random
95+
fn rand_diff(seed: u64) -> i32 {
96+
let mut x = seed;
97+
x ^= x << 13;
98+
x ^= x >> 7;
99+
x ^= x << 17;
100+
// Range -100 to 100
101+
((x % 200) as i32) - 100
102+
}

0 commit comments

Comments
 (0)