M-INTEROCEPTION P4: afferent input counters in act-stats (additive observability)

Extends engram_act_stats_json with five monotonic counters for the raw incoming
signals the mind receives — aff_activations (spreading activations run),
aff_queries (activate_json entries), aff_node_creates, aff_ise_ingests (ISE
nodes), aff_edge_creates. Module-scope statics incremented at the entry points,
emitted via the existing act-stats mechanism and rotated with it — MEASURED, and
never accreted as memory nodes. Process-lifetime totals, reset on restart like
the other _eg_act_* gauges. Additive JSON fields (backward-compatible); no graph
behavior changes. act-stats buffer grown 896->1088 to hold them.

MEASURED on a copy: after 5 node creates (2 ISE), 2 edge creates, then 4+3
queries — counters read exactly node_creates=5, ise_ingests=2, edge_creates=2,
queries=activations=4 then 7; create counters unchanged by queries; queries
strictly monotonic across readings. ASan+UBSan clean.
This commit is contained in:
2026-08-12 23:47:43 -05:00
parent 816b258255
commit 65ca0a3253
3 changed files with 130 additions and 3 deletions
+26 -3
View File
@@ -6534,6 +6534,15 @@ 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) */
/* M-INTEROCEPTION P4: AFFERENT input counters — monotonic raw counts of the
* incoming signals the mind receives. Additive observability, MEASURED and
* rotated via the existing act-stats mechanism, NEVER accreted as memory nodes.
* Process-lifetime totals (reset to 0 on restart, like the other _eg_act_*). */
static int64_t _eg_aff_activations = 0; /* engram_activate calls (core spreading) */
static int64_t _eg_aff_queries = 0; /* engram_activate_json entries */
static int64_t _eg_aff_node_creates = 0; /* engram_node_full calls */
static int64_t _eg_aff_ise_ingests = 0; /* InternalStateEvent nodes created */
static int64_t _eg_aff_edge_creates = 0; /* engram_connect calls */
/* 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
@@ -7986,6 +7995,9 @@ el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label,
engram_idmap_put(g, n->id, new_idx_full);
engram_adj_on_node_added(g);
if (engram_store_enabled()) eg_store_put_node(n);
/* P4 afferent counters: a node was created; ISE ingests counted separately. */
_eg_aff_node_creates++;
if (n->node_type && strcmp(n->node_type, "InternalStateEvent") == 0) _eg_aff_ise_ingests++;
/* P1 CONNECTION threshold: self-gated (inert unless ENGRAM_CONSOLIDATION). */
eg_consolidate_ise_connect(n);
return el_wrap_str(el_strdup(n->id));
@@ -8549,6 +8561,7 @@ void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t
const char* t = EL_CSTR(to_id);
const char* r = EL_CSTR(relation);
if (!f || !t) return;
_eg_aff_edge_creates++; /* P4 afferent counter: an edge was authored */
engram_grow_edges();
EngramEdge* e = &g->edges[g->edge_count];
memset(e, 0, sizeof(*e));
@@ -9222,6 +9235,7 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) {
int64_t max_depth = (int64_t)depth; if (max_depth <= 0) max_depth = 2;
el_val_t out = el_list_empty();
if (!q || g->node_count == 0) return out;
_eg_aff_activations++; /* P4 afferent counter: a real spreading activation ran */
/* Rebuild adjacency index if the edge/node topology changed since the
* last activation call. This is O(E) one-time cost vs O(E) per BFS step
@@ -12249,6 +12263,7 @@ el_val_t engram_activate_json(el_val_t query, el_val_t depth) {
* Each entry includes both activation_strength (layer 1 background) and
* working_memory_weight (layer 2 executive filter), plus promoted flag.
* Callers performing context compilation should filter to promoted=1. */
_eg_aff_queries++; /* P4 afferent counter: a query entered the mind */
el_val_t lst = engram_activate(query, depth);
ElList* arr = (ElList*)(uintptr_t)lst;
JsonBuf b; jb_init(&b);
@@ -12455,7 +12470,7 @@ el_val_t engram_act_stats_json(void) {
/* 768, not 512: the write-back gauges added 2026-08-07 push the worst-case
* rendering past the old bound, and snprintf would truncate the JSON into
* an unparseable tail rather than fail loudly. */
char buf[896];
char buf[1088];
/* ctx_cos (2026-07-29): cos(query, context centroid) at the LAST
* activate call, measured before the query was folded in. ~1.0 =
* context aligned with current query; low = divergence (expected at
@@ -12476,7 +12491,12 @@ el_val_t engram_act_stats_json(void) {
* any climb means a write path is mangling text again. Cheap
* (counted at creation) the full census lives in
* engram_text_health_json. (2026-08-08 self-review) */
"\"txt_damaged\":%lld}",
"\"txt_damaged\":%lld,"
/* P4 afferent input counters (M-INTEROCEPTION): monotonic raw
* counts of incoming signals; MEASURED here, never memory nodes. */
"\"aff_activations\":%lld,\"aff_queries\":%lld,"
"\"aff_node_creates\":%lld,\"aff_ise_ingests\":%lld,"
"\"aff_edge_creates\":%lld}",
(long long)_eg_act_wm_evicted,
(long long)_eg_act_breakthroughs,
breaker_open, _eg_embed_consec_fail,
@@ -12488,7 +12508,10 @@ el_val_t engram_act_stats_json(void) {
(long long)_eg_hebb_wb_dropped,
(long long)_eg_act_dup_seeds, (long long)_eg_act_dup_wm,
(long long)_eg_act_dup_wm_global,
(long long)_eg_txt_write_damaged);
(long long)_eg_txt_write_damaged,
(long long)_eg_aff_activations, (long long)_eg_aff_queries,
(long long)_eg_aff_node_creates, (long long)_eg_aff_ise_ingests,
(long long)_eg_aff_edge_creates);
return el_wrap_str(el_strdup(buf));
}