Archived
iteration-1: the compiler stops adjudicating #164
@@ -14379,7 +14379,67 @@ el_val_t engram_ise_log_append(el_val_t content_v){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fputs("\"}\n", f);
|
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);
|
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);
|
return EL_INT(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user