9a0266cbf9
Flag-on checkpoint now full-walks the resident graph: store_put_node (WM weight, activation_count, last_activated, wm_anchor) + store_put_edge (hebb, last_fired) for every node/edge, then engram_checkpoint. Uses store_put_edge (idempotent upsert) not store_hebb_batch, because activation FORMS new hebbian-associate edges that bypass the create hook and delta-only hebb_batch can't create them. Store-on boot now applies the same WM-halving + floor + cap transforms as engram_load. This is the hebb-survives-restart fix. Gate: reboot from neuron.egm with snapshot.json deleted -> edge hebb + activation_count survive unchanged, WM weight survives with identical boot transform; negative control proves persist is load-bearing (hebb->0 without it). M1 33/33 + M2 36/36 + M3 parity PASS, ASan/UBSan clean, flag-off untouched. Engine unchanged (boundary held).
156 lines
8.8 KiB
C
156 lines
8.8 KiB
C
/* test_m3_parity.c — M3 JSON-parity gate for the ENGRAM_STORE wiring.
|
|
*
|
|
* This is a REAL el-level harness: it links the actual el_runtime.o (the soul's
|
|
* native engram builtins) + engram_store.o and calls the engram_node family plus
|
|
* engram_connect, engram_activate_json, engram_save, engram_store_boot directly. No EL interpreter
|
|
* and no full soul build are needed — el_runtime.c compiles to a standalone .o
|
|
* whose engram builtins operate on the process-global engram store, and the
|
|
* string arena is inert unless el_request_start() is called, so the builtins are
|
|
* callable straight from C (el_val_t is int64_t; EL_STR/EL_CSTR are pointer casts).
|
|
*
|
|
* Modes (argv[1]), data dir (argv[2]):
|
|
* seed — ENGRAM_STORE unset: build a fixed seed graph, write snapshot.json +
|
|
* off_graph.json (pristine, pre-activation), then activate → off_act.json.
|
|
* on — ENGRAM_STORE=1: engram_store_boot(dir) imports snapshot.json ONCE into
|
|
* neuron.egm and loads it resident; write on_graph.json, then activate →
|
|
* on_act.json; checkpoint + close.
|
|
* reboot — ENGRAM_STORE=1 with snapshot.json DELETED: boot must reload from
|
|
* neuron.egm (WAL replay), never re-reading JSON; write reboot_graph.json.
|
|
* offcheck — assert flag-off leaves the store untouched.
|
|
*
|
|
* The graph comparison (done by run_m3_parity.sh via python, modulo ordering) is
|
|
* the deterministic gate; activation ids/promoted are compared as a robust set.
|
|
*/
|
|
#include "el_runtime.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* Builtins the header declares are pulled in via el_runtime.h. The M3 additions
|
|
* are not in the header yet, so declare them here. */
|
|
extern int engram_store_enabled(void);
|
|
extern el_val_t engram_store_boot(el_val_t data_dir);
|
|
extern el_val_t engram_store_checkpoint(void);
|
|
extern el_val_t engram_store_close(void);
|
|
extern el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label,
|
|
el_val_t salience, el_val_t certainty, el_val_t confidence,
|
|
el_val_t status, el_val_t tags, el_val_t layer_id);
|
|
|
|
static el_val_t S(const char* s){ return EL_STR(s); }
|
|
static el_val_t F(double d){ return el_from_float(d); }
|
|
|
|
/* Build a fixed, deterministic seed graph: 12 nodes across two layers + 9 edges.
|
|
* Content is chosen so an activation query has real matches to rank. */
|
|
static void build_seed(void){
|
|
/* core-identity layer (1) via engram_node_full */
|
|
el_val_t n0 = engram_node_full(S("tiered storage engine design"), S("Concept"),
|
|
S("storage-engine"), F(0.9), F(0.8), F(1.0), S("Semantic"), S("design,storage"));
|
|
el_val_t n1 = engram_node_full(S("write-ahead log durability"), S("Concept"),
|
|
S("wal"), F(0.85), F(0.75), F(1.0), S("Semantic"), S("wal,durability"));
|
|
el_val_t n2 = engram_node_full(S("paged buffer pool with checkpointing"), S("Concept"),
|
|
S("buffer-pool"), F(0.8), F(0.7), F(1.0), S("Semantic"), S("paging"));
|
|
el_val_t n3 = engram_node_full(S("spreading activation over the graph"), S("Concept"),
|
|
S("activation"), F(0.8), F(0.7), F(1.0), S("Semantic"), S("activation,graph"));
|
|
el_val_t n4 = engram_node_full(S("hebbian co-activation potentiation"), S("Concept"),
|
|
S("hebbian"), F(0.7), F(0.6), F(1.0), S("Semantic"), S("hebb"));
|
|
el_val_t n5 = engram_node_full(S("crash recovery replays the log"), S("Concept"),
|
|
S("recovery"), F(0.75), F(0.65), F(1.0), S("Semantic"), S("recovery,wal"));
|
|
/* domain-knowledge layer (2) via engram_node_layered */
|
|
el_val_t n6 = engram_node_layered(S("b-tree primary index id to location"), S("Fact"),
|
|
S("btree"), F(0.7), F(0.6), F(1.0), S(""), S("index"), (el_val_t)2);
|
|
el_val_t n7 = engram_node_layered(S("adjacency index for edge lookup"), S("Fact"),
|
|
S("adjacency"), F(0.7), F(0.6), F(1.0), S(""), S("index,graph"), (el_val_t)2);
|
|
el_val_t n8 = engram_node_layered(S("slotted pages hold tlv records"), S("Fact"),
|
|
S("slotted-page"), F(0.65), F(0.55), F(1.0), S(""), S("format"), (el_val_t)2);
|
|
el_val_t n9 = engram_node_full(S("memory tiers working semantic episodic"), S("Concept"),
|
|
S("tiers"), F(0.7), F(0.6), F(1.0), S("Semantic"), S("tiers,memory"));
|
|
el_val_t n10 = engram_node_full(S("embeddings enable nearest neighbour search"), S("Concept"),
|
|
S("embeddings"), F(0.65), F(0.55), F(1.0), S("Semantic"), S("embeddings"));
|
|
el_val_t n11 = engram_node_full(S("the durable engram is the mind's memory"), S("Belief"),
|
|
S("engram"), F(0.95), F(0.9), F(1.0), S("Semantic"), S("engram,memory"));
|
|
|
|
engram_connect(n0, n1, F(0.8), S("depends-on"));
|
|
engram_connect(n0, n2, F(0.8), S("depends-on"));
|
|
engram_connect(n0, n3, F(0.7), S("enables"));
|
|
engram_connect(n1, n5, F(0.9), S("enables"));
|
|
engram_connect(n3, n4, F(0.6), S("triggers"));
|
|
engram_connect(n2, n6, F(0.7), S("uses"));
|
|
engram_connect(n3, n7, F(0.7), S("uses"));
|
|
engram_connect(n0, n8, F(0.6), S("uses"));
|
|
engram_connect(n11, n9, F(0.8), S("about"));
|
|
engram_connect(n11, n10, F(0.5), S("about"));
|
|
}
|
|
|
|
static void write_file(const char* path, const char* content){
|
|
FILE* f = fopen(path, "wb");
|
|
if (!f){ fprintf(stderr, "cannot open %s\n", path); exit(2); }
|
|
if (content) fwrite(content, 1, strlen(content), f);
|
|
fclose(f);
|
|
}
|
|
|
|
static const char* QUERY = "storage engine activation and the durable log";
|
|
|
|
int main(int argc, char** argv){
|
|
if (argc < 3){ fprintf(stderr, "usage: %s <seed|on|reboot|offcheck> <dir>\n", argv[0]); return 2; }
|
|
const char* mode = argv[1];
|
|
const char* dir = argv[2];
|
|
char p[1024];
|
|
|
|
if (!strcmp(mode, "seed")){
|
|
if (engram_store_enabled()){ fprintf(stderr, "seed mode requires ENGRAM_STORE unset\n"); return 2; }
|
|
build_seed();
|
|
snprintf(p, sizeof p, "%s/snapshot.json", dir);
|
|
if (!engram_save(S(p))){ fprintf(stderr, "seed save failed\n"); return 2; }
|
|
snprintf(p, sizeof p, "%s/off_graph.json", dir);
|
|
engram_save(S(p)); /* pristine off-path graph */
|
|
el_val_t act = engram_activate_json(S(QUERY), (el_val_t)3);
|
|
snprintf(p, sizeof p, "%s/off_act.json", dir);
|
|
write_file(p, EL_CSTR(act));
|
|
printf("[seed] nodes=%lld edges=%lld\n",
|
|
(long long)(int64_t)engram_node_count(), (long long)(int64_t)engram_edge_count());
|
|
return 0;
|
|
}
|
|
if (!strcmp(mode, "on")){
|
|
if (!engram_store_enabled()){ fprintf(stderr, "on mode requires ENGRAM_STORE=1\n"); return 2; }
|
|
if (!engram_store_boot(S(dir))){ fprintf(stderr, "store boot failed\n"); return 2; }
|
|
snprintf(p, sizeof p, "%s/on_graph.json", dir);
|
|
engram_save(S(p)); /* export resident (== store) */
|
|
/* Checkpoint the freshly-imported (pristine) graph — this is the state
|
|
* the reboot comparison expects to round-trip. Under M3.5 a checkpoint
|
|
* persists the resident graph's CURRENT field state, so it must run
|
|
* BEFORE activation mutates fields in place; activation itself is
|
|
* exercised below only for the activation-result-set parity check. The
|
|
* M3.5 gate (test_m35_hebb_persist) separately proves that a checkpoint
|
|
* taken AFTER activation durably carries the learned hebb/WM state. */
|
|
engram_store_checkpoint();
|
|
el_val_t act = engram_activate_json(S(QUERY), (el_val_t)3);
|
|
snprintf(p, sizeof p, "%s/on_act.json", dir);
|
|
write_file(p, EL_CSTR(act));
|
|
printf("[on] nodes=%lld edges=%lld\n",
|
|
(long long)(int64_t)engram_node_count(), (long long)(int64_t)engram_edge_count());
|
|
engram_store_close();
|
|
return 0;
|
|
}
|
|
if (!strcmp(mode, "reboot")){
|
|
if (!engram_store_enabled()){ fprintf(stderr, "reboot mode requires ENGRAM_STORE=1\n"); return 2; }
|
|
/* snapshot.json has been deleted by the runner — boot MUST come from
|
|
* neuron.egm (+ WAL replay), never re-reading JSON. */
|
|
if (!engram_store_boot(S(dir))){ fprintf(stderr, "reboot boot failed\n"); return 2; }
|
|
snprintf(p, sizeof p, "%s/reboot_graph.json", dir);
|
|
engram_save(S(p));
|
|
printf("[reboot] nodes=%lld edges=%lld\n",
|
|
(long long)(int64_t)engram_node_count(), (long long)(int64_t)engram_edge_count());
|
|
engram_store_close();
|
|
return 0;
|
|
}
|
|
if (!strcmp(mode, "offcheck")){
|
|
/* ENGRAM_STORE unset: enabled()==0 and boot is a no-op returning 0. */
|
|
int en = engram_store_enabled();
|
|
el_val_t b = engram_store_boot(S(dir));
|
|
printf("[offcheck] enabled=%d boot_ret=%lld\n", en, (long long)(int64_t)b);
|
|
return (en == 0 && (int64_t)b == 0) ? 0 : 1;
|
|
}
|
|
fprintf(stderr, "unknown mode %s\n", mode);
|
|
return 2;
|
|
}
|