src/concept.ts now names three readings a mote has — swimming, scattered, beached — and says of the third, in its own comment: beached is not on the wire at all, and a door reads it from where the mote is. Three doors are queued to do exactly that: the canvas (#10), the SVG still (#55) and the terminal (#63). Each will pick its own "close enough to the rim", and AGENTS.md names that failure by hand: a rule outside the one place it belongs is a bug waiting for the door you forgot.
It is also not derivable from position alone. rim() in src/world.ts clamps a slow arrival to the wall and keeps what runs along it, so a mote sliding down the rim at speed looks identical, by radius, to one sitting against it — and the record says those are different things: beaching costs you the push into the wall and nothing else, scattering costs three seconds. A door guessing from radius will label a swimmer beached in front of the player who is currently overtaking them.
Done looks like
[ ] The state is decided in one place and written down: either a MOTE_BEACHED bit beside MOTE_STUNNED in src/protocol.ts's flags word, or one exported predicate every door calls. The pull argues which and why; a bit on a word that already exists costs nothing and is the obvious default.
[ ] src/world.ts says when a body is beached, in rim() where the rule already lives — the tick it was stopped by the rim and stayed stopped, not "its radius is large".
[ ] Whatever is chosen, docs/wake.md's look section stops saying a door reads it from where the mote is, and src/concept.ts's comment goes with it.
[ ] The protocol's version is considered out loud: a new flag bit on an existing word is backward compatible, and the pull says so rather than bumping PROTOCOL_VERSION out of caution or forgetting to.
[ ] Tests: a mote driven slowly into the rim reads beached and not stunned; one driven in above SCATTER_SPEED reads stunned and not beached; a mote sliding along the rim under thrust reads neither; the state clears on the tick the mote leaves the rim; and the flag survives encodeFrame/decodeFrame.
Filessrc/protocol.ts, src/world.ts, src/concept.ts, docs/wake.md, and the tests beside each.
Risks This is a small change to files three open issues are about to build on — take it before #55, #63 and #66 rather than after, and keep it to the one state. The temptation is to put every reading a door might want on the wire; the frame is a budget (#44) and every bit spent here is bytes a phone pays for ten times a second.
Fits Vesper's brief: the state, in the module that owns the rule.
src/concept.tsnow names three readings a mote has — swimming, scattered, beached — and says of the third, in its own comment:beachedis not on the wire at all, and a door reads it from where the mote is. Three doors are queued to do exactly that: the canvas (#10), the SVG still (#55) and the terminal (#63). Each will pick its own "close enough to the rim", andAGENTS.mdnames that failure by hand: a rule outside the one place it belongs is a bug waiting for the door you forgot.It is also not derivable from position alone.
rim()insrc/world.tsclamps a slow arrival to the wall and keeps what runs along it, so a mote sliding down the rim at speed looks identical, by radius, to one sitting against it — and the record says those are different things: beaching costs you the push into the wall and nothing else, scattering costs three seconds. A door guessing from radius will label a swimmer beached in front of the player who is currently overtaking them.Done looks like
MOTE_BEACHEDbit besideMOTE_STUNNEDinsrc/protocol.ts's flags word, or one exported predicate every door calls. The pull argues which and why; a bit on a word that already exists costs nothing and is the obvious default.src/world.tssays when a body is beached, inrim()where the rule already lives — the tick it was stopped by the rim and stayed stopped, not "its radius is large".docs/wake.md's look section stops saying a door reads it from where the mote is, andsrc/concept.ts's comment goes with it.PROTOCOL_VERSIONout of caution or forgetting to.SCATTER_SPEEDreads stunned and not beached; a mote sliding along the rim under thrust reads neither; the state clears on the tick the mote leaves the rim; and the flag survivesencodeFrame/decodeFrame.Files
src/protocol.ts,src/world.ts,src/concept.ts,docs/wake.md, and the tests beside each.Risks This is a small change to files three open issues are about to build on — take it before #55, #63 and #66 rather than after, and keep it to the one state. The temptation is to put every reading a door might want on the wire; the frame is a budget (#44) and every bit spent here is bytes a phone pays for ten times a second.
Fits Vesper's brief: the state, in the module that owns the rule.