add daily lookup counter for memory retrieval tracking

Mmap'd open-addressing hash table (~49KB/day) records which memory
keys get retrieved. FNV-1a hash, linear probing, 4096 slots.

- lookups::bump()/bump_many(): fast path, no store loading needed
- Automatically wired into cmd_search (top 15 results bumped)
- lookup-bump subcommand for external callers
- lookups [DATE] subcommand shows resolved counts

This gives the knowledge loop a signal for which graph neighborhoods
are actively used, enabling targeted extraction.

Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-03-03 18:36:25 -05:00
parent 152cd3ab63
commit ca0c8cfac6
2 changed files with 248 additions and 1 deletions

View file

@ -27,6 +27,7 @@ mod migrate;
mod neuro;
mod query;
mod spectral;
mod lookups;
pub mod memory_capnp {
include!(concat!(env!("OUT_DIR"), "/schema/memory_capnp.rs"));
@ -125,6 +126,8 @@ fn main() {
"journal-write" => cmd_journal_write(&args[2..]),
"journal-tail" => cmd_journal_tail(&args[2..]),
"query" => cmd_query(&args[2..]),
"lookup-bump" => cmd_lookup_bump(&args[2..]),
"lookups" => cmd_lookups(&args[2..]),
_ => {
eprintln!("Unknown command: {}", args[1]);
usage();
@ -202,7 +205,9 @@ Commands:
journal-tail [N] [--full] Show last N journal entries (default 20, --full for content)
query 'EXPR | stages' Query the memory graph
Stages: sort F [asc], limit N, select F,F, count
Ex: \"degree > 15 | sort degree | limit 10\"");
Ex: \"degree > 15 | sort degree | limit 10\"
lookup-bump KEY [KEY...] Bump daily lookup counter for keys (fast, no store)
lookups [DATE] Show daily lookup counts (default: today)");
}
fn cmd_search(args: &[String]) -> Result<(), String> {
@ -225,6 +230,10 @@ fn cmd_search(args: &[String]) -> Result<(), String> {
store::Store::log_retrieval_static(&query,
&results.iter().map(|r| r.key.clone()).collect::<Vec<_>>());
// Bump daily lookup counters (fast path, no store needed)
let bump_keys: Vec<&str> = results.iter().take(15).map(|r| r.key.as_str()).collect();
let _ = lookups::bump_many(&bump_keys);
// Show text results
let text_keys: std::collections::HashSet<String> = results.iter()
.take(15).map(|r| r.key.clone()).collect();
@ -1593,3 +1602,37 @@ Pipe stages:\n \
let graph = store.build_graph();
query::run_query(&store, &graph, &query_str)
}
fn cmd_lookup_bump(args: &[String]) -> Result<(), String> {
if args.is_empty() {
return Err("Usage: poc-memory lookup-bump KEY [KEY...]".into());
}
let keys: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
lookups::bump_many(&keys)
}
fn cmd_lookups(args: &[String]) -> Result<(), String> {
let date = if args.is_empty() {
chrono::Local::now().format("%Y-%m-%d").to_string()
} else {
args[0].clone()
};
let store = store::Store::load()?;
let keys: Vec<String> = store.nodes.values().map(|n| n.key.clone()).collect();
let resolved = lookups::dump_resolved(&date, &keys)?;
if resolved.is_empty() {
println!("No lookups for {}", date);
return Ok(());
}
println!("Lookups for {}:", date);
for (key, count) in &resolved {
println!(" {:4} {}", count, key);
}
println!("\n{} distinct keys, {} total lookups",
resolved.len(),
resolved.iter().map(|(_, c)| *c as u64).sum::<u64>());
Ok(())
}