agents: add DEMOTE action for redundancy cleanup

New action type that halves a node's weight (min 0.05), enabling
extractors to mark redundant nodes for decay without deleting them.

Parser, apply logic, depth computation, and display all updated.
This commit is contained in:
ProofOfConcept 2026-03-10 22:57:02 -04:00
parent 8ba58ce9cd
commit 9d29e392a8
2 changed files with 34 additions and 1 deletions

View file

@ -231,6 +231,8 @@ pub fn apply_consolidation(store: &mut Store, do_apply: bool, report_key: Option
println!(" WRITE {}", key), println!(" WRITE {}", key),
knowledge::ActionKind::Refine { key, .. } => knowledge::ActionKind::Refine { key, .. } =>
println!(" REFINE {}", key), println!(" REFINE {}", key),
knowledge::ActionKind::Demote { key } =>
println!(" DEMOTE {}", key),
} }
} }
println!("\nTo apply: poc-memory apply-consolidation --apply"); println!("\nTo apply: poc-memory apply-consolidation --apply");

View file

@ -48,6 +48,9 @@ pub enum ActionKind {
key: String, key: String,
content: String, content: String,
}, },
Demote {
key: String,
},
} }
#[derive(Debug, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
@ -161,10 +164,27 @@ pub fn parse_refines(text: &str) -> Vec<Action> {
.collect() .collect()
} }
pub fn parse_demotes(text: &str) -> Vec<Action> {
let re = Regex::new(r"(?m)^DEMOTE\s+(\S+)").unwrap();
re.captures_iter(text)
.map(|cap| Action {
kind: ActionKind::Demote {
key: cap[1].to_string(),
},
confidence: Confidence::Medium,
weight: 0.5,
depth: -1,
applied: None,
rejected_reason: None,
})
.collect()
}
pub fn parse_all_actions(text: &str) -> Vec<Action> { pub fn parse_all_actions(text: &str) -> Vec<Action> {
let mut actions = parse_write_nodes(text); let mut actions = parse_write_nodes(text);
actions.extend(parse_links(text)); actions.extend(parse_links(text));
actions.extend(parse_refines(text)); actions.extend(parse_refines(text));
actions.extend(parse_demotes(text));
actions actions
} }
@ -223,7 +243,7 @@ fn agent_base_depth(agent: &str) -> Option<i32> {
pub fn compute_action_depth(db: &DepthDb, action: &Action, agent: &str) -> i32 { pub fn compute_action_depth(db: &DepthDb, action: &Action, agent: &str) -> i32 {
match &action.kind { match &action.kind {
ActionKind::Link { .. } => -1, ActionKind::Link { .. } | ActionKind::Demote { .. } => -1,
ActionKind::Refine { key, .. } => db.get(key), ActionKind::Refine { key, .. } => db.get(key),
ActionKind::WriteNode { covers, .. } => { ActionKind::WriteNode { covers, .. } => {
if !covers.is_empty() { if !covers.is_empty() {
@ -307,6 +327,14 @@ pub fn apply_action(
let stamped = stamp_content(content, agent, timestamp, depth); let stamped = stamp_content(content, agent, timestamp, depth);
store.upsert_provenance(key, &stamped, provenance).is_ok() store.upsert_provenance(key, &stamped, provenance).is_ok()
} }
ActionKind::Demote { key } => {
if let Some(node) = store.nodes.get_mut(key) {
node.weight = (node.weight * 0.5).max(0.05);
true
} else {
false
}
}
} }
} }
@ -696,6 +724,9 @@ fn run_cycle(
ActionKind::Refine { key, .. } => { ActionKind::Refine { key, .. } => {
eprintln!(" REFINE {} depth={}", key, depth); eprintln!(" REFINE {} depth={}", key, depth);
} }
ActionKind::Demote { key } => {
eprintln!(" DEMOTE {}", key);
}
} }
if apply_action(&mut store, action, agent_name, &timestamp, depth) { if apply_action(&mut store, action, agent_name, &timestamp, depth) {