Make engram deletes/updates immutable (tombstone + supersede) #82
Open
will.anderson
wants to merge 4 commits from
feat/immutable-engram-deletes into hotfix/elc-source-typos
pull from: feat/immutable-engram-deletes
merge into: :hotfix/elc-source-typos
:main
:reconcile/hotfix-to-main-launch
:hotfix/elc-source-typos
:fix/safety-contact-truncation
:fix/genesis-boot-crash
:fix/immutable-on-hotfix
:feat/bounded-persona-floor
:ci/rdynamic-http-handler
:ci/harden-gate-boot
:feat/neuron-dev-setup
:feat/immutable-engram-deletes
:feat/agent-phase1-soul
:salvage/elh-state-20260704
:hotfix/trackb-threat-to-others
:feat/soul-model-self-report
:feat/openai-format-providers
:feat/plan-mode-endpoint
:fix/operator-identity-home-resolution
:fix/wrapper-backlog-endpoints
:fix/list-typed-slice-offset
:feat/connectors-call-route
:fix/chat-vision-attachments
:fix/prevent-engram-corruption
:fix/emergency-regressions
:fix/session-continuity-hook
:fix/context-dedup-shared-ids
:fix/engram-float-parser
:improve/recall-context-format
:improve/recall-context-dedup
:improve/recall-cross-session-continuity
:improve/recall-emotional-recall
:improve/recall-activation-seed
:improve/recall-recall-completeness
:improve/recall-temporal-precision
:improve/recall-engram-scoring
:improve/recall-recall-reliability
:improve/recall-session-start-recall
:improve/reliability-engram-write
:improve/reliability-state-management
:improve/soul-memory-formation
:improve/safety-crisis-detection
:improve/reliability-route-error-recovery
:improve/reliability-llm-retry
:improve/reliability-session-boundary
:improve/reliability-safety-resilience
:improve/reliability-engram-connection
:improve/soul-routes-api
:improve/reliability-cross-session-affective
:propose/agent-workspace-root-read
:improve/reliability-conv-history
:improve/soul-strip
:improve/soul-chat-pipeline
:docs/conversation-retrieval-design
:propose/no-fake-tools-in-chat-mode
:fix/ci-soul-build-single-file
:fix/canonical-self-bridge
:feat/agent-tool-workspace-scope
:fix/agentic-tools-duplicate-web-search
:green/agentic-fixes
:feat/connectors-soul
:feat/layer-safety
:feat/layer-imprint
:feat/layer-stewardship
:test/layer-composition
:test/layer-safety
:test/layer-stewardship
:test/layer-imprint
:feat/memory-delete-update
:feat/native-web-search
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
290a637883 |
ci: gate the Linux soul on the contract before publishing
Wire the soul contract gate into ci.yaml as a hard block between the cc build and the Publish-to-Artifact-Registry step. A non-zero gate fails the build, so a stale (route-404ing) or memory-destroying (hard-deleting) soul can never publish neuron-soul to foundation-prod or blue-green deploy to GKE — the same class-fix now guarding the desktop builds, extended to prod. Vendors scripts/verify-soul-contract.sh (copied from neuron-ui; the route contract is baked in, so it's portable POSIX bash/curl with no neuron-ui source dependency). It boots dist/neuron on a throwaway port with a throwaway HOME/engram/cgi — never touching ~/.neuron or any live service — and checks PRESENCE (every app route answered) + IMMUTABILITY (no engram write route hard-deletes; deletes/forgets tombstone). Adds curl to the build deps for the probe. |
||
|
|
40d800195a |
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.
|
||
|
|
f3034d23f7 |
Regenerate per-module dist/neuron-api.c for the immutability fix
soul.c (the macOS single-TU amalgamation) already carries the tombstone/supersede change, but the Windows/Linux build path compiles the per-module dist/*.c instead (build-soul-windows.sh excludes soul.c). That path was still pulling the stale, destructive dist/neuron-api.c — so without this the cross-compiled neuron.exe would keep hard-deleting engram nodes even though the source is fixed. Regenerated with `elc --emit-header neuron-api.el`: no engram_forget in memory_delete/node_delete (tombstone), supersedes edge in node_update. Portable C — identical for macOS/Windows/Linux; only the runtime it links against differs. |
||
|
|
d337fcb265 |
Make engram deletes/updates immutable (tombstone + supersede)
The soul was hard-deleting engram nodes: memory/delete and node/delete called engram_forget (frees the node and drops its incident edges), and node/update created a replacement then forgot the original with no link back. That violates the day-one rule that engram nodes are immutable — memory could be silently, irrecoverably destroyed via the API. Convert the three destructive handlers to Will's immutability semantics, mirroring the pattern memory/update and knowledge evolve/promote already use: - node/update -> create the new node, wire a "supersedes" edge new->old, KEEP the original. No engram_forget. (Was: create + forget old, no edge.) - memory/delete and node/delete -> TOMBSTONE: keep the node AND its edges, create a Tombstone marker node (content = target id, label "tombstone:<id>") wired with a "tombstones" edge. Never engram_forget. Default bounded list reads (handle_api_list_typed / the memory list) hide tombstoned nodes and the markers; ?include_deleted=1 returns them, and internal cognition + /api/graph/nodes still traverse them. memory/update was already correct and is unchanged. Full-graph hiding on /api/graph/nodes is deliberately NOT done at the el layer: json_array_get is O(index), so filtering that endpoint (called with limit up to 999999) would be O(n^2). That hide needs a runtime scan filter and is a separate follow-up; nodes there remain traversable, tagged status:deleted via the marker edge. Regenerated dist/soul.c from these sources (flat single-TU amalgamation, compiled under a 3GB physical-RSS watchdog, peak ~32MB). Verified with scripts/verify-soul-contract.sh in neuron-ui: PRESENCE passes (all 27 routes) and IMMUTABILITY passes (all four mutation routes KEPT; deletes produce a real tombstone marker and hide from the default list). |