Make engram deletes/updates immutable (tombstone + supersede) #82
Reference in New Issue
Block a user
Delete Branch "feat/immutable-engram-deletes"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Make the soul's engram
deleteandupdateroutes immutable, and regeneratedist/soul.c.Why
Three handlers were destroying engram nodes:
memory/delete,node/delete→engram_forget(frees the node and drops its incident edges)node/update→ created a replacement thenengram_forget'd the original, with no link backThat violates the day-one rule that engram nodes are immutable — API callers could silently, irrecoverably destroy memory.
memory/updatewas already correct (supersede-with-edge); the others were not.The fix (mirrors
memory/updateand knowledge evolve/promote)node/update→ create the new node, wire asupersedesedge new→old, keep the original. Noengram_forget.memory/delete+node/delete→ tombstone: keep the node and all its edges; create aTombstonemarker node (content = target id, labeltombstone:<id>) wired with atombstonesedge. Neverengram_forget. Default bounded list reads (handle_api_list_typed/ the memory list) hide tombstoned nodes and the markers;?include_deleted=1returns them, and internal cognition +/api/graph/nodesstill traverse them.Deliberately deferred (documented in code)
Full-graph hiding on
/api/graph/nodesis not done at the el layer:json_array_getis O(index), so filtering that endpoint (the app calls it withlimitup to 999999) would be O(n²). That hide needs a runtime scan filter (skip tombstoned inengram_scan_nodes_json) and is a separate follow-up. Tombstoned nodes remain present and traversable there, taggedstatus:deletedvia the marker edge.Regen + verification
dist/soul.cregenerated from these sources as a flat single-TU amalgamation, compiled under a 3GB physical-RSS watchdog (macOS ignoresulimit -v), peak ~32MB. Diff is exactlyneuron-api.el+dist/soul.c.hotfix/elc-source-typos(where the shippedsoul.c/ neuron-ui PR #144 came from) so the diff stays minimal.neuron-ui/scripts/verify-soul-contract.shagainst the freshly-built binary on a throwaway port:The stale/destructive binary fails the same gate (memory-delete / node-update / node-delete → DESTROYED), so the gate discriminates.
Never touched the live soul (:7770), engram (:8742),
~/.neuron, or the running :7799 sandbox — all build + test on throwaway paths/ports.Do not merge — going live is a controlled-deploy call.
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.Closing as superseded. The immutability arc (tombstone + supersede for engram deletes/updates) already landed on the launch branch via the merged #94 ("Immutability fix (tombstone/supersede) on the launch branch"), and the same source landed on main through the merged #83 ("Land immutability arc + CI soul-contract gate on main") — which used this very branch. This PR (base
hotfix/elc-source-typos, now stale/unmergeable) adds nothing beyond what #94/#83 shipped. Deleting the head branchfeat/immutable-engram-deletesas part of cleanup.Pull request closed