self-review 2026-07-24: boot counter — demote to telemetry weight, restore persistence via HTTP write-back

Three stale soul:boot_count copies (salience .9, importance .9, Canonical:
+0.2 tier bias, 0.15 threshold) held the top WM slots for 23h — a boot
counter outcompeting real context. Demoted to salience .55 / importance .2 /
tier Working: plumbing, not memory.

Persistence was also broken: in HTTP-engram mode the server owns state and
nothing wrote the counter back — the log shows boot #5 on three consecutive
boots. mem_boot_count_inc now mirrors the persona write-back: delete stale
server copies (matched by content prefix — route_create_node sets
label=content), create the replacement server-side. Working tier is in the
boot seed (/api/nodes) but excluded from periodic /api/sync, so the count
survives restarts without re-importing mid-session. Verified: restart
incremented 1->2 with exactly one server-side counter node.
This commit is contained in:
2026-07-24 08:53:02 -05:00
parent 9e59c51f3c
commit fb0bb553f3
4 changed files with 123 additions and 5 deletions
+18 -1
View File
@@ -236,7 +236,24 @@ fn auto_term_try_slot(slot_type: String, slot_lbl: String) -> Void {
if !str_eq(slot_lbl, "") { if !str_eq(slot_lbl, "") {
let sp: Int = str_find_chars(slot_lbl, " :([") let sp: Int = str_find_chars(slot_lbl, " :([")
if sp > 3 { if sp > 3 {
state_set("cseed_auto", str_slice(slot_lbl, 0, sp)) // GENRE-WORD BLOCKLIST (2026-07-23 self-review): world-ingestor
// titles open with classifier prefixes ("Method paper ...",
// "Theory paper ..."), so the first word is a genre tag, not a
// topic. Verified live: every scan after Knowledge admission
// seeded on 'Method'. Skip these; a lower-WM slot with a
// topical first word wins instead.
let term: String = str_slice(slot_lbl, 0, sp)
state_set("_ats_gw", "0")
if str_eq(term, "Method") { state_set("_ats_gw", "1") }
if str_eq(term, "Theory") { state_set("_ats_gw", "1") }
if str_eq(term, "Finding") { state_set("_ats_gw", "1") }
if str_eq(term, "Survey") { state_set("_ats_gw", "1") }
if str_eq(term, "Paper") { state_set("_ats_gw", "1") }
if str_eq(term, "Knowledge") { state_set("_ats_gw", "1") }
if str_eq(term, "Value") { state_set("_ats_gw", "1") }
if str_eq(state_get("_ats_gw"), "0") {
state_set("cseed_auto", term)
}
} }
} }
} }
Generated Vendored
+26 -1
View File
@@ -188,7 +188,32 @@ el_val_t auto_term_try_slot(el_val_t slot_type, el_val_t slot_lbl) {
if (!str_eq(slot_lbl, EL_STR(""))) { if (!str_eq(slot_lbl, EL_STR(""))) {
el_val_t sp = str_find_chars(slot_lbl, EL_STR(" :([")); el_val_t sp = str_find_chars(slot_lbl, EL_STR(" :(["));
if (sp > 3) { if (sp > 3) {
state_set(EL_STR("cseed_auto"), str_slice(slot_lbl, 0, sp)); el_val_t term = str_slice(slot_lbl, 0, sp);
state_set(EL_STR("_ats_gw"), EL_STR("0"));
if (str_eq(term, EL_STR("Method"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Theory"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Finding"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Survey"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Paper"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Knowledge"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Value"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(state_get(EL_STR("_ats_gw")), EL_STR("0"))) {
state_set(EL_STR("cseed_auto"), term);
}
} }
} }
} }
Generated Vendored
+27 -1
View File
@@ -169,7 +169,7 @@ el_val_t mem_boot_count_inc(void) {
} }
el_val_t content = el_str_concat(EL_STR("soul:boot_count:"), int_to_str(next)); el_val_t content = el_str_concat(EL_STR("soul:boot_count:"), int_to_str(next));
el_val_t tags = EL_STR("[\"soul-meta\",\"boot-counter\"]"); el_val_t tags = EL_STR("[\"soul-meta\",\"boot-counter\"]");
el_val_t boot_node_id = engram_node_full(content, EL_STR("Memory"), EL_STR("soul:boot_count"), el_from_float(0.9), el_from_float(0.9), el_from_float(1.0), EL_STR("Canonical"), tags); el_val_t boot_node_id = engram_node_full(content, EL_STR("Memory"), EL_STR("soul:boot_count"), el_from_float(0.55), el_from_float(0.2), el_from_float(1.0), EL_STR("Working"), tags);
if (str_eq(boot_node_id, EL_STR(""))) { if (str_eq(boot_node_id, EL_STR(""))) {
println(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: write rejected (empty id) \xe2\x80\x94 boot counter node lost (count="), int_to_str(next)), EL_STR(")"))); println(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: write rejected (empty id) \xe2\x80\x94 boot counter node lost (count="), int_to_str(next)), EL_STR(")")));
return next; return next;
@@ -178,6 +178,32 @@ el_val_t mem_boot_count_inc(void) {
if (str_eq(boot_readback, EL_STR("")) || str_eq(boot_readback, EL_STR("{}"))) { if (str_eq(boot_readback, EL_STR("")) || str_eq(boot_readback, EL_STR("{}"))) {
println(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id="), boot_node_id), EL_STR(" count=")), int_to_str(next))); println(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id="), boot_node_id), EL_STR(" count=")), int_to_str(next)));
} }
el_val_t wb_url = env(EL_STR("ENGRAM_URL"));
el_val_t wb_key = env(EL_STR("ENGRAM_API_KEY"));
if (!str_eq(wb_url, EL_STR("")) && !str_eq(wb_key, EL_STR(""))) {
el_val_t auth_body = el_str_concat(el_str_concat(EL_STR("{\"_auth\":\""), json_safe(wb_key)), EL_STR("\"}"));
el_val_t srv_old = http_get(el_str_concat(wb_url, EL_STR("/api/search?q=soul:boot_count&limit=20")));
if (!str_eq(srv_old, EL_STR("")) && !str_eq(srv_old, EL_STR("[]"))) {
el_val_t srv_len = json_array_len(srv_old);
el_val_t si = 0;
while (si < srv_len) {
el_val_t srv_node = json_array_get(srv_old, si);
el_val_t srv_content = json_get(srv_node, EL_STR("content"));
if (str_starts_with(srv_content, EL_STR("soul:boot_count:"))) {
el_val_t srv_id = json_get(srv_node, EL_STR("id"));
if (!str_eq(srv_id, EL_STR(""))) {
http_delete_json(el_str_concat(el_str_concat(wb_url, EL_STR("/api/nodes/")), srv_id), auth_body);
}
}
si = (si + 1);
}
}
el_val_t wb_body = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"content\":\""), content), EL_STR("\",\"node_type\":\"Memory\",\"label\":\"soul:boot_count\",\"salience\":0.55,\"importance\":0.2,\"tier\":\"Working\",\"tags\":\"[\\\"soul-meta\\\",\\\"boot-counter\\\"]\",\"_auth\":\"")), json_safe(wb_key)), EL_STR("\"}"));
el_val_t wb_resp = http_post_json(el_str_concat(wb_url, EL_STR("/api/nodes")), wb_body);
if (str_contains(wb_resp, EL_STR("\"error\""))) {
println(el_str_concat(EL_STR("[memory] mem_boot_count_inc: HTTP write-back failed (count in-memory only): "), wb_resp));
}
}
return next; return next;
return 0; return 0;
} }
+52 -2
View File
@@ -188,10 +188,20 @@ fn mem_boot_count_inc() -> Int {
} }
let content: String = "soul:boot_count:" + int_to_str(next) let content: String = "soul:boot_count:" + int_to_str(next)
let tags: String = "[\"soul-meta\",\"boot-counter\"]" let tags: String = "[\"soul-meta\",\"boot-counter\"]"
// TELEMETRY DEMOTION (2026-07-24 self-review): this counter was written at
// salience 0.9 / importance 0.9 / tier Canonical Canonical gets +0.2
// goal bias and the 0.15 promotion threshold, so three stale copies of a
// BOOT COUNTER held the top working-memory slots (wm 0.31+) for 23h,
// crowding out real context. It is plumbing, not memory. Working tier:
// 0.40 threshold, no tier bias, and the /api/sync route excludes
// Working-tier nodes so the counter also stops leaking to the engram
// server graph, which is where the duplicate copies accumulated (the
// prune below only reaches the soul's local graph). Persistence across
// restarts comes from the soul's own snapshot (mem_save), not from sync.
let boot_node_id: String = engram_node_full( let boot_node_id: String = engram_node_full(
content, "Memory", "soul:boot_count", content, "Memory", "soul:boot_count",
el_from_float(0.9), el_from_float(0.9), el_from_float(1.0), el_from_float(0.55), el_from_float(0.2), el_from_float(1.0),
"Canonical", tags "Working", tags
) )
if str_eq(boot_node_id, "") { if str_eq(boot_node_id, "") {
println("[memory] mem_boot_count_inc: write rejected (empty id) — boot counter node lost (count=" + int_to_str(next) + ")") println("[memory] mem_boot_count_inc: write rejected (empty id) — boot counter node lost (count=" + int_to_str(next) + ")")
@@ -201,6 +211,46 @@ fn mem_boot_count_inc() -> Int {
if str_eq(boot_readback, "") || str_eq(boot_readback, "{}") { if str_eq(boot_readback, "") || str_eq(boot_readback, "{}") {
println("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id=" + boot_node_id + " count=" + int_to_str(next)) println("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id=" + boot_node_id + " count=" + int_to_str(next))
} }
// HTTP WRITE-BACK (2026-07-24 self-review): in HTTP-engram mode the server
// owns persistence and the soul's in-process graph dies with the process
// the local create above is invisible to the next boot. The counter only
// ever "persisted" via a long-gone push path, which is why the log shows
// boot #5 on three consecutive boots. Mirror the persona write-back
// pattern: delete stale server copies (dupes were the 23h WM-pollution
// bug), then create the demoted replacement server-side. Boot seeding
// reads /api/nodes, which includes Working-tier nodes, so the count
// survives restarts; the periodic /api/sync excludes Working tier, so it
// never re-imports mid-session. Fail-soft: on any HTTP error the counter
// is in-memory-only this session, same as before.
let wb_url: String = env("ENGRAM_URL")
let wb_key: String = env("ENGRAM_API_KEY")
if !str_eq(wb_url, "") && !str_eq(wb_key, "") {
let auth_body: String = "{\"_auth\":\"" + json_safe(wb_key) + "\"}"
let srv_old: String = http_get(wb_url + "/api/search?q=soul:boot_count&limit=20")
if !str_eq(srv_old, "") && !str_eq(srv_old, "[]") {
let srv_len: Int = json_array_len(srv_old)
let si: Int = 0
while si < srv_len {
let srv_node: String = json_array_get(srv_old, si)
// Match by CONTENT prefix, not label: route_create_node sets
// label = content, so server-side counter nodes carry labels
// like "soul:boot_count:6". (2026-07-24)
let srv_content: String = json_get(srv_node, "content")
if str_starts_with(srv_content, "soul:boot_count:") {
let srv_id: String = json_get(srv_node, "id")
if !str_eq(srv_id, "") {
http_delete_json(wb_url + "/api/nodes/" + srv_id, auth_body)
}
}
let si = si + 1
}
}
let wb_body: String = "{\"content\":\"" + content + "\",\"node_type\":\"Memory\",\"label\":\"soul:boot_count\",\"salience\":0.55,\"importance\":0.2,\"tier\":\"Working\",\"tags\":\"[\\\"soul-meta\\\",\\\"boot-counter\\\"]\",\"_auth\":\"" + json_safe(wb_key) + "\"}"
let wb_resp: String = http_post_json(wb_url + "/api/nodes", wb_body)
if str_contains(wb_resp, "\"error\"") {
println("[memory] mem_boot_count_inc: HTTP write-back failed (count in-memory only): " + wb_resp)
}
}
return next return next
} }