diff --git a/lang/releases/v1.0.0-20260501/el_runtime.c b/lang/releases/v1.0.0-20260501/el_runtime.c index 35b006f..129986c 100644 --- a/lang/releases/v1.0.0-20260501/el_runtime.c +++ b/lang/releases/v1.0.0-20260501/el_runtime.c @@ -7077,16 +7077,33 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { } /* Persist working_memory_weight (post Pass 3) to node store. - * Also emit ISE when a node transitions into working memory (was 0, now > 0.5), + * + * ACT-R semantics: spreading activation is additive. An absent spreading + * source contributes zero to the spread term but does NOT override existing + * base-level / WM state. Nodes not reached by this activation pass therefore + * retain their current working_memory_weight, decayed by ENGRAM_WM_DECAY + * (the per-turn attenuation factor). This replaces the prior behaviour of + * zeroing every non-reached node on each call, which destroyed WM state + * accumulated by MCP-layer activations within one tick of idle operation. + * + * Hard floor: weights decayed below 0.005 are cleared to 0.0 to avoid + * an infinite tail of near-zero values accumulating. + * + * Also emit ISE when a node transitions into working memory (was 0, now > 0.1), * excluding InternalStateEvent nodes to prevent ISEs about ISEs. */ for (int64_t i = 0; i < g->node_count; i++) { EngramNode* wn = &g->nodes[i]; double prev_wm = wn->working_memory_weight; + /* Nodes not participating in this pass: decay rather than zero. */ + if (!reached[i] || best_bg[i] <= 0.0) { + if (prev_wm > 0.0) { + double decayed = prev_wm * ENGRAM_WM_DECAY; + wn->working_memory_weight = (decayed < 0.005) ? 0.0 : decayed; + } + continue; + } wn->working_memory_weight = wm_weights[i]; - /* ISE: working memory promotion — on 0→>0.1 transition, non-ISE nodes. - * Threshold lowered from 0.5 to 0.1 so quieter promotions are observable. - * Previously only very strong promotions (wm_weight>0.5) fired an ISE, - * leaving most activations invisible in the state-event log. */ + /* ISE: working memory promotion — on 0→>0.1 transition, non-ISE nodes. */ if (prev_wm <= 0.0 && wm_weights[i] > 0.1 && wn->node_type && strcmp(wn->node_type, "InternalStateEvent") != 0) { char ise_buf[512];