Commit graph

10 commits

Author SHA1 Message Date
victortaelin
c08119e701 note criteria: new + important + lasting, and never redundant 2026-07-25 17:53:22 -03:00
victortaelin
1f1ec1511e prompts re-derived from scratch: inclusive block ids, honest terminators, orders with recovery
- Block ids are inclusive everywhere (16-31 = memories #16..#31), matching
  what the wake document prints. Before, wake showed #16-31 but sleep and
  forget demanded 16-32: an agent copying its own document was rejected.
- Only a successful wake says 'You are awake.' Sleep ends with 'Nothing left
  to compress.' Before, the final sleep of a refused wake claimed the agent
  was awake when it had read zero memories.
- An empty store's wake also ends with 'You are awake.' (it never did, so a
  fresh agent could not satisfy its own instructions).
- Wake's refusal closes the loop: 'Do them, then run memo wake again.'
- Nap prompt names its object first and labels merged halves with their ids.
- Every error ends with the recovery command.
- README synced to reality (it still quoted the pre-terseness prompts,
  TREE.txt, and 'four commands').
2026-07-25 17:38:56 -03:00
victortaelin
af17f94c2f every command handed to an agent is an order, not a label
'next: memo wake 2 246' is an annotation, not an instruction. ASD-STE100:
an instruction is an imperative, verb first. Same defect in the nap prompt,
where the command sat on a bare line with nothing telling the agent to run it.

The wake terminator is 'You are awake.', the same words memo sleep already
used, instead of a bare 'awake.' -- one term, one meaning.

test.py now asserts that every offered command starts with 'Run: '.
2026-07-25 17:20:01 -03:00
victortaelin
dc5339c55b test: 100s -> 1.6s
The suite spawned a python interpreter per nap, ~2000 of them. The CLI now
runs in-process; real processes are kept only for the cross-process lock
test, which is their subject. The 3000-step cover sweep is sampled: the
property is structural, not a function of the exact T.
2026-07-25 17:15:33 -03:00
victortaelin
fdcc92eeea wake always ends with 'awake.', even when the memory fits one part
AGENTS.md tells the agent to run parts until one says 'awake.' A one-part
memory printed no terminator, so the word never arrived.
2026-07-25 17:12:11 -03:00
victortaelin
672cbbdb9c terse prompts; fix id race, torn writes, wake races, unbounded recall
Prompts were verbose and repeated the same story in every tool result, which
floods context and eats the output budget. They are now instructions only,
stated once. The 4-line wake footer is 'next: memo wake 2 246'.

Real harness caps, verified from source (Claude Code 30,000 chars, pi 50 KB /
2000 lines, Codex 10,000 tokens): the old PART_CHARS=8000 was sized against a
wrong 10 KiB figure and cost 8 calls per wake. 20000 costs 4.

Bugs found by audit:
- note assigned its id outside the lock: parallel sessions could collide
- a torn record from a crash misaligned every later record, permanently
- a note landing between two wake parts could shift a boundary and drop a line
  (wake parts now render as of an explicit T)
- recall printed unboundedly and was silently truncated by the harness
2026-07-25 15:43:08 -03:00
Victor Taelin
363ff72d8c audit fixes: UTF-8 record corruption, byte-vs-char limits
- log_slice decoded the whole buffer then sliced at 320-CHARACTER offsets;
  one multi-byte char (memory #42: 'Gestão') shifted every later record and
  crashed recall on the live store. Records are bytes: slice, then decode.
- limits counted characters while records are bytes, so 150 'ã's passed
  check() and died inside pad() mid-append. check/import/paginate now count
  UTF-8 bytes; config rejects an ENTRY_CHARS the records cannot fit.
- tests were ASCII-only (why 239k assertions missed it): UTF-8 cases added.
2026-07-25 14:49:34 -03:00
Victor Taelin
e123c89317 fixed-width records: O(1) lookup, no scanning
Finding a block meant parsing the whole tree: 1.3s at a million memories, and
the Minilins write fast enough to get there. Records are now fixed width, so
position is identity -- memory i at i*320 of LOG.txt, block [ks,(k+1)s) at
k*288 of TREE/s. One seek, no index file to keep in sync.

A directory of one file per block was the obvious alternative and is worse:
25x disk (781 MB for 31 MB of text) and finding pending work still scans.
Here a level file is a dense prefix, so its length IS the watermark: pending
costs one stat per level. Measured at 1M memories: wake 0.96s -> 0.03s,
note 1.30s -> 0.02s, disk 370 MB -> 607 MB.
2026-07-25 14:34:29 -03:00
Victor Taelin
e544f6548a wake in parts: a single-shot dump is silently truncated by every harness
Measured: Codex CLI cuts tool output at 10 KiB or 256 lines, Claude Code at
30,000 chars, pi at 50 KB -- and each drops a different piece. A 320-line
memory is ~79 KB, so waking was losing memories everywhere, silently. Observed
live on pi: memories #0-#41, the compressed ancient past, vanished.

memo wake now pages the document into parts under the strictest cap and each
part names the exact command for the next. No harness is special-cased.
2026-07-25 14:22:29 -03:00
Victor Taelin
7e3d55dad6 OptMem: a permanent, append-only memory for AI agents 2026-07-25 13:58:35 -03:00