init is idempotent by test; put it in the command table

This commit is contained in:
victortaelin 2026-07-26 14:39:55 -03:00
parent bd2a799500
commit 2623c95294
2 changed files with 42 additions and 11 deletions

27
memo
View file

@ -366,13 +366,13 @@ from another agent, you are that subagent: skip this section.
"""
def cmd_init(args):
def cmd_init(d, args):
"""The one command that may create the memory directory, and the whole
setup: make the store, write the size knobs, print the block the user
pastes into their agent's instruction file."""
pastes into their agent's instruction file. Re-running it is safe: it
only ever creates what is missing, and never rewrites what is there."""
if args:
die("usage: memo init")
d = memory_dir()
fresh = not os.path.isdir(d)
os.makedirs(os.path.join(d, "TREE"), exist_ok=True)
open(log_path(d), "a").close()
@ -595,24 +595,29 @@ def cmd_import(d, args):
print("%s pending. Run: memo sleep" % plural(n, "compression"))
COMMANDS = {"wake": cmd_wake, "note": cmd_note, "sleep": cmd_sleep,
"recall": cmd_recall, "forget": cmd_forget, "import": cmd_import}
COMMANDS = {"init": cmd_init, "wake": cmd_wake, "note": cmd_note,
"sleep": cmd_sleep, "recall": cmd_recall, "forget": cmd_forget,
"import": cmd_import}
def main():
if len(sys.argv) < 2:
print(__doc__.strip())
sys.exit(0)
if sys.argv[1] == "init":
cmd_init(sys.argv[2:])
return
if sys.argv[1] not in COMMANDS:
print("No such command: %s\n" % sys.argv[1], file=sys.stderr)
cmd = sys.argv[1]
if cmd not in COMMANDS:
print("No such command: %s\n" % cmd, file=sys.stderr)
print(__doc__.strip(), file=sys.stderr)
sys.exit(1)
# `init` is the only command that may run without an existing memory:
# it is the one that creates it. Every other command refuses, so a typo
# in MEMORY_DIR is an error instead of a second, empty identity.
if cmd == "init":
cmd_init(memory_dir(), sys.argv[2:])
return
d = store()
config(d)
COMMANDS[sys.argv[1]](d, sys.argv[2:])
COMMANDS[cmd](d, sys.argv[2:])
if __name__ == "__main__":

26
test.py
View file

@ -385,6 +385,32 @@ r = run("wake", store=d2)
check(r.stdout.rstrip().endswith("You are awake."),
"a one-part wake never says `You are awake.`:\n" + r.stdout)
# re-running init on a lived-in store must not touch one byte of it: the
# whole setup is idempotent, so it is safe on every provision. `init` only
# ever makedirs(exist_ok), opens LOG.txt for APPEND, and writes `config`
# when absent -- never truncating, never overwriting a tuned config.
def fingerprint(path):
out = {}
for root, _, files in os.walk(path):
for f in files:
if f == ".lock":
continue
p = os.path.join(root, f)
out[os.path.relpath(p, path)] = open(p, "rb").read()
return out
with open(os.path.join(d, "config"), "a") as f:
f.write("WAKE_LINES=120\n") # a size the user tuned by hand
before = fingerprint(d)
check(len(before) > 3 and before["LOG.txt"], "the store under test is empty")
for _ in range(3):
r = run("init")
check(r.returncode == 0 and "Found" in r.stdout, "init on a live store failed")
check(fingerprint(d) == before, "init modified an existing memory")
r = run("wake")
check(r.stdout.rstrip().endswith("You are awake."), "wake broke after re-init")
shutil.rmtree(d2)
shutil.rmtree(d)
print("\n%d passed, %d failed" % (ok, fail))