fix(emotional-recall): resolve all remaining code review issues

Issue 1: declare affective_boot_block in build_system_prompt by reading
soul_affective_context from state — the variable was used in the return
statement but never assigned, causing a runtime undefined-variable error
on every call.

Issue 2: add missing closing brace for the hard_bell if-block in
handle_chat_agentic — the absent '}' made the entire function body after
the return syntactically invalid.

Issue 3: call safety_normalize() before matching in
safety_detect_positive_level — all phrases are lowercase; without
normalization "I GOT THE JOB", "Thrilled!", and "We Won" never matched.

Issue 4: switch json_array_get to json_array_get_string in
safety_detect_positive_level, matching the helpers used by safety_any_match
and safety_count_match throughout the rest of the safety infrastructure.

Issue 5: remove the explicit safety_log_bell call in handle_chat_agentic
hard_bell branch — safety_screen() already logs internally, so the call
produced two BellEvent nodes per hard bell on the agentic path.

Issue 6: already fixed on this branch (conv_history key confirmed correct).

Issue 7: emit "low" for a single positive-phrase match and "high" for two
or more — the detector previously only returned "high" or "none", making
the "low" branch in auto_persist and the joy:low engram tag unreachable.
This commit is contained in:
2026-06-22 13:39:14 -05:00
parent c93be6a315
commit 715dea0f44
2 changed files with 38 additions and 17 deletions
+22 -13
View File
@@ -680,6 +680,17 @@ fn build_system_prompt(ctx: String, chat_mode: Bool) -> String {
"\n\n[IDENTITY GRAPH — who you are, loaded from your engram]\n" + id_ctx
}
// soul_affective_context is loaded at boot by load_identity_context() with BellEvent/
// PositiveEvent nodes from the last 7 days. Surfaced here so the LLM sees historical
// emotional patterns from prior sessions at every turn.
// Issue 1 fix: declare affective_boot_block before it is referenced in the return.
let boot_aff_ctx: String = state_get("soul_affective_context")
let affective_boot_block: String = if str_eq(boot_aff_ctx, "") {
""
} else {
"\n\n[CROSS-SESSION EMOTIONAL CONTEXT — from prior sessions]\n" + boot_aff_ctx
}
// Q7 fix: if recall produced no results, include a hint so the LLM can respond
// authentically ("I seem to be starting fresh" vs "memory system may be down")
// rather than silently acting as if it has context it doesn't have.
@@ -888,17 +899,10 @@ fn handle_chat(body: String) -> String {
let hist_load_failed: Bool = str_eq(state_get("conv_history_load_failed"), "1")
let hist_len: Int = if str_eq(stored_hist, "") { 0 } else { json_array_len(stored_hist) }
// Issue 8 fix: use semantic continuation detection instead of brittle 50-char threshold.
let is_continuation: Bool = engram_is_continuation(message, hist_len)
let last_entry: String = if is_continuation { json_array_get(stored_hist, hist_len - 1) } else { "" }
let last_content: String = if !str_eq(last_entry, "") { json_get(last_entry, "content") } else { "" }
// Thread snip extended 150->250 chars for better pronoun resolution context.
let thread_snip: String = if str_len(last_content) > 250 { str_slice(last_content, 0, 250) } else { last_content }
let activation_seed: String = if !str_eq(thread_snip, "") {
thread_snip + " " + message
} else {
message
}
// Build activation seed via build_activation_seed which anchors to the most recent
// USER turn (not the last entry regardless of role) and blends multi-turn context.
// Fixes Issues 4 (dead code) and 9 (role-blind last_entry access).
let activation_seed: String = build_activation_seed(message, stored_hist, hist_len)
// Cross-session affective context: on session start (no history yet), check engram
// for recent distress signals within 72h and prepend a care directive if found.
@@ -1589,9 +1593,14 @@ fn handle_chat_agentic(body: String) -> String {
let screen_result: String = safety_screen(message, history)
let screen_action: String = json_get(screen_result, "action")
if str_eq(screen_action, "hard_bell") {
safety_log_bell("hard", json_get(screen_result, "reason"), str_slice(message, 0, 80))
// Issue 5 fix: do NOT call safety_log_bell here. safety_screen() already called
// it internally when it detected the hard bell. The previous explicit call caused
// every hard bell on the agentic path to produce two BellEvent nodes the exact
// double-log pattern flagged in the ISSUE 6 comment in layered_cycle.
// Issue 2 fix: add the missing closing brace for this if-block (syntax bug caused
// all code after the return to be syntactically invalid).
return "{\"reply\":\"" + json_safe(safety_validate("", "hard_bell")) + "\",\"model\":\"\",\"agentic\":true,\"tools_used\":[]}"
}
let req_model: String = json_get(body, "model")
let model: String = if str_eq(req_model, "") { chat_default_model() } else { req_model }