iteration-1: the compiler stops adjudicating #164

Merged
will.anderson merged 49 commits from iteration-1 into dev 2026-08-17 15:55:22 +00:00
Showing only changes of commit 82e998273b - Show all commits
+60
View File
@@ -14379,7 +14379,67 @@ el_val_t engram_ise_log_append(el_val_t content_v){
}
}
fputs("\"}\n", f);
/* RETENTION (2026-08-17 self-review). The on-graph ISE branch in
* server.el calls engram_prune_telemetry(48h) on every insert, but that
* branch is DEAD in production: ENGRAM_ISE_OFFGRAPH=1 is the live
* setting, so every state event lands here instead and this path had
* no retention of any kind. Measured: 17.1 MB / 14,305 events over 3.56
* days = 4.81 MB/day, growing without bound (~1.76 GB/year). The graph
* got its telemetry-growth fix on 2026-07-16; moving telemetry off-graph
* moved the leak rather than closing it.
*
* Byte-bounded rather than time-bounded on purpose: this is a flat
* append-only file with no index, so size is the property that actually
* has to be bounded, and a byte check is O(1) against the handle we
* already hold (ftell) instead of an O(file) timestamp scan per append.
* At the measured rate the 64 MB default retains ~13 days comfortably
* more history than the 48h the on-graph path kept.
*
* Compaction keeps the TAIL, never the head: engram_dreams_json reads
* the last ~2 MB of this file for dream-recall, so the recent end is the
* end that has a reader. KEEP is held well above that 2 MB window so
* recall is never truncated by a rotation. The honesty rail is
* preserved exactly as before rotated-out remains "I don't remember",
* never a synthesized dream; this only makes the forgetting bounded and
* explicit instead of deferred forever. */
long pos = ftell(f);
fclose(f);
{
long maxb = 64L*1024L*1024L;
long keepb = 16L*1024L*1024L;
const char* mv = getenv("ENGRAM_ISE_LOG_MAX_BYTES");
if (mv && *mv) { long v = atol(mv); if (v > 0) maxb = v; }
if (keepb > maxb/2) keepb = maxb/2;
if (pos > 0 && pos > maxb) {
FILE* rf = fopen(path, "rb");
if (rf) {
if (fseek(rf, pos - keepb, SEEK_SET) == 0) {
char* buf = (char*)malloc((size_t)keepb + 1);
if (buf) {
size_t rd = fread(buf, 1, (size_t)keepb, rf);
buf[rd] = 0;
/* Resume at the first LINE boundary so the tail never
* begins with a half-written JSON record. */
char* start = memchr(buf, '\n', rd);
start = start ? start + 1 : buf;
size_t keep_n = rd - (size_t)(start - buf);
char tmp[4096];
snprintf(tmp, sizeof tmp, "%s/state-events.jsonl.tmp", dir);
FILE* wf = fopen(tmp, "wb");
if (wf) {
int ok = (fwrite(start, 1, keep_n, wf) == keep_n);
fclose(wf);
/* Only replace the live log if the tail was written
* in full a short write must not destroy history. */
if (ok) rename(tmp, path); else remove(tmp);
}
free(buf);
}
}
fclose(rf);
}
}
}
return EL_INT(1);
}