self-review 2026-05-19: ACT-R WM persistence — decay non-reached nodes instead of zeroing
The activation persist step was writing wm_weight=0 for every node not reached by the current BFS fan-out. This destroyed working memory accumulated by MCP-layer activations within one tick of the awareness loop firing on an empty inbox. ACT-R and Soar treat spreading activation as additive: absent seeds contribute zero spread, not a zero override of existing WM state. Fix: non-reached nodes now decay by ENGRAM_WM_DECAY (0.7) per activation call rather than being immediately zeroed. A hard floor of 0.005 clears near-zero values to prevent infinite decay tails. Reached nodes behave unchanged.
This commit is contained in:
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user