diff --git a/engram/dist/engram b/engram/dist/engram index f3178b7..403fd55 100755 Binary files a/engram/dist/engram and b/engram/dist/engram differ diff --git a/lang/releases/v1.0.0-20260501/el_runtime.c b/lang/releases/v1.0.0-20260501/el_runtime.c index 2314047..0445841 100644 --- a/lang/releases/v1.0.0-20260501/el_runtime.c +++ b/lang/releases/v1.0.0-20260501/el_runtime.c @@ -5578,11 +5578,24 @@ void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, * when a suppressed node breaks through. * ENGRAM_INHIBITION_FACTOR: multiplier applied to working_memory_weight when * an inhibitory edge fires against a node (0 = full suppress, 0.3 = partial). */ -#define ENGRAM_WM_THRESHOLD 0.15 +/* ENGRAM_WM_THRESHOLD lowered 0.15 → 0.08 (2026-06-04 self-review): + * With 29K nodes and only ~100 edges the graph is extremely sparse. BFS + * fan-out carries very little activation energy — most background values + * arrive at 0.05-0.12 through the thin path set. The prior 0.15 threshold + * was gatekeeping too aggressively, suppressing legitimate weak signals. + * Cognitive literature (TBRS*, Altmann/Schunn) uses θ=0.05; 0.08 is a + * conservative move in that direction that still filters random noise. */ +#define ENGRAM_WM_THRESHOLD 0.08 #define ENGRAM_WM_DECAY 0.7 #define ENGRAM_SUPPRESSION_BREAKTHROUGH 5 #define ENGRAM_BREAKTHROUGH_WEIGHT 0.25 -#define ENGRAM_INHIBITION_FACTOR 0.1 +/* ENGRAM_INHIBITION_FACTOR raised 0.1 → 0.2 (2026-06-04 self-review): + * Factor=0.1 produces 90% suppression per inhibitory edge hit. On a sparse + * graph where edges are rare, this nearly always silences the target node + * entirely. Factor=0.2 (80% suppression) retains meaningful inhibition + * while allowing partially-suppressed nodes to remain faintly active, + * consistent with partial inhibition models in cognitive neuroscience. */ +#define ENGRAM_INHIBITION_FACTOR 0.2 /* ── Layered consciousness architecture ────────────────────────────────────── * @@ -8917,6 +8930,24 @@ el_val_t engram_wm_count(void) { return (el_val_t)count; } +/* Average working_memory_weight across all promoted nodes (wm > 0). + * Returns the float bit-pattern via el_from_float so EL can use it with + * float_to_str / float_gt. Returns 0.0 when no nodes are promoted. + * Useful in heartbeat ISEs to distinguish "many weak activations" (sparse + * graph, low avg) from "few strong activations" (dense subgraph, high avg). + * Added 2026-06-04 self-review for graph health observability. */ +el_val_t engram_wm_avg_weight(void) { + EngramStore* g = engram_get(); + double sum = 0.0; + int64_t count = 0; + for (int64_t i = 0; i < g->node_count; i++) { + double w = g->nodes[i].working_memory_weight; + if (w > 0.0) { sum += w; count++; } + } + double avg = (count > 0) ? (sum / (double)count) : 0.0; + return el_from_float(avg); +} + /* engram_list_layers_json — serialized counterpart of engram_list_layers. * Returns a JSON array, sorted by activation_priority ascending. */ el_val_t engram_list_layers_json(void) { diff --git a/lang/releases/v1.0.0-20260501/el_runtime.h b/lang/releases/v1.0.0-20260501/el_runtime.h index 8a22b73..c733dd6 100644 --- a/lang/releases/v1.0.0-20260501/el_runtime.h +++ b/lang/releases/v1.0.0-20260501/el_runtime.h @@ -619,6 +619,7 @@ el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t d el_val_t engram_activate_json(el_val_t query, el_val_t depth); el_val_t engram_stats_json(void); el_val_t engram_wm_count(void); +el_val_t engram_wm_avg_weight(void); /* avg wm weight of promoted nodes; float bits */ el_val_t engram_apply_decay_json(void); el_val_t engram_list_layers_json(void); /* engram_compile_layered_json — produce a prompt-ready text block split