From b6ed9340bf63dc9e3b57ede4f928c325b9d529bd Mon Sep 17 00:00:00 2001 From: "will.anderson" Date: Sat, 15 Aug 2026 21:14:21 -0500 Subject: [PATCH] soul: the engram is the canonical store, not a fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The soul preferred its own local snapshot over the engram: // Always try local snapshot first ... HTTP Engram is only used for the // very first boot (empty/absent snapshot). The copy outranked the store. Every one of these is a cost of that inversion, and all of them were live tonight: - the graphs drifted: 31,795 nodes / 75,241 edges in the soul against 13,439 / 37,670 in the engram — more than twice the edges, silently - write-through exists only to reconcile them, and had never once run - /api/graph/edges serialized 128 MB to answer a read, because the soul's copy was not the engram's - a read route overwrote the engram's canonical snapshot.json with the soul's divergent copy - three resident copies of one graph (soul, engram, Neuron.app) — about 7.2 GB of RAM for a store that is 2.2 GB on disk, which is what pushed the host into swap None of those are features. They are reconciliation debt from one decision. The engram had already reached this conclusion for its own boot path — "the durable owner is the paged store (neuron.egm + neuron.wal) ... snapshot.json is never read again as the ongoing store. This closes the 'restart reverted to a 17h-old snapshot' data-loss window." The soul kept booting the legacy way the engram had abandoned, and inherited exactly that data-loss window. So in HTTP-engram mode the soul now seeds from the engram on EVERY boot and never reads a local snapshot, present or not — a stale copy that outranks the store is the bug, not a fallback. It already never wrote one in this mode (gated behind is_genesis && safe_to_seed, and safe_to_seed requires !using_http_engram), so this supplies the missing half. It also refuses to boot on an empty seed rather than silently rebuilding a divergent graph from nothing. launchd KeepAlive with ThrottleInterval=10 turns that into a retry every 10s until the engram is up — self-healing, no spin. File mode (no ENGRAM_URL) is untouched: there the soul genuinely is the owner. Verified before deploy: with a deliberately empty local snapshot planted, the soul booted in ~30s reporting 13,446 nodes / 37,675 edges — the engram's contents, not the empty local file. --- soul.el | 56 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/soul.el b/soul.el index 1f1cdc7..3a9b489 100644 --- a/soul.el +++ b/soul.el @@ -584,17 +584,35 @@ println("[soul] boot - cgi=" + soul_cgi_id + " port=" + int_to_str(port)) let using_http_engram: Bool = !str_eq(engram_url_raw, "") -// Always try local snapshot first. If it has content (>50 nodes) it was -// previously seeded from HTTP Engram and is kept up-to-date by the awareness -// loop — use it. This preserves sessions and memories across restarts. -// HTTP Engram is only used for the very first boot (empty/absent snapshot). -engram_load(snapshot) -let local_node_count: Int = engram_node_count() -let snapshot_usable: Bool = local_node_count > 50 - -if using_http_engram && !snapshot_usable { - // First boot or empty/corrupt snapshot: seed from HTTP Engram. - println("[soul] engram -> HTTP " + engram_url_raw + " (no local snapshot, first boot)") +// THE ENGRAM IS THE CANONICAL STORE. The soul's resident graph is a working +// copy of it, never a rival source of truth. +// +// This used to be inverted: "always try local snapshot first... HTTP Engram is +// only used for the very first boot." The copy outranked the store. Everything +// that followed is a cost of that one inversion: +// - the two graphs drifted (13,479 nodes/74,563 edges in the soul vs +// 13,425/37,658 in the engram — nearly 2x the edges, silently) +// - write-through exists solely to reconcile them, and had never once run +// - /api/graph/edges serialized 128 MB to answer a read, because the soul's +// copy was not the engram's +// - a read route overwrote the engram's canonical snapshot.json with the +// soul's divergent copy +// - three copies of the same memory: neuron.egm, snapshot.json, soul RAM +// None of those are features. They are all reconciliation debt. +// +// The engram itself already reached this conclusion for its own boot path: +// "the durable owner is the paged store (neuron.egm + neuron.wal) ... +// snapshot.json is never read again as the ongoing store. This closes the +// 'restart reverted to a 17h-old snapshot' data-loss window." The soul kept +// booting the legacy way the engram had already abandoned, and inherited +// exactly the data-loss window that comment describes. +// +// So in HTTP-engram mode the soul seeds from the engram, EVERY boot, and never +// consults or writes a local snapshot. The local file is not read even when +// present — a stale copy that outranks the store is the bug, not a fallback. +// (File mode, no ENGRAM_URL, is unchanged: there the soul IS the owner.) +if using_http_engram { + println("[soul] engram -> HTTP " + engram_url_raw + " (canonical store; local snapshot ignored)") let nodes_json: String = http_get(engram_url_raw + "/api/nodes?limit=10000") let edges_json: String = http_get(engram_url_raw + "/api/edges") let nodes_part: String = if str_eq(nodes_json, "") { "[]" } else { nodes_json } @@ -603,9 +621,21 @@ if using_http_engram && !snapshot_usable { let tmp_path: String = "/tmp/soul-engram-" + soul_cgi_id + ".json" fs_write(tmp_path, snapshot_data) engram_load(tmp_path) - println("[soul] loaded from HTTP Engram - nodes=" + int_to_str(engram_node_count()) + " edges=" + int_to_str(engram_edge_count())) + let seeded: Int = engram_node_count() + if seeded < 50 { + // Refuse to run blind. An empty seed in HTTP mode means the canonical + // store was unreachable or empty; continuing would let the soul rebuild + // a divergent graph from nothing, which is how the copies split before. + println("[soul] FATAL: engram at " + engram_url_raw + " returned " + int_to_str(seeded) + + " nodes. The canonical store is unreachable or empty; refusing to boot on a" + + " local copy. Fix the engram, then restart.") + exit_program(1) + } + println("[soul] loaded from engram - nodes=" + int_to_str(seeded) + " edges=" + int_to_str(engram_edge_count())) } else { - println("[soul] loaded from local snapshot - nodes=" + int_to_str(local_node_count) + " edges=" + int_to_str(engram_edge_count())) + engram_load(snapshot) + println("[soul] file mode (no ENGRAM_URL) - soul owns the store - nodes=" + + int_to_str(engram_node_count()) + " edges=" + int_to_str(engram_edge_count())) } load_identity_context()