Skip to content

fix(bots): never blank a letter, and drop blank paper on the ground - #714

Merged
frandallfarmer merged 2 commits into
masterfrom
fix/oracle-never-blank-letters
Oct 15, 2026
Merged

frandallfarmer merged 2 commits into
masterfrom
fix/oracle-never-blank-letters

Conversation

@frandallfarmer

Copy link
Copy Markdown
Owner

Supersedes #702, which is included here as the first commit — the two changes touch the same lines and are the same subject: where paper goes when the Oracle is done with it.

1. Blank paper goes on the ground, not in a pocket (your rule)

-  return bot.send({ op: 'PUT', to: ref, containerNoid: me.noid, x: 0, y: DISCARD_SLOT, orientation: 0 })
+  return bot.send({ op: 'PUT', to: ref, containerNoid: THE_REGION })

Paper.PUT defaults containerNoid to THE_REGION (Constants.java:272) and x/y/orientation to the avatar's own, so this drops the sheet at the bot's feet, where the region recycles it. A pocket would keep it, and a bot that accumulates paper runs out of slots.

2. Never blank a letter — it deletes a body other sheets still point at

Elko's trace, 2026-09-30:

17:05:00.922  Showing written Paper paper-i-2495581085713971936-…      ← read OK
17:05:01.998  Avatar Oracle requested clearing of contents for Paper …  ← body DELETED
17:05:02.500  PUT success for Paper text-emptypaper: true               ← that sheet destroyed ✓
17:05:03.006  Advanced Mail slot … to paper-i-2495581085713971936-…     ← new sheet → deleted body

Letter bodies are shared: Paper.sendMailToUser reuses the sender's text_path for the queued record (Paper.java:657), and Avatar.advance_mail_slot points the next MAIL_SLOT sheet at that same path (Avatar.java:1990). Paper.WRITE's clear calls deletePaperContents(), deleting the body document — so blanking one sheet destroys content other sheets and queued records reference. Three sheets carried that one body in the trace.

The handed-over letter is then unreadable from birth. clearHands can't deliver it and correctly refuses to destroy an unread letter, so it stays in the hands — and a full hand blocks every Paper.GET, killing mail in both directions. That is what left husks in the Oracle's hands in September and again on Sept 30.

putDownHeldPaper puts a sheet down exactly as it is. Paper.PUT only destroys when is_blank(), so a letter survives intact and the hands come free. special_get already spawned the replacement in MAIL_SLOT.

  • drainMailSlot — after reading a letter: put down, no blanking
  • oracle.js — after relaying a recovered letter: put down, no blanking
  • discardHeldPaper — unchanged, now documented as our own drafts only: we created those bodies, so blanking them is safe

A human rarely blanks a letter they received, which is why this went unnoticed; the bot did it to every letter it read.

npm test — 58 pass, including new tests that a blanked sheet goes to THE_REGION with no pocket slot, and that a letter read from the mail slot is not blanked.

What this does not fix

Read letters now accumulate on the floor of context-oraclehome, one per inbound mail, because the region only recycles blank paper. The real fix is server-side — don't delete a body another sheet or queued record still references, or copy the body on delivery rather than sharing it. That's elko, so it needs your sign-off.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PP6PsCtYXunah4Y9vczMJb

frandallfarmer and others added 2 commits October 15, 2026 10:17
Disposal put the blanked sheet into pocket slot 0 (containerNoid = the
avatar). Paper.PUT does destroy a blank sheet wherever it lands, but a pocket
is the wrong place for a bot to aim: anything that survives — a sheet whose
blanking didn't take, say — stays in the pocket, and a bot that accumulates
paper there runs out of free slots and can no longer pick anything up.

Put it down on the ground instead (Randy's rule): the region recycles a blank
sheet left on the floor. Paper.PUT defaults containerNoid to THE_REGION
(Constants.java:272) and x/y/orientation to the avatar's own, so sending only
containerNoid: 0 drops the sheet at the bot's feet.

Both disposal paths go through this — drainMailSlot after reading a letter,
and discardHeldPaper after delivering one — and habibots/lib/mail.js is shared
with sage, so its mail path gets the same behaviour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PP6PsCtYXunah4Y9vczMJb
The Oracle kept ending up with letters in its hands that it could neither read
nor safely destroy. Diagnosed from elko's own trace on 2026-09-30:

  17:05:01.998  clearing contents for Paper paper-i-2495581085713971936-…
  17:05:02.500  PUT success for Paper text-emptypaper: true     (that sheet destroyed)
  17:05:03.006  Advanced Mail slot … to paper-i-2495581085713971936-…

Letter bodies are SHARED. Paper.sendMailToUser reuses the sender's text_path for
the queued record (Paper.java:657), and Avatar.advance_mail_slot points the next
MAIL_SLOT sheet at that same path (Avatar.java:1990). Paper.WRITE's clear calls
deletePaperContents(), which removes the body document outright — so blanking one
sheet destroys content other sheets and queued records still reference. The newly
handed-over letter is unreadable from birth; clearHands then cannot deliver it and
correctly refuses to destroy an unread letter, so it sits in the hands forever and
blocks every Paper.GET. Three sheets carried that one body in the trace above.

So: never blank a letter. putDownHeldPaper puts the sheet on the ground exactly as
it is — Paper.PUT only destroys when is_blank(), so the content survives for
whoever else points at it, and the hands come free. Paper.GET's special_get has
already spawned the replacement sheet in MAIL_SLOT, so nothing needs the old one.
Blanking stays for sheets we wrote ourselves, whose bodies nothing else references.

A human rarely blanks a letter they received, which is why this went unnoticed; the
bot did it to every letter it read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PP6PsCtYXunah4Y9vczMJb
@frandallfarmer
frandallfarmer merged commit 510ec80 into master Oct 15, 2026
13 checks passed
@frandallfarmer
frandallfarmer deleted the fix/oracle-never-blank-letters branch October 15, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant