the merge command is nap, not sleep: it never was a nightly job

This commit is contained in:
victortaelin 2026-07-26 15:50:16 -03:00
parent e61c97df36
commit bfdeae2170
3 changed files with 34 additions and 34 deletions

View file

@ -20,9 +20,9 @@ update.
|---|---| |---|---|
| `memo wake` | read the memory — the first command of every session | | `memo wake` | read the memory — the first command of every session |
| `memo note "..."` | record one memory: one line, up to 280 chars | | `memo note "..."` | record one memory: one line, up to 280 chars |
| `memo sleep` | answer the merges that came due | | `memo nap` | answer the merges that came due |
| `memo recall <regex>` | search every memory ever recorded, word for word | | `memo recall <regex>` | search every memory ever recorded, word for word |
| `memo forget <lo>-<hi>` | drop a bad summary; the next sleep rebuilds it | | `memo forget <lo>-<hi>` | drop a bad summary; the next nap rebuilds it |
Merges arrive one at a time, in the output of `note`. Nothing ever runs in the Merges arrive one at a time, in the output of `note`. Nothing ever runs in the
background. background.

22
memo
View file

@ -4,9 +4,9 @@
memo init create this machine's memory, print the setup block. memo init create this machine's memory, print the setup block.
memo wake [part [T]] read your memory. Run first, every session. memo wake [part [T]] read your memory. Run first, every session.
memo note "..." record one memory: one short line. memo note "..." record one memory: one short line.
memo sleep [id "..."] do the pending compressions. memo nap [id "..."] do the pending compressions.
memo recall <regex> search every memory ever recorded. memo recall <regex> search every memory ever recorded.
memo forget <lo>-<hi> drop a bad summary; sleep rebuilds it. memo forget <lo>-<hi> drop a bad summary; nap rebuilds it.
memo config [NAME=N] show this memory's sizes, or change one. memo config [NAME=N] show this memory's sizes, or change one.
memo import <file> bulk-load dated memories (bootstrap only). memo import <file> bulk-load dated memories (bootstrap only).
@ -379,7 +379,7 @@ def nap_prompt(d, lo, hi, left):
for a, b in ((lo, mid), (mid, hi)): for a, b in ((lo, mid), (mid, hi)):
s = tree_get(d, a, b) s = tree_get(d, a, b)
if s is None: if s is None:
die("Summary %d-%d is missing. Run: memo sleep" % (a, b - 1)) die("Summary %d-%d is missing. Run: memo nap" % (a, b - 1))
halves.append(" #%d-%d %s" % (a, b - 1, s)) halves.append(" #%d-%d %s" % (a, b - 1, s))
body = "\n".join(halves) body = "\n".join(halves)
tail = "" if not left else "\n%s after this one." % ( tail = "" if not left else "\n%s after this one." % (
@ -389,7 +389,7 @@ def nap_prompt(d, lo, hi, left):
"Keep what has lasting effect, drop what does not. Invent " "Keep what has lasting effect, drop what does not. Invent "
"nothing.\n\n" "nothing.\n\n"
"%s\n%s\n" "%s\n%s\n"
"Run: memo sleep %d-%d \"<your line>\"" "Run: memo nap %d-%d \"<your line>\""
% (lo, hi - 1, ENTRY_CHARS, body, tail, lo, hi - 1)) % (lo, hi - 1, ENTRY_CHARS, body, tail, lo, hi - 1))
@ -561,12 +561,12 @@ def cmd_note(d, args):
print("\n" + nap) print("\n" + nap)
def cmd_sleep(d, args): def cmd_nap(d, args):
T, said = log_len(d), False T, said = log_len(d), False
if args: if args:
said = True said = True
if len(args) != 2: if len(args) != 2:
die("usage: memo sleep <lo>-<hi> \"<one line>\"") die("usage: memo nap <lo>-<hi> \"<one line>\"")
m = re.fullmatch(r"(\d+)-(\d+)", args[0]) m = re.fullmatch(r"(\d+)-(\d+)", args[0])
if not m: if not m:
die("'%s' is not a block id. Copy it from the prompt." % args[0]) die("'%s' is not a block id. Copy it from the prompt." % args[0])
@ -580,7 +580,7 @@ def cmd_sleep(d, args):
print("%d-%d is already settled." % (lo, hi - 1)) print("%d-%d is already settled." % (lo, hi - 1))
else: else:
die("Wrong block: %s. Blocks are built in order; the next is " die("Wrong block: %s. Blocks are built in order; the next is "
"%d-%d. Run: memo sleep" "%d-%d. Run: memo nap"
% (args[0], todo[0][0], todo[0][1] - 1)) % (args[0], todo[0][0], todo[0][1] - 1))
elif not tree_put(d, lo, hi, check(args[1])): elif not tree_put(d, lo, hi, check(args[1])):
print("%d-%d was settled or forgotten meanwhile." % (lo, hi - 1)) print("%d-%d was settled or forgotten meanwhile." % (lo, hi - 1))
@ -618,7 +618,7 @@ def cmd_config(d, args):
def cmd_forget(d, args): def cmd_forget(d, args):
"""A summary can be wrong -- mistyped, or a bad compression. Drop it and """A summary can be wrong -- mistyped, or a bad compression. Drop it and
everything built on top of it; the next sleep computes them again. The log everything built on top of it; the next nap computes them again. The log
is untouched, so nothing is ever actually lost.""" is untouched, so nothing is ever actually lost."""
if len(args) != 1: if len(args) != 1:
die("usage: memo forget <lo>-<hi>") die("usage: memo forget <lo>-<hi>")
@ -633,7 +633,7 @@ def cmd_forget(d, args):
gone = tree_drop(d, lo, hi) gone = tree_drop(d, lo, hi)
if not gone: if not gone:
die("No summary at %s." % args[0]) die("No summary at %s." % args[0])
print("Forgot %s, from %d-%d up. Run: memo sleep" print("Forgot %s, from %d-%d up. Run: memo nap"
% (plural(len(gone), "summary"), gone[0][0], gone[0][1] - 1)) % (plural(len(gone), "summary"), gone[0][0], gone[0][1] - 1))
@ -699,11 +699,11 @@ def cmd_import(d, args):
% (plural(len(out), "memory"), base, base + len(out) - 1)) % (plural(len(out), "memory"), base, base + len(out) - 1))
n = pending_count(d, log_len(d)) n = pending_count(d, log_len(d))
if n: if n:
print("%s pending. Run: memo sleep" % plural(n, "compression")) print("%s pending. Run: memo nap" % plural(n, "compression"))
COMMANDS = {"init": cmd_init, "wake": cmd_wake, "note": cmd_note, COMMANDS = {"init": cmd_init, "wake": cmd_wake, "note": cmd_note,
"sleep": cmd_sleep, "recall": cmd_recall, "forget": cmd_forget, "nap": cmd_nap, "recall": cmd_recall, "forget": cmd_forget,
"config": cmd_config, "import": cmd_import} "config": cmd_config, "import": cmd_import}

42
test.py
View file

@ -122,14 +122,14 @@ def run(*args, store=None):
def nap_id(out): def nap_id(out):
"""The block id from the command a nap prompt offers.""" """The block id from the command a nap prompt offers."""
m = re.search(r"memo sleep (\d+)-(\d+)", out) m = re.search(r"memo nap (\d+)-(\d+)", out)
return "%s-%s" % m.groups() if m else None return "%s-%s" % m.groups() if m else None
def offered(out): def offered(out):
"""The line offering a command. Every command handed to an agent must be """The line offering a command. Every command handed to an agent must be
an order, not a label: `Run: memo ...`, never `next: memo ...`.""" an order, not a label: `Run: memo ...`, never `next: memo ...`."""
return [l for l in out.splitlines() if "memo sleep " in l or "memo wake " in l] return [l for l in out.splitlines() if "memo nap " in l or "memo wake " in l]
# the real entry point still has to work: shebang, argv parsing, exit code # the real entry point still has to work: shebang, argv parsing, exit code
@ -192,9 +192,9 @@ check("run memo wake again" in r.stdout,
"the refusal must order the agent back to wake") "the refusal must order the agent back to wake")
check("None" not in r.stdout, "the refusal printed a Python None") check("None" not in r.stdout, "the refusal printed a Python None")
# sleep loop, with a fake compressor # nap loop, with a fake compressor
naps = 0 naps = 0
r = run("sleep") r = run("nap")
check("Compress memories #" in r.stdout, "nap prompt must name its object") check("Compress memories #" in r.stdout, "nap prompt must name its object")
while "Nothing left to compress" not in r.stdout: while "Nothing left to compress" not in r.stdout:
line = offered(r.stdout) line = offered(r.stdout)
@ -205,15 +205,15 @@ while "Nothing left to compress" not in r.stdout:
"an order: %r" % line[0]) "an order: %r" % line[0])
bid = nap_id(r.stdout) bid = nap_id(r.stdout)
body = [l.strip() for l in r.stdout.splitlines() if l.startswith(" #")] body = [l.strip() for l in r.stdout.splitlines() if l.startswith(" #")]
r = run("sleep", bid, (" ".join(body)[:280]).strip() or "empty") r = run("nap", bid, (" ".join(body)[:280]).strip() or "empty")
check(r.returncode == 0, "sleep rejected a valid nap: " + r.stderr) check(r.returncode == 0, "nap rejected a valid merge: " + r.stderr)
naps += 1 naps += 1
check("You are awake" not in r.stdout, check("You are awake" not in r.stdout,
"sleep must never claim the agent is awake; only wake may") "nap must never claim the agent is awake; only wake may")
check(naps == len(complete(N)), "did %d naps, expected %d" % (naps, len(complete(N)))) check(naps == len(complete(N)), "did %d naps, expected %d" % (naps, len(complete(N))))
r = run("wake") r = run("wake")
check(r.returncode == 0, "wake still refuses after a full sleep") check(r.returncode == 0, "wake still refuses after a full nap chain")
# the document survives pagination, and every part fits every harness's cap # the document survives pagination, and every part fits every harness's cap
parts, k = [], 1 parts, k = [], 1
@ -248,10 +248,10 @@ for f in os.listdir(os.path.join(d, "TREE")):
check(os.path.getsize(os.path.join(d, "TREE", f)) % 288 == 0, check(os.path.getsize(os.path.join(d, "TREE", f)) % 288 == 0,
"TREE/%s is not a whole number of records" % f) "TREE/%s is not a whole number of records" % f)
# a sleep when nothing is pending writes nothing and says so # a nap when nothing is pending writes nothing and says so
r = run("sleep", "0-1", "attempted overwrite") r = run("nap", "0-1", "attempted overwrite")
check(r.returncode == 0 and "Nothing left to compress" in r.stdout, check(r.returncode == 0 and "Nothing left to compress" in r.stdout,
"sleep with nothing pending must say so and write nothing") "nap with nothing pending must say so and write nothing")
# recall reaches memories the summaries lost, and matches the whole line: # recall reaches memories the summaries lost, and matches the whole line:
# id and date included, not just the text # id and date included, not just the text
@ -278,22 +278,22 @@ check(run("wake").returncode == 1, "wake should refuse after a forget")
# a settled block cannot be rewritten. Resubmitting one (two sessions paid # a settled block cannot be rewritten. Resubmitting one (two sessions paid
# the same nap) is not an error: say it is settled, write nothing # the same nap) is not an error: say it is settled, write nothing
mid = treesize() mid = treesize()
r = run("sleep", "0-1", "attempted overwrite") r = run("nap", "0-1", "attempted overwrite")
check(r.returncode == 0 and "already settled" in r.stdout, check(r.returncode == 0 and "already settled" in r.stdout,
"resubmitting a settled block was not reported as settled: " + r.stderr) "resubmitting a settled block was not reported as settled: " + r.stderr)
check(treesize() == mid, "resubmitting a settled block wrote something") check(treesize() == mid, "resubmitting a settled block wrote something")
# a block that is neither settled nor next (here: a dropped ancestor, # a block that is neither settled nor next (here: a dropped ancestor,
# submitted before its half is rebuilt) is a real mistake # submitted before its half is rebuilt) is a real mistake
r = run("sleep", "0-31", "out of order") r = run("nap", "0-31", "out of order")
check(r.returncode == 1 and "Wrong block" in r.stderr, check(r.returncode == 1 and "Wrong block" in r.stderr,
"an out-of-order block was accepted") "an out-of-order block was accepted")
n = 0 n = 0
while True: while True:
r = run("sleep") r = run("nap")
if "Nothing left to compress" in r.stdout: if "Nothing left to compress" in r.stdout:
break break
bid = nap_id(r.stdout) bid = nap_id(r.stdout)
check(run("sleep", bid, "rebuilt after forget").returncode == 0, "rebuild rejected") check(run("nap", bid, "rebuilt after forget").returncode == 0, "rebuild rejected")
n += 1 n += 1
check(n > 0, "forget created no work") check(n > 0, "forget created no work")
check(run("wake").returncode == 0, "wake still refuses after rebuilding") check(run("wake").returncode == 0, "wake still refuses after rebuilding")
@ -314,11 +314,11 @@ check(r.returncode == 1 and "300 bytes" in r.stderr,
# note landed -> its blocks are pending; settle before the final wake check # note landed -> its blocks are pending; settle before the final wake check
while True: while True:
r = run("sleep") r = run("nap")
if "Nothing left to compress" in r.stdout: if "Nothing left to compress" in r.stdout:
break break
bid = nap_id(r.stdout) bid = nap_id(r.stdout)
run("sleep", bid, "settled") run("nap", bid, "settled")
check(run("wake").returncode == 0, "wake refuses at the very end") check(run("wake").returncode == 0, "wake refuses at the very end")
# a part is rendered as of T, so a note landing mid-wake cannot shift a # a part is rendered as of T, so a note landing mid-wake cannot shift a
@ -336,10 +336,10 @@ check(run("wake", "1", str(T0 + 99)).returncode == 1, "wake accepted a future T"
# never count as negative work, or the rest of the wake is refused with an # never count as negative work, or the rest of the wake is refused with an
# impossible number. # impossible number.
while True: while True:
r = run("sleep") r = run("nap")
if "Nothing left to compress" in r.stdout: if "Nothing left to compress" in r.stdout:
break break
run("sleep", nap_id(r.stdout), "settled mid-wake") run("nap", nap_id(r.stdout), "settled mid-wake")
r = run("wake", "1", str(T0)) r = run("wake", "1", str(T0))
check(r.returncode == 0 and r.stdout == before.stdout, check(r.returncode == 0 and r.stdout == before.stdout,
"a compression paid mid-wake broke the rest of the wake:\n" "a compression paid mid-wake broke the rest of the wake:\n"
@ -386,11 +386,11 @@ check("#%d " % P in r.stdout, "the memory after a torn write reads wrong")
# a memory small enough to fit one part must still end with the terminator # a memory small enough to fit one part must still end with the terminator
# the agent was told to wait for # the agent was told to wait for
while True: while True:
r = run("sleep", store=d2) r = run("nap", store=d2)
if "Nothing left to compress" in r.stdout: if "Nothing left to compress" in r.stdout:
break break
bid = nap_id(r.stdout) bid = nap_id(r.stdout)
run("sleep", bid, "settled", store=d2) run("nap", bid, "settled", store=d2)
r = run("wake", store=d2) r = run("wake", store=d2)
check(r.stdout.rstrip().endswith("You are awake."), check(r.stdout.rstrip().endswith("You are awake."),
"a one-part wake never says `You are awake.`:\n" + r.stdout) "a one-part wake never says `You are awake.`:\n" + r.stdout)