Tombstone the remaining forget paths (close the immutability arc)
Phase 1 tombstoned memory/delete + node/delete, but the generic forget
path was still destructive. This routes every forget through the same
tombstone semantics so nothing in the daemon can hard-delete an engram
node anymore.
Canonical helper: mem_tombstone (memory.el, imported first so every module
can call it) — keep the node + its edges, record a Tombstone marker, never
engram_forget. neuron-api's tombstone_node now delegates to it (single
source of truth).
Per-path before -> after:
- memory.el `mem_forget` hard delete (engram_forget) -> tombstone. This
alone fixes both callers: the /api/neuron/memory/forget route
(handle_api_forget) and the cultivate op=="forget".
- awareness.el autonomous `forget` action engram_forget -> mem_tombstone.
The soul can no longer autonomously hard-delete a memory.
- mcp-wrapper tool_forget was a FAKE no-op that returned {"ok","deleted"}
without deleting OR tombstoning -> now routes to the soul's tombstoning
/api/neuron/memory/delete; tool description fixed to say it
supersedes/tombstones (recoverable), not "Remove a node".
Left intentionally as hard deletes (internal GC / lifecycle, not user
memory, all call engram_forget directly): session-summary replace
(chat.el), mem_consolidate dedup (memory.el), session-start telemetry
pruning (soul.el), session lifecycle (sessions.el).
Regenerated both ship paths under a 3GB physical-RSS watchdog (peak ~32MB):
dist/soul.c (single-TU amalgamation, macOS/Linux) and the per-module
dist/{memory,awareness,neuron-api}.c (Windows/Linux build). Verified: no
forget handler calls engram_forget; a forget leaves the node present +
tombstone marker. Gate (neuron-ui verify-soul-contract.sh, new memory-forget
row): PRESENCE + IMMUTABILITY PASS.
This commit is contained in:
+8
-12
@@ -114,15 +114,8 @@ fn api_not_persisted(id: String) -> String {
|
||||
// bounded list reads hide tombstoned nodes (memory_hide_tombstoned); internal
|
||||
// cognition and explicit ?include_deleted reads still see them.
|
||||
fn tombstone_node(id: String) -> String {
|
||||
let tags: String = "[\"Tombstone\",\"status:deleted\"]"
|
||||
let marker: String = engram_node_full(
|
||||
id, "Tombstone", "tombstone:" + id,
|
||||
el_from_float(0.01), el_from_float(0.01), el_from_float(1.0),
|
||||
"Episodic", tags)
|
||||
if !str_eq(marker, "") {
|
||||
engram_connect(marker, id, el_from_float(1.0), "tombstones")
|
||||
}
|
||||
return marker
|
||||
// Delegates to the canonical helper in memory.el (single source of truth).
|
||||
return mem_tombstone(id)
|
||||
}
|
||||
|
||||
// tombstoned_id_set — delimited "|id1|id2|" of every tombstoned target id.
|
||||
@@ -572,13 +565,15 @@ fn handle_api_link_entities(body: String) -> String {
|
||||
return "{\"ok\":true,\"from_id\":\"" + from_id + "\",\"to_id\":\"" + to_id + "\",\"relation\":\"" + eff_relation + "\"}"
|
||||
}
|
||||
|
||||
// handle_api_forget — delete a node by ID. Blocked for protected identity nodes.
|
||||
// handle_api_forget — TOMBSTONE a node by ID (immutable; mem_forget now
|
||||
// tombstones). The node + edges are kept and recoverable. Blocked for protected
|
||||
// identity nodes.
|
||||
fn handle_api_forget(body: String) -> String {
|
||||
let node_id: String = json_get(body, "id")
|
||||
if str_eq(node_id, "") { return api_err("id is required") }
|
||||
if is_protected_node(node_id) { return api_err_protected(node_id) }
|
||||
mem_forget(node_id)
|
||||
return "{\"ok\":true,\"id\":\"" + node_id + "\"}"
|
||||
return "{\"ok\":true,\"id\":\"" + node_id + "\",\"tombstoned\":true}"
|
||||
}
|
||||
|
||||
// handle_api_evolve_memory — evolve a Memory node. Blocked for protected identity nodes.
|
||||
@@ -693,8 +688,9 @@ fn handle_api_cultivate(body: String) -> String {
|
||||
if str_eq(op, "forget") {
|
||||
let node_id: String = json_get(body, "id")
|
||||
if str_eq(node_id, "") { return api_err("id is required") }
|
||||
// Immutable: mem_forget now tombstones (keep node + edges), never hard-delete.
|
||||
mem_forget(node_id)
|
||||
return "{\"ok\":true,\"id\":\"" + node_id + "\",\"cultivated\":true}"
|
||||
return "{\"ok\":true,\"id\":\"" + node_id + "\",\"tombstoned\":true,\"cultivated\":true}"
|
||||
}
|
||||
|
||||
if str_eq(op, "link_entities") {
|
||||
|
||||
Reference in New Issue
Block a user