self-review 2026-05-18: raise SEM_FLOOR to 0.70, add ACT-R frequency resistance to decay
Semantic seed floor raised 0.65 → 0.70: field literature (SuperLocalMemory arXiv:2604.04514) validates 0.70-0.75 as the noise floor for sentence-transformer embeddings on non-trivial corpora. The 0.65 threshold was admitting false positives that diluted BFS traversal quality on the 13K-node post-ingestor graph. Top-30 cap retained — sparse graph (1.26 edges/node) needs more semantic entry points than a dense graph would. ACT-R Base-Level Learning insight applied to engram_temporal_decay: current purely time-based formula treated a node activated 100 times identically to a node never activated (same decay rate). ACT-R BLL (Anderson 1993) shows frequently-accessed memories resist temporal decay. Fix: freq_resist multiplier = 1.0 + 0.1 * log(1 + activation_count). count=0→1.0×, count=9→1.23×, count=99→1.46×. Existing activation_dampening continues to reduce per-query novelty for well-known nodes — the two mechanisms are complementary: resist decay (durable in graph), dampen per-query (don't dominate any single turn).
This commit is contained in:
Vendored
BIN
Binary file not shown.
@@ -6552,8 +6552,21 @@ el_val_t engram_edge_count(void) {
|
||||
}
|
||||
|
||||
/* Compute temporal decay factor for a node given current time.
|
||||
* effective contribution = salience * exp(-lambda * age_hours / T_half)
|
||||
* Clamped to [0.05, 1.0] so very old nodes retain a meaningful floor. */
|
||||
* effective contribution = salience * exp(-lambda * age_hours / T_half) * freq_resist
|
||||
* Clamped to [0.05, 1.0] so very old nodes retain a meaningful floor.
|
||||
*
|
||||
* ACT-R-inspired frequency resistance (added 2026-05-18 self-review):
|
||||
* freq_resist = 1.0 + 0.1 * log(1 + activation_count)
|
||||
* count=0 → 1.00×, count=9 → 1.23×, count=99 → 1.46×, count=999 → 1.69×
|
||||
*
|
||||
* Rationale: ACT-R Base-Level Learning (Anderson 1993, d=0.5 power law) shows
|
||||
* that frequently-accessed memories resist temporal decay — the brain doesn't
|
||||
* let well-rehearsed knowledge fade at the same rate as never-accessed nodes.
|
||||
* Our activation_dampening already reduces per-query novelty for high-count
|
||||
* nodes (correct — prevents runaway dominance in any single turn). But without
|
||||
* freq_resist, that same node was decaying as fast as a node never activated,
|
||||
* which is cognitively wrong. This multiplier corrects it: canonical nodes and
|
||||
* heavily-used lessons resist decay, session-ephemeral nodes do not. */
|
||||
static double engram_temporal_decay(const EngramNode* n, int64_t now_ms) {
|
||||
int64_t age_ms = now_ms - n->last_activated;
|
||||
if (age_ms <= 0) return 1.0;
|
||||
@@ -6561,6 +6574,10 @@ static double engram_temporal_decay(const EngramNode* n, int64_t now_ms) {
|
||||
: ENGRAM_DECAY_LAMBDA;
|
||||
double age_hours = (double)age_ms / 3600000.0;
|
||||
double factor = exp(-lambda * age_hours / ENGRAM_T_HALF_HOURS);
|
||||
/* Frequency resistance: frequently-activated nodes decay more slowly. */
|
||||
double freq_resist = 1.0 + 0.1 * log(1.0 + (double)n->activation_count);
|
||||
factor *= freq_resist;
|
||||
if (factor > 1.0) factor = 1.0;
|
||||
if (factor < 0.05) factor = 0.05;
|
||||
return factor;
|
||||
}
|
||||
@@ -6758,11 +6775,16 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) {
|
||||
}
|
||||
/* ── Semantic seed supplement ────────────────────────────────────────────
|
||||
* When the query has an embedding vector, scan un-seeded nodes for cosine
|
||||
* similarity ≥ 0.65 and inject the top-30 as additional Pass-1 seeds.
|
||||
* similarity ≥ 0.70 and inject the top-30 as additional Pass-1 seeds.
|
||||
* This ensures semantically-related nodes that share no query tokens still
|
||||
* enter the BFS fan-out. Sem seeds get 85% of full act to stay slightly
|
||||
* weaker than exact lexical matches. Top-K=30 cap prevents queue flooding
|
||||
* on large graphs (11K+ nodes post-ingestor).
|
||||
* on large graphs (13K+ nodes post-ingestor).
|
||||
*
|
||||
* Floor raised from 0.65 → 0.70 (2026-05-18 self-review): field literature
|
||||
* (SuperLocalMemory, floop) validates 0.70-0.75 as the noise floor for
|
||||
* nomic-embed-text; 0.65 was admitting false positives that diluted BFS
|
||||
* traversal quality.
|
||||
*
|
||||
* Without this pass, embeddings collected at write-time via engram_embed_node
|
||||
* were only used in goal_bias (Pass 2) for nodes that already had lexical
|
||||
@@ -6770,7 +6792,7 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) {
|
||||
* completely invisible to activation regardless of embedding quality. */
|
||||
if (qvec && qdim > 0) {
|
||||
typedef struct { int64_t idx; float sim; } SemEntry;
|
||||
const float SEM_FLOOR = 0.65f;
|
||||
const float SEM_FLOOR = 0.70f;
|
||||
SemEntry top_sem[30];
|
||||
int64_t top_sem_cnt = 0;
|
||||
float top_sem_min = SEM_FLOOR;
|
||||
|
||||
Reference in New Issue
Block a user