Skip to content
C.W.K.
Stream
Lesson 04 of 05 · published

Never Replay Keystrokes

~12 min · replay, queue, create, disconnect, idempotency

Level 0Spark
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

A Queue Across a Hangup Is a Time Bomb

While the phone is locked, or in a tunnel, it is tempting to keep the keystrokes that did not leave, and send them when the network returns. That queue is a time bomb. The line has changed. The pager may have opened. The confirmation may have been answered on the Mac. The lease may belong to someone else. Replaying the queue is submitting a past self into a present that did not ask. A disconnected client that keeps an input queue is how you ship a yes into a prompt that is now a no, or a command into a shell that is now a password field.

Drop the queue when the attachment dies. Drop it when the lease dies. Drop it when you become a spectator, which reconnect already forced. There is no "offline typing buffer" that is honest for a host PTY you cannot see. Offline typing belongs, if anywhere, in a draft outside the PTY — the next lesson's Anvil view — where it cannot hit Enter by itself.

Uncertain Create Is Not Retried

Opening a new shell is not idempotent. You asked the daemon to create. The phone died before the receipt came back. Did the shell start? Maybe. Retrying the create is how you get two shells, two seats, two compilers, and a receipt that names the second while you think you are looking at the first. An uncertain create stays uncertain until you browse. The session list is the truth. If a new identity is there, you attach as spectator. If it is not, you may ask again, as a new ask, in the present, knowing you are asking.

The receipt from Track 4 is the tool. No receipt, no belief that create finished. A spinner that retries on reconnect is a factory in the pocket. Create is allowed to fail visibly. It is not allowed to double. The same rule covers uncertain Take Control, uncertain Close, uncertain Return Control. At-most-once for those acts, then look. At-least-once is for downloads, not for shells, not for leases, not for kills.

Replay Is for Output, Never for Input

Track 2's journal replay paints history into the emulator and suppresses side effects. That is the only replay in the product. Input does not get one. Not keystrokes, not a create, not a control claim, not an Anvil paste. If you need to continue a thought after a hangup, you look at the pane, you type again, or you paste a draft you can still see. The machine does not remember your fingers better than you do. It remembers output, bounded, and even that it will not call "in sync" if the prefix is incomplete.

Review the reconnect path as a list of things that must not fire. Keystroke queue, unconfirmed create, saved grant, auto-Enter on a draft, resize to the phone's new size. If any of those fire because "the user would have wanted it," you have built a model of the user that submits. The user is present, now, as a spectator. Let them want it out loud.

No input queue across a disconnect. Uncertain create is not retried. Replay paints output; it does not type. At-most-once for shells and leases, then look.

Code

What dies with the attachment, and what you do instead·text
attachment dies => drop
  outbound keystroke queue
  unconfirmed Take Control
  unconfirmed Return Control
  unconfirmed Close
  unconfirmed Create (do not retry)
  "pending" Anvil paste / Enter

attachment returns =>
  attach as spectator
  journal replay (output only, side effects off)
  browse session list to resolve uncertain create
  new asks only, in the present

# Create uncertainty
  asked, no receipt, phone died
  on return: LIST, do not CREATE again
  if new session present -> watch it
  if absent              -> operator may ask again, knowing it is new

# Illegal comfort
  offline typing buffer that flushes into the PTY
  at-least-once create
  "replay the last five keys, they probably still apply"

External links

Exercise

A phone asked to create a new seat, died before the receipt, and comes back five minutes later. Write what the session list might show in two branches (create landed / create did not). For each branch, write the one act you are allowed, and the one act you are not. Then add a third line: five queued letters from before the drop — where do they go? (Hint: nowhere in the PTY.)
Hint
Allowed acts are browse and a new, conscious create. Forbidden is retry-as-the-same-create. The five letters belong in a draft or in the bit bucket, never in a flush.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.