Independent review found 1 BLOCKER + 3 CONCERNs + 4 NITs.
R-B1 (BLOCKER): TOCTOU race on memory.jsonl — two aish processes
scanning the same file compute identical next_ids. Resolution:
flock(LOCK_EX | LOCK_NB) on the fd in M.open_memory, held until
close. Bundled into commit #1 (per reviewer: cannot defer because
adding flock retroactively means reopening the handle). Requires
ffi/libc.lua extension: flock cdef + LOCK_EX/LOCK_NB/LOCK_UN
constants + M.flock wrapper.
R-C1 (CONCERN, closes Q33): [background] block suppressed when
ctx.norris_active. Avoids ~16K of redundant tokens per 8-step
Norris run. Norris already anchors via its goal in the NORRIS
suffix; memory items rarely change step-to-step planning.
R-C2 (CONCERN): summarizer self-amplification — running :memory
summarize twice in one session would feed the prior summarize
call's assistant turn into the next input. Resolution: operate
on the session log file (history.load(session_path)) instead
of ctx:to_messages(), and tag prior summarize turns with
meta="summarize" so they're filterable.
R-C3 (CONCERN, cosmetic): §5 diagram clarified that
DEFAULT_SYSTEM_PROMPT already carries the Phase 2 MCP block
statically — not a separate dynamic block in v1.
NITs N1-N4 folded inline:
N1 forget no-op for unknown id surfaces a status
N2 path note: memory.jsonl is sibling of sessions/, no collision
N3 item-id invariants: id >= 1; meta header has no id; tombstones
with non-matching targets are no-ops
N4 :memory inject semantics explicit (replace ctx.memory_items
from a fresh load + LRU-by-ts truncation)
§3 module-changes table grew a new ffi/libc.lua row.
§12 commit #1 description tightened — flock work bundled inline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>