# HANDSHAKE — review, October 2026

A full pass over the game: every line of the engine and all fourteen hops read, a
lint for undefined names, then every hop **driven to its exit** in the browser with
the game's own physics, rather than loaded and checked for console errors. That
difference is the headline. All fourteen now reach `ctx.next()`, and the ending loops
back to hop 1.

## The headline

The game could not be finished. Five hops had a defect that stopped a fair player,
and the ending itself was unreachable:

| hop | what stopped you |
|---|---|
| 1 · cold boot | The DMA wanted you within 3.2 m of a pointer that runs on the ring; you wake 4 m inside it. Stand and wait for the thing the game says is coming, and it never comes. |
| 2 · the stack | Every floor's miss floor sat between its exit and the next floor, so you landed on your own catch floor and respawned on the gate; standing on a gate re-fired the advance every 3.2 s, skipping floors at a TTL each and, on the last floor, draining TTL forever. About a third of the jumps were longer than anyone can jump. The reorder floor needed a 3 m upward jump. The firewall was underneath it all. |
| 17 · smash | The canary value sat 2.6 m up against a 2.3 m jump (1 attempt in 24 got it, through a collision quirk). The NOP sled started 5.6 m above the floor. NX made the tile under you intangible and the respawn dropped you back through the sled once a second (TTL 12 → −5 in twenty seconds). The ret2libc gadgets hung 30 m apart with nothing between them. |
| 21 · the worm | Press K, as the game tells you to, and the cure takes ~50 of 60 hosts, the worm starves, and the level never ends. |
| 63 · the climb | `modern()` read an undefined variable on the first frame of the Spectre split. The error handler then disabled the level's update for the session. **Nobody could reach hop 64.** |

Why this went unseen: every earlier check loaded each hop, ran a few hundred frames,
and looked for console errors. That catches crashes on load. It cannot catch a level
you cannot finish, and it never ran the climb far enough to reach Spectre. I saw the
climb freeze once, in August, and wrote it off as the test harness. It was the game.

## What was fixed

All verified by playing it, not by reading it:

- **The stack**: rebuilt. The gate is a hole that opens under you, and you drop onto a
  landing pad on the next floor. Floors are generated as a walk from where you land,
  checked against the player's real jump physics (`reach()`/`canJump()`), and rerolled
  until crossable. The routing budget is the cheapest route plus one. Reorder is seven
  solid segments around a hub: early segments are *buffered*, the hub opens when the
  stream is whole, which is also what TCP does. Verified: every hop on every floor with
  the real `Body`, plus a full descent at exactly 6 TTL for 6 hops.
- **Smash**: reachable ledge; writing the fourth byte makes the function *return*, so
  you are carried onto the sled (the real mechanism, and now the only way on); NX
  kills the sled but leaves the shellcode standing; the gadgets are one crossable shelf
  with decoys to jump over; a segfault returns you to the last safe ground. Verified
  end to end.
- **The worm**: each copy of the fix has its own TTL of four hops; the ending counts
  what the worm can still reach, and twenty seconds of stillness also ends it.
  Verified: every strategy ends in 44–54 s; the most you can save is 15.
- **Cold boot**: the DMA is an angle, swept anywhere in the ring band, and after two
  laps it takes you from wherever you are.
- **The climb**: the undefined variable. Verified: runs through Spectre to root,
  through the ending, and loops back to hop 1.
- **Time wait**: the exit was any point past x = 12.4 inside a 30 m room. Walk at the
  EXIT sign and the level ended before you spoke to anyone. Now it's the doorway, once
  FIN has opened it.
- **The copper**: the duct's walls ran straight through the switching hall, so the MDF,
  the call you're meant to follow, and the Strowger plaque were unreachable.
- **The cuckoo's egg**: `clean` made you strictly worse off (24 lines → 10). Now it
  buys cover. Absolute paths work.
- **The handshake**: on a bad line the carrier swung outside where you can steer, and
  losing it cost 99 TTL and all five tones again. Now the channel stays within reach
  and losing it re-runs the ride for 2 TTL.
- **Retrain** stole SPACE from the blue box, the climb and every jump, and only counted
  presses *after* the beat. Now it's opt-in (only the copper, which has no jump) and
  measured to the nearer reversal.
- **The board**: ~75 words of *The Conscience of a Hacker* were reproduced verbatim,
  contradicting the model card; now it's a user's post that quotes six words. The ANSI
  bomb did nothing in a terminal; it now swaps your typing. "Hang up without saying
  goodbye" was a secret that didn't exist, and the ending claimed you'd done it if you
  had merely read about it. `+++` at the prompt now does it.
- **Rendering**: the Spectre split screen was wrong on every Retina display (three's
  `setViewport` writes the screen viewport × pixel ratio even with a render target
  bound): 2× left eye, then the whole picture shrunk into a corner for the rest of the
  game. Verified by logging every `gl.viewport` call at dpr 2.
- **Saves**: any key but R, or any click (including the "what this is" link), started
  a new game and wiped the save.
- **Terminals**: swallowed Cmd/Ctrl shortcuts; a keypress during a paint cut the text
  off (now it finishes instantly); redrew 2,000 glyphs every frame (now only on change);
  sat at 1× on most laptop windows (now scales in quarter steps).
- Smaller: the blue-box conference kept talking over later levels; the loop counter
  always said round 2; war's hint named a key that does nothing; the firewall charged a
  TTL every few frames you pushed against it (13 in 6 s); one exception froze a level
  for the session; card timers could close a newer card; `.claude/` was being published.

Also added: a **sound control** in the corner (full / half / off, remembered). There
was no way to turn this game down, and it is mostly oscillators at real telephone
frequencies. It's a button rather than a key so it works inside the terminals.

`deploy.sh` now pins every module to the commit, because Cloudflare holds JS for four
hours and a returning player could otherwise get half a release.

## What I did not change: decisions for you

1. **Dying refills TTL.** `expire()` restores TTL to the hop line (max(12, 65 − hop)),
   so a player on TTL 3 who dies comes back with 20. That's a heal, and it contradicts
   the card's "TTL only goes down… no healing, ever". It's also the only thing stopping
   a soft-lock when someone arrives at a level with less TTL than the level costs. The
   honest version is a checkpoint: restore the TTL you *arrived* with, floored at what
   the level needs. That's a balance change, so it's your call.
2. **The hop counter** only advances inside the stack. Every other multi-hop level shows
   its first hop throughout (the board says 35 for all ten hops).
3. **Accessibility** is still as the card says: no colourblind mode, no remapping, no
   subtitles for the non-speech cues. (There is now a sound control: see below.)
4. **The `` ` `` hop select** is advertised on the boot screen. It lets anyone skip
   anything, and it's also the only escape hatch for someone who can't hear the ANSam
   beat. I'd keep it.
5. **CHECKSUM** multiplayer still needs a server and your yes.
6. Nobody but me has played this. Playtesting with strangers is now actually possible,
   because the game can be finished.

## How to test a hop from now on

`HS.link.render = () => {}` turns rendering off; `HS.run(n)` then steps the logic at a
few thousand frames a second. Drive the level to its `ctx.next()`. A sweep that loads
each hop and watches the console is a smoke test, not a test.

## Depth pass (October 2026), what changed in play

Five hops were "watch the history happen". Each got one decision the player owns
(see [DESIGN-DEPTH.md](DESIGN-DEPTH.md)); all verified by driving them headless.

- **The worm** is one control: how hard you push. The 1-in-7 is on screen, locked, and
  lights up each time it fires. Hosts you hit gently get cleaned before they fail; hosts
  you hit hard fail before anyone can. Three endings, and the card says which you had.
- **The cuckoo's egg**: he is on one account and you can read what he is waiting for.
  `su` (after reading the passwd file) buys time; the last file needs the right account.
- **The copper**: cross a jumper at the frame and a stranger picks up instead.
- **The blue box** asks for more each route; the last one is done by ear.
- **Spectre**: the answer exists only in the branch that gets thrown away. This also
  fixed an old bug, in that the cache door sat 20 m *before* the branch resolved, so it
  always bounced, and the whole branch lasted about 1.4 s at climb speed. It is slowed
  down to ~7 s now.
- **The climb reads your save**: a fast line shows you the ANSam flip coming; the
  Strowger, Morris and netsplit philes slow or telegraph their gates. The card at the top
  says how many were easier for what you carried.
