diff --git a/awareness.el b/awareness.el index e2bb68e..e1cd139 100644 --- a/awareness.el +++ b/awareness.el @@ -30,8 +30,16 @@ fn ise_post(content: String) -> Void { ) return "" } - let safe: String = str_replace(content, "\"", "\\\"") - let body: String = "{\"content\":\"" + safe + "\"}" + // Proper JSON string escaping: backslashes first, then quotes, then control chars. + // Previously only escaped " — this caused ise_post to produce malformed JSON when + // content contained \n (backslash-n) from wm_top label escaping: the HTTP Engram + // server would decode \n as a literal newline in the stored content field, making + // the heartbeat ISE unparseable as JSON. (2026-06-10 self-review) + let safe1: String = str_replace(content, "\\", "\\\\") + let safe2: String = str_replace(safe1, "\"", "\\\"") + let safe3: String = str_replace(safe2, "\n", "\\n") + let safe4: String = str_replace(safe3, "\r", "\\r") + let body: String = "{\"content\":\"" + safe4 + "\"}" let discard: String = http_post_json(engram_url + "/api/neuron/state-events", body) return "" } diff --git a/dist/awareness.c b/dist/awareness.c index 999939a..ca59a05 100644 --- a/dist/awareness.c +++ b/dist/awareness.c @@ -174,8 +174,11 @@ el_val_t ise_post(el_val_t content) { el_val_t discard = engram_node_full(content, EL_STR("InternalStateEvent"), EL_STR("state-event"), el_from_float(el_from_float(0.3)), el_from_float(el_from_float(0.3)), el_from_float(el_from_float(0.8)), EL_STR("Episodic"), EL_STR("[\"internal-state\",\"InternalStateEvent\"]")); return EL_STR(""); } - el_val_t safe = str_replace(content, EL_STR("\""), EL_STR("\\\"")); - el_val_t body = el_str_concat(el_str_concat(EL_STR("{\"content\":\""), safe), EL_STR("\"}")); + el_val_t safe1 = str_replace(content, EL_STR("\\"), EL_STR("\\\\")); + el_val_t safe2 = str_replace(safe1, EL_STR("\""), EL_STR("\\\"")); + el_val_t safe3 = str_replace(safe2, EL_STR("\n"), EL_STR("\\n")); + el_val_t safe4 = str_replace(safe3, EL_STR("\r"), EL_STR("\\r")); + el_val_t body = el_str_concat(el_str_concat(EL_STR("{\"content\":\""), safe4), EL_STR("\"}")); el_val_t discard = http_post_json(el_str_concat(engram_url, EL_STR("/api/neuron/state-events")), body); return EL_STR(""); return 0; diff --git a/dist/neuron b/dist/neuron index a0dd954..fc4bf65 100755 Binary files a/dist/neuron and b/dist/neuron differ diff --git a/dist/neuron.c b/dist/neuron.c index 76aa2ba..8d3b485 100644 --- a/dist/neuron.c +++ b/dist/neuron.c @@ -25299,8 +25299,11 @@ el_val_t ise_post(el_val_t content) { el_val_t discard = engram_node_full(content, EL_STR("InternalStateEvent"), EL_STR("state-event"), el_from_float(el_from_float(0.3)), el_from_float(el_from_float(0.3)), el_from_float(el_from_float(0.8)), EL_STR("Episodic"), EL_STR("[\"internal-state\",\"InternalStateEvent\"]")); return EL_STR(""); } - el_val_t safe = str_replace(content, EL_STR("\""), EL_STR("\\\"")); - el_val_t body = el_str_concat(el_str_concat(EL_STR("{\"content\":\""), safe), EL_STR("\"}")); + el_val_t safe1 = str_replace(content, EL_STR("\\"), EL_STR("\\\\")); + el_val_t safe2 = str_replace(safe1, EL_STR("\""), EL_STR("\\\"")); + el_val_t safe3 = str_replace(safe2, EL_STR("\n"), EL_STR("\\n")); + el_val_t safe4 = str_replace(safe3, EL_STR("\r"), EL_STR("\\r")); + el_val_t body = el_str_concat(el_str_concat(EL_STR("{\"content\":\""), safe4), EL_STR("\"}")); el_val_t discard = http_post_json(el_str_concat(engram_url, EL_STR("/api/neuron/state-events")), body); return EL_STR(""); return 0;