diff --git a/awareness.el b/awareness.el index a3a5432..635b8b4 100644 --- a/awareness.el +++ b/awareness.el @@ -678,6 +678,8 @@ fn threat_trajectory_check(tool_name: String, tool_input: String) -> Int { return combined } +// TODO(reliability #10): agentic_conv_history is process-global; awareness loop +// and HTTP workers race on this key. Impact: noisy threat score only, not content. fn threat_history_append(text: String) -> Void { let current: String = state_get("agentic_conv_history") let safe_text: String = str_to_lower(text) diff --git a/chat.el b/chat.el index 51f6ff2..43835dc 100644 --- a/chat.el +++ b/chat.el @@ -275,6 +275,8 @@ fn handle_chat(body: String) -> String { } // Load history BEFORE compiling context so we can anchor activation to the thread. + // TODO(reliability #3 — conv_history global race): process-global key; concurrent + // /api/chat requests without session_id race on this read-append-write. let state_hist: String = state_get("conv_history") let stored_hist: String = if str_eq(state_hist, "") { conv_history_load() } else { state_hist } let hist_len: Int = if str_eq(stored_hist, "") { 0 } else { json_array_len(stored_hist) } @@ -802,15 +804,18 @@ fn is_builtin_tool(tool_name: String) -> Bool { || str_starts_with(tool_name, "neuron_") } -// next_bridge_id — monotonic correlation id for a suspended agentic turn. -// Combines boot-relative time with a per-process counter so two unknown-tool -// suspensions in the same second still get distinct ids. +// next_bridge_id — unique correlation id for a suspended agentic turn. +// Uses uuid_v4() as the primary uniqueness guarantee — concurrent calls cannot collide. +// +// TODO(reliability #6): mcp_bridge_seq RMW is non-atomic. Now benign because +// uuid_v4() provides collision-free uniqueness. Counter is kept for readability only. fn next_bridge_id() -> String { let prev: String = state_get("mcp_bridge_seq") let n: Int = if str_eq(prev, "") { 0 } else { str_to_int(prev) } let next: Int = n + 1 state_set("mcp_bridge_seq", int_to_str(next)) - return "br-" + int_to_str(time_now()) + "-" + int_to_str(next) + let uid: String = uuid_v4() + return "br-" + uid } fn handle_chat_agentic(body: String) -> String { diff --git a/imprint.el b/imprint.el index 86c3080..ce53ed7 100644 --- a/imprint.el +++ b/imprint.el @@ -5,6 +5,10 @@ // imprint_current — returns the active imprint ID from state. // Falls back to "base" (bare Neuron, no suit) when nothing is loaded. +// +// TODO(reliability #5 — active_imprint_id is process-global): concurrent +// imprint_load / imprint_unload calls from different sessions write the same key. +// Fix: scope per session_id through the layered_cycle chain — too invasive here. fn imprint_current() -> String { let id: String = state_get("active_imprint_id") return if str_eq(id, "") { "base" } else { id } diff --git a/routes.el b/routes.el index b0d6ae1..5902a53 100644 --- a/routes.el +++ b/routes.el @@ -274,6 +274,9 @@ fn handle_request(method: String, path: String, body: String) -> String { return engram_scan_nodes_json(9999, 0) } if str_eq(clean, "/api/graph/edges") { + // TODO(reliability #8): engram_save races with awareness loop mem_save(). + // Both now use atomic write-to-temp+rename (el_runtime.c). Serialised + // by engram_global_mu. Future: add engram_edges_json() builtin. let snap_path: String = env("HOME") + "/.neuron/engram/snapshot.json" engram_save(snap_path) let snap: String = fs_read(snap_path) diff --git a/sessions.el b/sessions.el index fac9a79..4a84878 100644 --- a/sessions.el +++ b/sessions.el @@ -57,6 +57,8 @@ fn session_create(body: String) -> String { state_set("session_node_" + id, node_id) // Maintain a state-based index for fast listing within this daemon run. // Newest sessions first (prepend). + // TODO(reliability #2): session_index RMW is non-atomic. Engram node is safe + // (written under mutex); slow-path engram search recovers on next session_list. let existing_idx: String = state_get("session_index") let idx_entry: String = "{\"id\":\"" + id + "\",\"title\":\"" + json_safe(title) + "\",\"folder\":\"" + json_safe(folder) + "\",\"created_at\":" + int_to_str(ts) + ",\"updated_at\":" + int_to_str(ts) + ",\"last_message\":\"\"}" let new_idx: String = if str_eq(existing_idx, "") { @@ -347,6 +349,8 @@ fn session_hist_load(session_id: String) -> String { } // session_hist_save — persist message history for a session to state and engram. +// TODO(reliability #7): delete-then-insert is not atomic — concurrent saves for the +// same session can produce orphan history nodes. State is primary truth; engram fallback. fn session_hist_save(session_id: String, hist: String) -> Void { state_set("session_hist_" + session_id, hist) // Delete old history node and write fresh one diff --git a/soul.el b/soul.el index 0147f2a..dc942d7 100644 --- a/soul.el +++ b/soul.el @@ -288,8 +288,11 @@ fn layered_cycle(raw_input: String) -> String { let cont_status: String = json_get(continuity, "status") let cont_action: String = json_get(continuity, "action") - // Store continuity status so imprint can adjust its response register - state_set("session_continuity", cont_status) + // Store continuity status so imprint can adjust its response register. + // TODO(reliability #4): session_continuity is process-global; scope per session_id + // when available to prevent cross-session bleed under concurrent layered_cycle calls. + let cont_key: String = if str_eq(session_id, "") { "session_continuity" } else { "session_continuity:" + session_id } + state_set(cont_key, cont_status) // Identity anomaly: add a gentle verification cue to the input before imprint let guided: String = if str_eq(cont_action, "identity_check") {