diff --git a/lang/releases/v1.0.0-20260501/el_runtime.c b/lang/releases/v1.0.0-20260501/el_runtime.c index c5ca86a..cb5a70c 100644 --- a/lang/releases/v1.0.0-20260501/el_runtime.c +++ b/lang/releases/v1.0.0-20260501/el_runtime.c @@ -6493,6 +6493,27 @@ static int64_t _eg_embed_breaker_until = 0; * rates keep the previous reading and diff. Restart legitimately resets to 0. */ static int64_t _eg_act_breakthroughs = 0; /* forced promotions at the floor, cumulative */ static int64_t _eg_act_wm_evicted = 0; /* ALL WM evictions, cumulative (see below) */ +/* ── Eviction CAUSE decomposition (2026-08-14 self-review) ────────────────── + * _eg_act_wm_evicted is incremented from six sites with four distinct causes, + * and every one of them collapsed into that single integer. Today's review + * measured 175,547 evictions over 13.5h (~216/min against 24 slots) and could + * not tell healthy rotation from cap thrashing from duplicate churn, because + * the only available number counts all three the same way. + * + * That is this file's most-repeated defect. The 08-02 and 08-06 reviews were + * each diagnosable only because someone first added a NEW gauge; dup_wm and + * dup_wm_global exist precisely because the aggregate could not answer "why". + * These three finish the decomposition, so that + * evicted == floor + cap + bll + dup_wm + dup_wm_global + * holds as an identity and each term names a different corrective action: + * floor - candidates below the absolute admission bar. High = weak retrieval. + * cap - lost the rank contest for 24 slots. High = genuine contention. + * bll - carried-over residents that decayed under the ACT-R tau. High = + * healthy forgetting, NOT pressure. + * Confusing the third with the second is what makes WM churn unreadable. */ +static int64_t _eg_act_evict_floor = 0; /* below ENGRAM_WM_FLOOR (both passes) */ +static int64_t _eg_act_evict_cap = 0; /* over ENGRAM_WM_CAP (both passes) */ +static int64_t _eg_act_evict_bll = 0; /* carry-over decayed under BLL tau */ /* Redundancy suppression counters (2026-08-05 self-review) — see * ENGRAM_DEDUP_COS. dup_seeds = semantic seed slots reclaimed from redundant * copies; dup_wm = WM candidates dropped for duplicating a higher-ranked @@ -8191,6 +8212,7 @@ static void eg_wm_carry_over(EngramNode* cn, int64_t now_ms, int64_t* evict_ctr) cn->working_memory_weight = 0.0; cn->wm_anchor = 0.0; if (evict_ctr) (*evict_ctr)++; + _eg_act_evict_bll++; } else { cn->working_memory_weight = w; } @@ -8949,9 +8971,31 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { * ~4x, never killed); unembedded targets pass ungated (no * information, no penalty); cosq == NULL (embedder down) means * no gating at all — same graceful degradation as seeding. */ + /* Rescale before gating (2026-08-14 self-review). Raw cosine from + * nomic-embed is compressed into a narrow high band, so feeding it + * to the gate directly makes the gate nearly a constant. Measured + * on this store: 400 random UNRELATED node pairs gave median 0.562, + * central 98% span [0.381, 0.743]. The raw gate therefore passed a + * typical unrelated node at 0.25 + 0.75*0.562 = 0.67 — two thirds + * strength for a node with no semantic relation to the query. That + * is not a gate, it is a small tax. + * + * Shift-and-floor about ENGRAM_EMBED_S0, exactly as the Pass-2 WM + * term at ENGRAM_EMBED_WM_WEIGHT already does. The constant was in + * this file for this reason; the propagation gate simply never used + * it. Same store, same 400 pairs, after the rescale: the median + * unrelated pair drops to 0.40 while the top of the range is + * preserved (0.85 vs 0.92), and gate spread widens 0.42 -> 0.60. + * Only 8.5% of pairs fall to the floor, so lexical/structural + * pathways through dissimilar nodes are damped, never severed. + * Cf. arXiv:2512.15922, which rescales w' = (w-c)/(1-c) about + * c = 0.4 for precisely this reason ("prevent overactivation and + * context explosion"). */ double qgate = 1.0; if (cosq && cosq[oi] > -1.5) { - double c = cosq[oi] > 0.0 ? cosq[oi] : 0.0; + double c = (cosq[oi] - ENGRAM_EMBED_S0) / (1.0 - ENGRAM_EMBED_S0); + if (c < 0.0) c = 0.0; + if (c > 1.0) c = 1.0; qgate = ENGRAM_QGATE_FLOOR + (1.0 - ENGRAM_QGATE_FLOOR) * c; } /* ── ACT-R fan effect (2026-08-11 self-review) ── @@ -9261,6 +9305,7 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { if (wm_weights[i] > 0.0 && wm_weights[i] < ENGRAM_WM_FLOOR) { wm_weights[i] = 0.0; _eg_act_wm_evicted++; + _eg_act_evict_floor++; } } int64_t cap_count = 0; @@ -9296,6 +9341,7 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { } wm_weights[i] = 0.0; /* over cap: evict */ _eg_act_wm_evicted++; + _eg_act_evict_cap++; } } /* If malloc failed, skip cap — WM unbounded this call, no corruption. */ @@ -9407,6 +9453,7 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { fn->working_memory_weight = 0.0; fn->wm_anchor = 0.0; _eg_act_wm_evicted++; + _eg_act_evict_floor++; } } /* ── Global redundancy suppression (2026-08-06 self-review) ────────── @@ -9515,6 +9562,7 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { n->working_memory_weight = 0.0; /* evict: over global cap */ n->wm_anchor = 0.0; /* keep anchor coherent */ _eg_act_wm_evicted++; /* was uncounted before 2026-08-02 */ + _eg_act_evict_cap++; } } /* If malloc failed, skip — WM over cap this call, no data corruption. */ @@ -10943,6 +10991,15 @@ el_val_t engram_act_stats_json(void) { * embedder down. The drift gauge for the context-centroid mechanism. */ snprintf(buf, sizeof(buf), "{\"wm_evicted\":%lld,\"breakthroughs\":%lld," + /* Eviction cause decomposition (2026-08-14 self-review): + * wm_evicted == evict_floor + evict_cap + evict_bll + * + dup_wm + dup_wm_global. + * Read them as a ratio, not a level. cap-dominant = real + * contention for the 24 slots; bll-dominant = healthy decay of + * carried-over residents; floor-dominant = retrieval is returning + * weak candidates. The aggregate alone cannot distinguish these + * and every prior WM incident needed a new gauge to diagnose. */ + "\"evict_floor\":%lld,\"evict_cap\":%lld,\"evict_bll\":%lld," "\"embed_breaker_open\":%d,\"embed_consec_fail\":%d," "\"ctx_cos\":%.3f," "\"hebb_edges\":%lld,\"hebb_max\":%.4f,\"hebb_mass\":%.3f," @@ -10966,6 +11023,9 @@ el_val_t engram_act_stats_json(void) { "\"fan_steps\":%lld,\"fan_dref\":%.2f}", (long long)_eg_act_wm_evicted, (long long)_eg_act_breakthroughs, + (long long)_eg_act_evict_floor, + (long long)_eg_act_evict_cap, + (long long)_eg_act_evict_bll, breaker_open, _eg_embed_consec_fail, _eg_act_ctx_cos, (long long)hebb_edges, hebb_max, hebb_mass,