cleanup: auto-fix clippy warnings in poc-memory
Applied cargo clippy --fix for collapsible_if, manual_char_comparison, and other auto-fixable warnings.
This commit is contained in:
parent
3640de444b
commit
653da40dcd
21 changed files with 99 additions and 149 deletions
|
|
@ -76,7 +76,7 @@ pub fn consolidate_full_with_progress(
|
|||
|
||||
match knowledge::run_and_apply(store, agent_type, *count, "consolidate") {
|
||||
Ok(()) => {
|
||||
let msg = format!(" Done");
|
||||
let msg = " Done".to_string();
|
||||
log_line(&mut log_buf, &msg);
|
||||
on_progress(&msg);
|
||||
println!("{}", msg);
|
||||
|
|
|
|||
|
|
@ -111,12 +111,11 @@ pub fn get_def(name: &str) -> Option<AgentDef> {
|
|||
let dir = agents_dir();
|
||||
for ext in ["agent", "md"] {
|
||||
let path = dir.join(format!("{}.{}", name, ext));
|
||||
if let Ok(content) = std::fs::read_to_string(&path) {
|
||||
if let Some(def) = parse_agent_file(&content) {
|
||||
if let Ok(content) = std::fs::read_to_string(&path)
|
||||
&& let Some(def) = parse_agent_file(&content) {
|
||||
return Some(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
load_defs().into_iter().find(|d| d.agent == name)
|
||||
}
|
||||
|
||||
|
|
@ -345,7 +344,7 @@ fn resolve(
|
|||
for (a, b, s) in &cross_links {
|
||||
out.push_str(&format!(" {} ↔ {} ({:.2})\n", a, b, s));
|
||||
}
|
||||
out.push_str("\n");
|
||||
out.push('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,17 +213,15 @@ pub fn select_conversation_fragments(n: usize) -> Vec<(String, String)> {
|
|||
if let Ok(files) = fs::read_dir(dir.path()) {
|
||||
for f in files.filter_map(|e| e.ok()) {
|
||||
let p = f.path();
|
||||
if p.extension().map(|x| x == "jsonl").unwrap_or(false) {
|
||||
if let Ok(meta) = p.metadata() {
|
||||
if meta.len() > 50_000 {
|
||||
if p.extension().map(|x| x == "jsonl").unwrap_or(false)
|
||||
&& let Ok(meta) = p.metadata()
|
||||
&& meta.len() > 50_000 {
|
||||
jsonl_files.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect unmined segments across all transcripts
|
||||
let mut candidates: Vec<(String, String)> = Vec::new();
|
||||
|
|
@ -307,12 +305,11 @@ pub fn mark_observation_done(fragment_ids: &[String]) {
|
|||
Err(_) => return,
|
||||
};
|
||||
for id in fragment_ids {
|
||||
if let Some((session_id, seg_str)) = id.rsplit_once('.') {
|
||||
if let Ok(seg) = seg_str.parse::<u32>() {
|
||||
if let Some((session_id, seg_str)) = id.rsplit_once('.')
|
||||
&& let Ok(seg) = seg_str.parse::<u32>() {
|
||||
let _ = store.mark_segment_mined(session_id, seg, "observation");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Format a segment's messages into readable text for the observation agent.
|
||||
|
|
|
|||
|
|
@ -216,16 +216,14 @@ pub(crate) fn parse_json_response(response: &str) -> Result<serde_json::Value, S
|
|||
let re_obj = Regex::new(r"\{[\s\S]*\}").unwrap();
|
||||
let re_arr = Regex::new(r"\[[\s\S]*\]").unwrap();
|
||||
|
||||
if let Some(m) = re_obj.find(cleaned) {
|
||||
if let Ok(v) = serde_json::from_str(m.as_str()) {
|
||||
if let Some(m) = re_obj.find(cleaned)
|
||||
&& let Ok(v) = serde_json::from_str(m.as_str()) {
|
||||
return Ok(v);
|
||||
}
|
||||
}
|
||||
if let Some(m) = re_arr.find(cleaned) {
|
||||
if let Ok(v) = serde_json::from_str(m.as_str()) {
|
||||
if let Some(m) = re_arr.find(cleaned)
|
||||
&& let Ok(v) = serde_json::from_str(m.as_str()) {
|
||||
return Ok(v);
|
||||
}
|
||||
}
|
||||
|
||||
let preview = crate::util::first_n_chars(cleaned, 200);
|
||||
Err(format!("no valid JSON in response: {preview}..."))
|
||||
|
|
|
|||
|
|
@ -154,14 +154,13 @@ pub fn cmd_fsck() -> Result<(), String> {
|
|||
}
|
||||
// Version mismatches
|
||||
for (key, log_node) in &log_store.nodes {
|
||||
if let Some(cache_node) = store.nodes.get(key) {
|
||||
if cache_node.version != log_node.version {
|
||||
if let Some(cache_node) = store.nodes.get(key)
|
||||
&& cache_node.version != log_node.version {
|
||||
eprintln!("CACHE STALE: '{}' cache v{} vs log v{}",
|
||||
key, cache_node.version, log_node.version);
|
||||
cache_issues += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cache_issues > 0 {
|
||||
eprintln!("{} cache inconsistencies found — rebuilding from logs", cache_issues);
|
||||
|
|
@ -310,7 +309,7 @@ pub fn cmd_dedup(apply: bool) -> Result<(), String> {
|
|||
// For diverged: keep the copy with most edges (it's the one that got
|
||||
// woven into the graph — the version that lived). Fall back to highest version.
|
||||
let all_groups: Vec<_> = identical_groups.into_iter()
|
||||
.chain(diverged_groups.into_iter())
|
||||
.chain(diverged_groups)
|
||||
.collect();
|
||||
|
||||
let mut merged = 0usize;
|
||||
|
|
|
|||
|
|
@ -228,14 +228,13 @@ pub fn cmd_evaluate_agents(matchups: usize, model: &str, dry_run: bool) -> Resul
|
|||
let mut seen = std::collections::HashSet::new();
|
||||
for word in report.split_whitespace() {
|
||||
let clean = word.trim_matches(|c: char| !c.is_alphanumeric() && c != '-' && c != '_');
|
||||
if clean.len() > 10 && seen.insert(clean.to_string()) && store.nodes.contains_key(clean) {
|
||||
if let Some(node) = store.nodes.get(clean) {
|
||||
if clean.len() > 10 && seen.insert(clean.to_string()) && store.nodes.contains_key(clean)
|
||||
&& let Some(node) = store.nodes.get(clean) {
|
||||
let preview = crate::util::truncate(&node.content, 200, "...");
|
||||
target_content.push_str(&format!("\n### {}\n{}\n", clean, preview));
|
||||
if target_content.len() > 1500 { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let context = format!(
|
||||
"## Agent instructions\n{}\n\n## Report output\n{}\n\n## Affected nodes\n{}",
|
||||
|
|
|
|||
|
|
@ -62,19 +62,16 @@ pub fn find_current_transcript() -> Option<String> {
|
|||
if let Ok(files) = std::fs::read_dir(dir_entry.path()) {
|
||||
for f in files.filter_map(|e| e.ok()) {
|
||||
let p = f.path();
|
||||
if p.extension().map(|x| x == "jsonl").unwrap_or(false) {
|
||||
if let Ok(meta) = p.metadata() {
|
||||
if let Ok(mtime) = meta.modified() {
|
||||
if newest.as_ref().is_none_or(|(t, _)| mtime > *t) {
|
||||
if p.extension().map(|x| x == "jsonl").unwrap_or(false)
|
||||
&& let Ok(meta) = p.metadata()
|
||||
&& let Ok(mtime) = meta.modified()
|
||||
&& newest.as_ref().is_none_or(|(t, _)| mtime > *t) {
|
||||
newest = Some((mtime, p));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newest.map(|(_, p)| p.to_string_lossy().to_string())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ pub fn cmd_search(terms: &[String], pipeline_args: &[String], expand: bool, full
|
|||
for (i, (key, score)) in raw.iter().enumerate().take(max_results) {
|
||||
let weight = store.nodes.get(key).map(|n| n.weight).unwrap_or(0.0);
|
||||
println!("{:2}. [{:.2}/{:.2}] {}", i + 1, score, weight, key);
|
||||
if full {
|
||||
if let Some(node) = store.nodes.get(key) {
|
||||
if full
|
||||
&& let Some(node) = store.nodes.get(key) {
|
||||
println!();
|
||||
for line in node.content.lines() {
|
||||
println!(" {}", line);
|
||||
|
|
@ -65,7 +65,6 @@ pub fn cmd_search(terms: &[String], pipeline_args: &[String], expand: bool, full
|
|||
println!();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fast MmapView path — algorithm-only pipeline
|
||||
use crate::store::StoreView;
|
||||
|
|
@ -120,8 +119,8 @@ pub fn cmd_search(terms: &[String], pipeline_args: &[String], expand: bool, full
|
|||
let marker = if r.is_direct { "→" } else { " " };
|
||||
let weight = view.node_weight(&r.key);
|
||||
println!("{}{:2}. [{:.2}/{:.2}] {}", marker, i + 1, r.activation, weight, r.key);
|
||||
if full {
|
||||
if let Some(content) = view.node_content(&r.key) {
|
||||
if full
|
||||
&& let Some(content) = view.node_content(&r.key) {
|
||||
println!();
|
||||
for line in content.lines() {
|
||||
println!(" {}", line);
|
||||
|
|
@ -130,7 +129,6 @@ pub fn cmd_search(terms: &[String], pipeline_args: &[String], expand: bool, full
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -219,12 +217,11 @@ fn get_group_content(group: &crate::config::ContextGroup, store: &crate::store::
|
|||
if n.created_at > 0 { return n.created_at; }
|
||||
if let Some(caps) = key_date_re.captures(&n.key) {
|
||||
use chrono::{NaiveDate, TimeZone, Local};
|
||||
if let Ok(d) = NaiveDate::parse_from_str(&caps[1], "%Y-%m-%d") {
|
||||
if let Some(dt) = Local.from_local_datetime(&d.and_hms_opt(0, 0, 0).unwrap()).earliest() {
|
||||
if let Ok(d) = NaiveDate::parse_from_str(&caps[1], "%Y-%m-%d")
|
||||
&& let Some(dt) = Local.from_local_datetime(&d.and_hms_opt(0, 0, 0).unwrap()).earliest() {
|
||||
return dt.timestamp();
|
||||
}
|
||||
}
|
||||
}
|
||||
n.timestamp
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub mod misc;
|
|||
|
||||
/// Exit silently if POC_MEMORY_DRY_RUN=1.
|
||||
pub fn check_dry_run() {
|
||||
if std::env::var("POC_MEMORY_DRY_RUN").map_or(false, |v| v == "1" || v == "true") {
|
||||
if std::env::var("POC_MEMORY_DRY_RUN").is_ok_and(|v| v == "1" || v == "true") {
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,13 +352,12 @@ pub fn cmd_history(key: &[String], full: bool) -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
if !full {
|
||||
if let Some(latest) = versions.last() {
|
||||
if !full
|
||||
&& let Some(latest) = versions.last() {
|
||||
eprintln!("\n--- Latest content (v{}, {}) ---",
|
||||
latest.version, latest.provenance);
|
||||
print!("{}", latest.content);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,10 @@ static CONFIG: OnceLock<RwLock<Arc<Config>>> = OnceLock::new();
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, serde::Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[derive(Default)]
|
||||
pub enum ContextSource {
|
||||
#[serde(alias = "")]
|
||||
#[default]
|
||||
Store,
|
||||
File,
|
||||
Journal,
|
||||
|
|
@ -33,9 +35,6 @@ pub struct ContextGroup {
|
|||
pub source: ContextSource,
|
||||
}
|
||||
|
||||
impl Default for ContextSource {
|
||||
fn default() -> Self { Self::Store }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Deserialize)]
|
||||
#[serde(default)]
|
||||
|
|
@ -133,8 +132,8 @@ impl Config {
|
|||
config.llm_concurrency = config.llm_concurrency.max(1);
|
||||
|
||||
// Resolve API settings: agent_model → models → backend
|
||||
if let Some(model_name) = &config.agent_model {
|
||||
if let Some(model_cfg) = root.get("models").and_then(|m| m.get(model_name.as_str())) {
|
||||
if let Some(model_name) = &config.agent_model
|
||||
&& let Some(model_cfg) = root.get("models").and_then(|m| m.get(model_name.as_str())) {
|
||||
let backend_name = model_cfg.get("backend").and_then(|v| v.as_str()).unwrap_or("");
|
||||
let model_id = model_cfg.get("model_id").and_then(|v| v.as_str()).unwrap_or("");
|
||||
|
||||
|
|
@ -146,7 +145,6 @@ impl Config {
|
|||
}
|
||||
config.api_model = Some(model_id.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Some(config)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,14 +75,12 @@ pub fn digest_parent(store: &Store, key: &str) -> Option<String> {
|
|||
// Look for structural links first (digest:structural provenance)
|
||||
for r in &store.relations {
|
||||
if r.deleted { continue; }
|
||||
if r.source_key == key {
|
||||
if let Some(target) = store.nodes.get(&r.target_key) {
|
||||
if target.node_type == parent_type {
|
||||
if r.source_key == key
|
||||
&& let Some(target) = store.nodes.get(&r.target_key)
|
||||
&& target.node_type == parent_type {
|
||||
return Some(r.target_key.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: match by date for journal→daily
|
||||
if node.node_type == store::NodeType::EpisodicSession {
|
||||
|
|
@ -92,8 +90,8 @@ pub fn digest_parent(store: &Store, key: &str) -> Option<String> {
|
|||
dates.push(store::format_date(node.timestamp));
|
||||
}
|
||||
// Extract date from key patterns like "journal#2026-03-03-..." or "journal#j-2026-03-13t..."
|
||||
if let Some(rest) = key.strip_prefix("journal#j-").or_else(|| key.strip_prefix("journal#")) {
|
||||
if rest.len() >= 10 {
|
||||
if let Some(rest) = key.strip_prefix("journal#j-").or_else(|| key.strip_prefix("journal#"))
|
||||
&& rest.len() >= 10 {
|
||||
let candidate = &rest[..10];
|
||||
if candidate.chars().nth(4) == Some('-') {
|
||||
let date = candidate.to_string();
|
||||
|
|
@ -102,7 +100,6 @@ pub fn digest_parent(store: &Store, key: &str) -> Option<String> {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for date in &dates {
|
||||
for prefix in [&format!("daily-{}", date), &format!("digest#daily#{}", date)] {
|
||||
for (k, n) in &store.nodes {
|
||||
|
|
@ -133,14 +130,12 @@ pub fn digest_children(store: &Store, key: &str) -> Vec<String> {
|
|||
let mut children: Vec<(String, i64)> = Vec::new();
|
||||
for r in &store.relations {
|
||||
if r.deleted { continue; }
|
||||
if r.target_key == key {
|
||||
if let Some(source) = store.nodes.get(&r.source_key) {
|
||||
if source.node_type == child_type {
|
||||
if r.target_key == key
|
||||
&& let Some(source) = store.nodes.get(&r.source_key)
|
||||
&& source.node_type == child_type {
|
||||
children.push((r.source_key.clone(), source.timestamp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback for daily → journal: extract date from key and match
|
||||
if children.is_empty() && node.node_type == store::NodeType::EpisodicDaily {
|
||||
|
|
@ -225,26 +220,23 @@ pub fn show(store: &Store) -> Result<(), String> {
|
|||
// Temporal context
|
||||
let (prev, next) = temporal_neighbors(store, &key);
|
||||
eprintln!();
|
||||
if let Some(ref p) = prev {
|
||||
if let Some(pn) = store.nodes.get(p) {
|
||||
if let Some(ref p) = prev
|
||||
&& let Some(pn) = store.nodes.get(p) {
|
||||
eprintln!(" ← {}", node_summary(pn));
|
||||
eprintln!(" `cursor back`");
|
||||
}
|
||||
}
|
||||
if let Some(ref n) = next {
|
||||
if let Some(nn) = store.nodes.get(n) {
|
||||
if let Some(ref n) = next
|
||||
&& let Some(nn) = store.nodes.get(n) {
|
||||
eprintln!(" → {}", node_summary(nn));
|
||||
eprintln!(" `cursor forward`");
|
||||
}
|
||||
}
|
||||
|
||||
// Hierarchy
|
||||
if let Some(ref parent) = digest_parent(store, &key) {
|
||||
if let Some(pn) = store.nodes.get(parent) {
|
||||
if let Some(ref parent) = digest_parent(store, &key)
|
||||
&& let Some(pn) = store.nodes.get(parent) {
|
||||
eprintln!(" ↑ {}", node_summary(pn));
|
||||
eprintln!(" `cursor up`");
|
||||
}
|
||||
}
|
||||
let children = digest_children(store, &key);
|
||||
if !children.is_empty() {
|
||||
let count = children.len();
|
||||
|
|
|
|||
|
|
@ -572,14 +572,12 @@ fn add_implicit_temporal_edges(
|
|||
fn date_from_key(key: &str) -> Option<NaiveDate> {
|
||||
// Try extracting YYYY-MM-DD after known prefixes
|
||||
for prefix in ["daily-", "journal#j-", "journal#"] {
|
||||
if let Some(rest) = key.strip_prefix(prefix) {
|
||||
if rest.len() >= 10 {
|
||||
if let Ok(d) = NaiveDate::parse_from_str(&rest[..10], "%Y-%m-%d") {
|
||||
if let Some(rest) = key.strip_prefix(prefix)
|
||||
&& rest.len() >= 10
|
||||
&& let Ok(d) = NaiveDate::parse_from_str(&rest[..10], "%Y-%m-%d") {
|
||||
return Some(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
|
@ -650,9 +648,8 @@ fn add_implicit_temporal_edges(
|
|||
monthlies.sort_by_key(|(_, ym)| *ym);
|
||||
|
||||
let add_edge = |adj: &mut HashMap<String, Vec<Edge>>, a: &str, b: &str| {
|
||||
if let Some(edges) = adj.get(a) {
|
||||
if edges.iter().any(|e| e.target == b) { return; }
|
||||
}
|
||||
if let Some(edges) = adj.get(a)
|
||||
&& edges.iter().any(|e| e.target == b) { return; }
|
||||
adj.entry(a.to_owned()).or_default().push(Edge {
|
||||
target: b.to_owned(),
|
||||
strength: 1.0,
|
||||
|
|
|
|||
|
|
@ -384,11 +384,10 @@ impl Stage {
|
|||
}
|
||||
|
||||
// Try algorithm parse first (bare words, no colon)
|
||||
if !s.contains(':') {
|
||||
if let Ok(algo) = AlgoStage::parse(s) {
|
||||
if !s.contains(':')
|
||||
&& let Ok(algo) = AlgoStage::parse(s) {
|
||||
return Ok(Stage::Algorithm(algo));
|
||||
}
|
||||
}
|
||||
|
||||
// Algorithm with params: "spread,max_hops=4" (contains comma but no colon)
|
||||
if s.contains(',') && !s.contains(':') {
|
||||
|
|
@ -748,12 +747,11 @@ pub fn run_transform(
|
|||
value += 1;
|
||||
}
|
||||
for (nbr, _) in graph.neighbors(k) {
|
||||
if input_keys.contains(nbr.as_str()) {
|
||||
if cover_count.get(nbr.as_str()).copied().unwrap_or(0) < REQUIRED_COVERAGE {
|
||||
if input_keys.contains(nbr.as_str())
|
||||
&& cover_count.get(nbr.as_str()).copied().unwrap_or(0) < REQUIRED_COVERAGE {
|
||||
value += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
(k.clone(), value)
|
||||
})
|
||||
.max_by_key(|(_, v)| *v);
|
||||
|
|
@ -814,7 +812,7 @@ pub fn match_seeds_opts(
|
|||
key_map.insert(lkey.clone(), (key.to_owned(), weight as f64));
|
||||
|
||||
// Split key on hyphens, underscores, dots, hashes for component matching
|
||||
for component in lkey.split(|c: char| c == '-' || c == '_' || c == '.' || c == '#') {
|
||||
for component in lkey.split(['-', '_', '.', '#']) {
|
||||
if component.len() >= 3 {
|
||||
component_map.entry(component.to_owned())
|
||||
.or_default()
|
||||
|
|
@ -833,8 +831,8 @@ pub fn match_seeds_opts(
|
|||
}
|
||||
|
||||
// Strategy 2: key component match (0.5× weight) — only when explicitly requested
|
||||
if component_match {
|
||||
if let Some(matches) = component_map.get(term.as_str()) {
|
||||
if component_match
|
||||
&& let Some(matches) = component_map.get(term.as_str()) {
|
||||
for (orig_key, node_weight) in matches {
|
||||
let score = term_weight * node_weight * 0.5;
|
||||
*seed_map.entry(orig_key.clone()).or_insert(0.0) += score;
|
||||
|
|
@ -842,7 +840,6 @@ pub fn match_seeds_opts(
|
|||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 3: content match (0.2× weight) — only when explicitly requested
|
||||
if content_fallback {
|
||||
|
|
|
|||
|
|
@ -393,13 +393,12 @@ fn execute_parsed(
|
|||
|
||||
for r in &mut results {
|
||||
for f in &needed {
|
||||
if !r.fields.contains_key(f) {
|
||||
if let Some(v) = resolve_field(f, &r.key, store, graph) {
|
||||
if !r.fields.contains_key(f)
|
||||
&& let Some(v) = resolve_field(f, &r.key, store, graph) {
|
||||
r.fields.insert(f.clone(), v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply pipeline stages
|
||||
let mut has_sort = false;
|
||||
|
|
@ -432,7 +431,7 @@ fn execute_parsed(
|
|||
.map(|r| (r.key.clone(), graph.degree(&r.key) as f64))
|
||||
.collect();
|
||||
let xform = super::engine::Transform::DominatingSet;
|
||||
items = super::engine::run_transform(&xform, items, store, &graph);
|
||||
items = super::engine::run_transform(&xform, items, store, graph);
|
||||
let keep: std::collections::HashSet<String> = items.into_iter().map(|(k, _)| k).collect();
|
||||
results.retain(|r| keep.contains(&r.key));
|
||||
}
|
||||
|
|
@ -611,8 +610,8 @@ fn print_connectivity(results: &[QueryResult], graph: &Graph) {
|
|||
println!(" {} (degree {})", node, graph.degree(node));
|
||||
}
|
||||
// Show a sample path between first two nodes
|
||||
if component.len() >= 2 {
|
||||
if let Some(path) = bfs_path(graph, &component[0], &component[1], max_hops) {
|
||||
if component.len() >= 2
|
||||
&& let Some(path) = bfs_path(graph, &component[0], &component[1], max_hops) {
|
||||
print!(" path: ");
|
||||
for (j, step) in path.iter().enumerate() {
|
||||
if j > 0 { print!(" → "); }
|
||||
|
|
@ -626,15 +625,13 @@ fn print_connectivity(results: &[QueryResult], graph: &Graph) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Suggest link-add commands for islands
|
||||
if !islands.is_empty() {
|
||||
if let Some(ref hub) = largest_cluster {
|
||||
if !islands.is_empty()
|
||||
&& let Some(ref hub) = largest_cluster {
|
||||
println!("\nFix islands:");
|
||||
for island in &islands {
|
||||
println!(" poc-memory graph link-add {} {}", island, hub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ pub fn decompose(graph: &Graph, k: usize) -> SpectralResult {
|
|||
|
||||
for (i, key) in keys.iter().enumerate() {
|
||||
for (neighbor, strength) in graph.neighbors(key) {
|
||||
if let Some(&j) = key_to_idx.get(neighbor.as_str()) {
|
||||
if j > i { // each edge once
|
||||
if let Some(&j) = key_to_idx.get(neighbor.as_str())
|
||||
&& j > i { // each edge once
|
||||
let w = strength as f64;
|
||||
adj_entries.push((i, j, w));
|
||||
degree[i] += w;
|
||||
|
|
@ -86,7 +86,6 @@ pub fn decompose(graph: &Graph, k: usize) -> SpectralResult {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build normalized Laplacian: L_sym = I - D^{-1/2} A D^{-1/2}
|
||||
let mut laplacian = Mat::<f64>::zeros(n, n);
|
||||
|
|
@ -445,14 +444,13 @@ pub fn analyze_positions(
|
|||
let mut node_dists: Vec<(String, u32, f64)> = Vec::new();
|
||||
|
||||
for (key, coords) in &emb.coords {
|
||||
if let Some(&comm) = communities.get(key) {
|
||||
if let Some(center) = centers.get(&comm) {
|
||||
if let Some(&comm) = communities.get(key)
|
||||
&& let Some(center) = centers.get(&comm) {
|
||||
let dist = weighted_distance(coords, center, &weights);
|
||||
by_community.entry(comm).or_default().push(dist);
|
||||
node_dists.push((key.clone(), comm, dist));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Median distance per community for outlier scoring
|
||||
let medians: HashMap<u32, f64> = by_community.into_iter()
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@ impl Store {
|
|||
let nodes_size = fs::metadata(&nodes_p).map(|m| m.len()).unwrap_or(0);
|
||||
let rels_size = fs::metadata(&rels_p).map(|m| m.len()).unwrap_or(0);
|
||||
|
||||
if let Ok(data) = fs::read(&state_p) {
|
||||
if data.len() >= CACHE_HEADER_LEN && data[..4] == CACHE_MAGIC {
|
||||
if let Ok(data) = fs::read(&state_p)
|
||||
&& data.len() >= CACHE_HEADER_LEN && data[..4] == CACHE_MAGIC {
|
||||
let cached_nodes = u64::from_le_bytes(data[4..12].try_into().unwrap());
|
||||
let cached_rels = u64::from_le_bytes(data[12..20].try_into().unwrap());
|
||||
|
||||
if cached_nodes == nodes_size && cached_rels == rels_size {
|
||||
if let Ok(mut store) = bincode::deserialize::<Store>(&data[CACHE_HEADER_LEN..]) {
|
||||
if cached_nodes == nodes_size && cached_rels == rels_size
|
||||
&& let Ok(mut store) = bincode::deserialize::<Store>(&data[CACHE_HEADER_LEN..]) {
|
||||
// Rebuild uuid_to_key (skipped by serde)
|
||||
for (key, node) in &store.nodes {
|
||||
store.uuid_to_key.insert(node.uuid, key.clone());
|
||||
|
|
@ -67,16 +67,13 @@ impl Store {
|
|||
store.loaded_nodes_size = nodes_size;
|
||||
store.loaded_rels_size = rels_size;
|
||||
// Bootstrap: write rkyv snapshot if missing
|
||||
if !snapshot_path().exists() {
|
||||
if let Err(e) = store.save_snapshot(cached_nodes, cached_rels) {
|
||||
if !snapshot_path().exists()
|
||||
&& let Err(e) = store.save_snapshot(cached_nodes, cached_rels) {
|
||||
eprintln!("rkyv bootstrap: {}", e);
|
||||
}
|
||||
}
|
||||
return Ok(store);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stale or no cache — rebuild from capnp logs
|
||||
let mut store = Store::default();
|
||||
|
|
@ -513,7 +510,7 @@ impl Store {
|
|||
pub fn is_segment_mined(&self, transcript_id: &str, segment_index: u32, agent: &str) -> bool {
|
||||
self.transcript_progress
|
||||
.get(&(transcript_id.to_string(), segment_index))
|
||||
.map_or(false, |agents| agents.contains(agent))
|
||||
.is_some_and(|agents| agents.contains(agent))
|
||||
}
|
||||
|
||||
/// Mark a transcript segment as successfully processed.
|
||||
|
|
@ -529,31 +526,28 @@ impl Store {
|
|||
pub fn migrate_transcript_progress(&mut self) -> Result<usize, String> {
|
||||
let mut segments = Vec::new();
|
||||
|
||||
for (key, _node) in &self.nodes {
|
||||
for key in self.nodes.keys() {
|
||||
// _observed-transcripts-f-{UUID}.{segment}
|
||||
if let Some(rest) = key.strip_prefix("_observed-transcripts-f-") {
|
||||
if let Some((uuid, seg_str)) = rest.rsplit_once('.') {
|
||||
if let Ok(seg) = seg_str.parse::<u32>() {
|
||||
if let Some((uuid, seg_str)) = rest.rsplit_once('.')
|
||||
&& let Ok(seg) = seg_str.parse::<u32>() {
|
||||
segments.push(new_transcript_segment(uuid, seg, "observation"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// _mined-transcripts#f-{UUID}.{segment}
|
||||
else if let Some(rest) = key.strip_prefix("_mined-transcripts#f-") {
|
||||
if let Some((uuid, seg_str)) = rest.rsplit_once('.') {
|
||||
if let Ok(seg) = seg_str.parse::<u32>() {
|
||||
if let Some((uuid, seg_str)) = rest.rsplit_once('.')
|
||||
&& let Ok(seg) = seg_str.parse::<u32>() {
|
||||
segments.push(new_transcript_segment(uuid, seg, "experience"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// _mined-transcripts-f-{UUID}.{segment}
|
||||
else if let Some(rest) = key.strip_prefix("_mined-transcripts-f-") {
|
||||
if let Some((uuid, seg_str)) = rest.rsplit_once('.') {
|
||||
if let Ok(seg) = seg_str.parse::<u32>() {
|
||||
if let Some((uuid, seg_str)) = rest.rsplit_once('.')
|
||||
&& let Ok(seg) = seg_str.parse::<u32>() {
|
||||
segments.push(new_transcript_segment(uuid, seg, "experience"));
|
||||
}
|
||||
}
|
||||
}
|
||||
// _facts-{UUID} (whole-file, segment 0)
|
||||
else if let Some(uuid) = key.strip_prefix("_facts-") {
|
||||
if !uuid.contains('-') || uuid.len() < 30 { continue; } // skip non-UUID
|
||||
|
|
|
|||
|
|
@ -352,11 +352,10 @@ impl Node {
|
|||
/// is empty (old record), fall back to the deprecated provenanceOld enum.
|
||||
pub fn from_capnp_migrate(r: memory_capnp::content_node::Reader<'_>) -> Result<Self, String> {
|
||||
let mut node = Self::from_capnp(r)?;
|
||||
if node.provenance.is_empty() {
|
||||
if let Ok(old) = r.get_provenance_old() {
|
||||
if node.provenance.is_empty()
|
||||
&& let Ok(old) = r.get_provenance_old() {
|
||||
node.provenance = Provenance::from_capnp(old).label().to_string();
|
||||
}
|
||||
}
|
||||
// Sanitize timestamps: old capnp records have raw offsets instead
|
||||
// of unix epoch. Anything past year 2100 (~4102444800) is bogus.
|
||||
const MAX_SANE_EPOCH: i64 = 4_102_444_800;
|
||||
|
|
@ -383,11 +382,10 @@ capnp_message!(Relation,
|
|||
impl Relation {
|
||||
pub fn from_capnp_migrate(r: memory_capnp::relation::Reader<'_>) -> Result<Self, String> {
|
||||
let mut rel = Self::from_capnp(r)?;
|
||||
if rel.provenance.is_empty() {
|
||||
if let Ok(old) = r.get_provenance_old() {
|
||||
if rel.provenance.is_empty()
|
||||
&& let Ok(old) = r.get_provenance_old() {
|
||||
rel.provenance = Provenance::from_capnp(old).label().to_string();
|
||||
}
|
||||
}
|
||||
Ok(rel)
|
||||
}
|
||||
}
|
||||
|
|
@ -503,11 +501,10 @@ pub(crate) fn read_text(result: capnp::Result<capnp::text::Reader>) -> String {
|
|||
/// Read a capnp data field as [u8; 16], zero-padded
|
||||
pub(crate) fn read_uuid(result: capnp::Result<&[u8]>) -> [u8; 16] {
|
||||
let mut out = [0u8; 16];
|
||||
if let Ok(data) = result {
|
||||
if data.len() >= 16 {
|
||||
if let Ok(data) = result
|
||||
&& data.len() >= 16 {
|
||||
out.copy_from_slice(&data[..16]);
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,13 +107,11 @@ pub fn find_last_compaction(data: &[u8]) -> Option<usize> {
|
|||
if let Some(content) = obj.get("message")
|
||||
.and_then(|m| m.get("content"))
|
||||
.and_then(|c| c.as_str())
|
||||
{
|
||||
if content.starts_with("This session is being continued") {
|
||||
&& content.starts_with("This session is being continued") {
|
||||
let offset = obj_bytes.as_ptr() as usize - data.as_ptr() as usize;
|
||||
return Some(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ fn render_overview(frame: &mut Frame, app: &App, area: Rect) {
|
|||
let [health_area, tasks_area] =
|
||||
Layout::vertical([Constraint::Length(12), Constraint::Min(0)]).areas(area);
|
||||
|
||||
if let Some(ref gh) = app.status.as_ref().and_then(|s| s.graph_health.as_ref()) {
|
||||
if let Some(gh) = app.status.as_ref().and_then(|s| s.graph_health.as_ref()) {
|
||||
render_health(frame, gh, health_area);
|
||||
} else {
|
||||
let p = Paragraph::new(" No graph health data available")
|
||||
|
|
@ -689,16 +689,14 @@ fn render_agent_tab(frame: &mut Frame, app: &App, agent_type: &str, area: Rect)
|
|||
}
|
||||
|
||||
// Error
|
||||
if matches!(t.status, TaskStatus::Failed) {
|
||||
if let Some(ref r) = t.result {
|
||||
if let Some(ref err) = r.error {
|
||||
if matches!(t.status, TaskStatus::Failed)
|
||||
&& let Some(ref r) = t.result
|
||||
&& let Some(ref err) = r.error {
|
||||
lines.push(Line::from(vec![
|
||||
Span::styled(" error: ", Style::default().fg(Color::Red)),
|
||||
Span::styled(err.as_str(), Style::default().fg(Color::Red)),
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lines.push(Line::raw(""));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,11 +63,10 @@ pub fn parse_timestamp_to_epoch(ts: &str) -> Option<i64> {
|
|||
use chrono::{Local, NaiveDateTime, TimeZone};
|
||||
let formats = ["%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M"];
|
||||
for fmt in &formats {
|
||||
if let Ok(ndt) = NaiveDateTime::parse_from_str(ts, fmt) {
|
||||
if let Some(dt) = Local.from_local_datetime(&ndt).earliest() {
|
||||
if let Ok(ndt) = NaiveDateTime::parse_from_str(ts, fmt)
|
||||
&& let Some(dt) = Local.from_local_datetime(&ndt).earliest() {
|
||||
return Some(dt.timestamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue