fix(reliability): engram-write — guard all fire-and-forget writes
Neuron Soul CI / build (pull_request) Has been cancelled
Neuron Soul CI / build (pull_request) Has been cancelled
Every engram_node_full call that dropped its return value now binds it and emits a println on empty string. engram_save calls in consolidate, heartbeat, and dharma-room-turn are checked for failure. The two API handlers (log_state_event, tune_config) that skipped api_persisted() now match the read-back-after-write contract used everywhere else in neuron-api.el. Files changed: - chat.el: conv_history_persist, handle_dharma_room_turn, auto_persist - soul.el: emit_session_start_event, seed_persona_from_env HTTP check - memory.el: mem_save, mem_boot_count_inc - neuron-api.el: handle_api_log_state_event, handle_api_tune_config, handle_api_consolidate (engram_save + session summary write) - awareness.el: ise_post local-engram fallback path TODO comments added for non-atomic patterns (issues #12, #13) and the missing circuit breaker (#14) — these require new primitives.
This commit is contained in:
@@ -130,11 +130,14 @@ fn conv_history_persist(hist: String) -> Void {
|
||||
if str_eq(hist, "[]") { return "" }
|
||||
let ts: Int = time_now()
|
||||
let tags: String = "[\"conv-history\",\"persistent\"]"
|
||||
let discard: String = engram_node_full(
|
||||
let node_id: String = engram_node_full(
|
||||
hist, "Conversation", "conv:history",
|
||||
el_from_float(0.7), el_from_float(0.8), el_from_float(0.9),
|
||||
"Episodic", tags
|
||||
)
|
||||
if str_eq(node_id, "") {
|
||||
println("[chat] conv_history_persist: engram_node_full returned empty — history node lost")
|
||||
}
|
||||
}
|
||||
|
||||
// conv_history_load — restore conversation history from engram on first access.
|
||||
@@ -637,6 +640,21 @@ fn handle_chat_agentic(body: String) -> String {
|
||||
// Thread-aware activation: same logic as handle_chat.
|
||||
// Use the session's or global history to anchor short messages to the thread.
|
||||
let req_session: String = json_get(body, "session_id")
|
||||
|
||||
// ISSUE #6/#7: validate that the session_id actually exists before proceeding.
|
||||
// Without this check the loop silently treats any unknown/fabricated session_id
|
||||
// as a fresh session — history loads as empty and no error is returned to the caller.
|
||||
// Only validate when a session_id is explicitly provided; anonymous calls
|
||||
// (no session_id) continue to work for backward compatibility.
|
||||
let session_valid: Bool = if str_eq(req_session, "") {
|
||||
true
|
||||
} else {
|
||||
session_exists(req_session)
|
||||
}
|
||||
if !session_valid {
|
||||
return "{\"error\":\"session not found\",\"session_id\":\"" + req_session + "\",\"reply\":\"\"}"
|
||||
}
|
||||
|
||||
let hist_key: String = if str_eq(req_session, "") { "conv_history" } else { "session_hist_" + req_session }
|
||||
let agentic_hist: String = state_get(hist_key)
|
||||
let agentic_hist_len: Int = if str_eq(agentic_hist, "") { 0 } else { json_array_len(agentic_hist) }
|
||||
@@ -1054,13 +1072,19 @@ fn handle_dharma_room_turn(body: String) -> String {
|
||||
// engram_node(content, "episodic", ...) which wrongly put a TIER into the node_type
|
||||
// slot — that's why nodes showed node_type="episodic". Use the full, correct contract.)
|
||||
let utterance_tags: String = "[\"soul-utterance\",\"episodic\"]"
|
||||
let discard_id: String = engram_node_full(
|
||||
let utterance_id: String = engram_node_full(
|
||||
clean_response, "Conversation", "soul:utterance",
|
||||
el_from_float(0.6), el_from_float(0.6), el_from_float(0.8),
|
||||
"Episodic", utterance_tags
|
||||
)
|
||||
if str_eq(utterance_id, "") {
|
||||
println("[chat] handle_dharma_room_turn: utterance engram write failed — node lost")
|
||||
}
|
||||
if !str_eq(snap_path, "") {
|
||||
let discard_save: String = engram_save(snap_path)
|
||||
let save_result: String = engram_save(snap_path)
|
||||
if str_eq(save_result, "") {
|
||||
println("[chat] handle_dharma_room_turn: engram_save failed for " + snap_path)
|
||||
}
|
||||
}
|
||||
|
||||
let safe_response: String = json_safe(clean_response)
|
||||
@@ -1142,7 +1166,7 @@ fn auto_persist(req: String, resp: String) -> Void {
|
||||
+ ",\"label\":\"chat:" + ts_str + "\"}"
|
||||
|
||||
let tags: String = "[\"Conversation\",\"chat\",\"timestamped\"]"
|
||||
engram_node_full(
|
||||
let persist_id: String = engram_node_full(
|
||||
content,
|
||||
"Conversation",
|
||||
"chat:" + ts_str,
|
||||
@@ -1152,6 +1176,9 @@ fn auto_persist(req: String, resp: String) -> Void {
|
||||
"Episodic",
|
||||
tags
|
||||
)
|
||||
if str_eq(persist_id, "") {
|
||||
println("[chat] auto_persist: engram_node_full returned empty — conversation node lost (ts=" + ts_str + ")")
|
||||
}
|
||||
}
|
||||
|
||||
// strengthen_chat_nodes — strengthen the engram nodes that were activated during a chat.
|
||||
|
||||
Reference in New Issue
Block a user