fix/test: PR #21 review — guard, safety Bell, api write-back, temp paths
Neuron Soul CI / build (pull_request) Failing after 13m22s

fix(soul): add HTTP-engram guard to safe_to_seed — when ENGRAM_URL is set
the HTTP Engram owns persistence; genesis must never save to local snapshot
regardless of node counts (was: guard_disk forced to empty string, making
the ratio check vacuously true and allowing init_soul_edges+engram_save).

fix(soul): use multiplication form for ratio guard — node_count * 16000 <
disk_len avoids floor-division truncation that underestimated boundary files
(250KB / 16000 = 15.6, floors to 15; a 15-node graph wrongly passed old guard).

fix(chat): add safety_augment_system to handle_chat_as_soul,
handle_dharma_room_turn, and handle_dharma_room_turn_agentic — all three
called the LLM without Hard Bell evaluation, leaving users in dharma rooms
without crisis resource routing.

fix(neuron-api): add api_persisted read-back to handle_api_define_process —
was the only write handler that returned ok:true without verifying the node
was actually written to engram.

fix(routes): unique temp file path in connectd_post — replaces fixed
/tmp/neuron-connectors-req.json with a timestamped path to prevent
collision if concurrency is added or two soul instances share a machine.

test: add tests/test_bell_safety.el — covers safety_detect_bell_level
(none/soft/hard), safety_classify_hard_bell (abuse/self_harm routing),
safety_normalize (smart-quote), safety_augment_system, and
handle_safety_contact_post (validation + read-back).

test: add tests/test_soul_guard.el — pure-function logic tests for the
safe_to_seed predicate: 200KB boundary, 47MB/63-node clobber scenario,
HTTP-engram mode, multiplication vs division truncation at 250KB.

test: add tests/test_api_define_process.el — verifies the define_process
write is read-back verified after the fix.
This commit is contained in:
2026-06-17 13:04:12 -05:00
parent 5ddb860201
commit 8b692e4666
7 changed files with 520 additions and 2 deletions
+8 -1
View File
@@ -368,12 +368,19 @@ let is_genesis: Bool = str_eq(soul_cgi_id, "ntn-genesis")
// sparse but the on-disk snapshot file is large, the load FAILED seeding+saving now would
// clobber the user's real memory (this is exactly how the 06-14 clobber happened). Read the
// on-disk file (local mode only) and refuse the destructive seed+save when it looks populated.
//
// HTTP-engram guard (2026-06-17): when ENGRAM_URL is set the HTTP Engram owns persistence
// the soul must NEVER write to the local snapshot regardless of node counts. safe_to_seed is
// unconditionally false in HTTP mode (not the persistence owner).
let guard_disk: String = if str_eq(engram_url_raw, "") { fs_read(snapshot) } else { "" }
let guard_disk_len: Int = str_len(guard_disk)
// Ratio guard (2026-06-15 fix): refuse to seed/save whenever the in-memory load is FAR smaller than
// the on-disk file implies (~16KB/node) catches partial loads of ANY size, not just <50. The old
// <50 threshold let a 63-node identity-only load clobber a 47MB/5000-node graph.
let safe_to_seed: Bool = !(guard_disk_len > 200000 && engram_node_count() < guard_disk_len / 16000)
// Multiplication form (2026-06-17): node_count * 16000 < disk_len avoids floor-division truncation
// (e.g., 250KB / 16000 = 15.6, floors to 15 a 15-node graph wrongly passes the old guard).
// HTTP-engram guard: when using_http_engram the soul is not the persistence owner; never seed.
let safe_to_seed: Bool = !using_http_engram && !(guard_disk_len > 200000 && engram_node_count() * 16000 < guard_disk_len)
if is_genesis && !safe_to_seed {
println("[soul] GUARD: loaded " + int_to_str(engram_node_count())
+ " nodes but snapshot file is " + int_to_str(guard_disk_len)