Context
The Crate Works drafts use ordinary PLATE and GATE nouns linked by a small
visible channel palette. A plate is pressed while another entity occupies its
cell. A gate is traversable when its channel has a pressed plate, or while
another entity occupies the gate cell after contacts. The latter is a jam, not
hidden history: every settled gate state is recomputed from the current board.
The current engine plans movement through planAutomatonMove(), treats all
objects in a cell as contacts, and resolves SINK/DEFEAT before final victory.
The gate contract must use the prior settled gate projection while planning a
turn, then recompute after contacts. This makes pressing a plate take effect on
the next turn and lets a presser destroyed by SINK or DEFEAT release its plate
on the same turn.
Goals and non-goals
Goals
- Make channels data-only and stable across noun transformations.
- Keep circuit membership determined by the current noun, with no remembered open bit that can disagree with the visible board.
- Make anything except the plate entity itself a valid presser.
- Make closed gates stop movement regardless of current rule properties.
- Preserve behavior through snapshots, Undo, reset, restore, sharing, and the compact solver transition boundary.
- Provide bounded settled events for design-owned animation and audio.
Non-goals
- Edge-triggered switches or toggles.
- Gate crushing, damage, or automatic destruction of occupants.
- A new grammar such as
PLATE IS SWITCHorGATE IS SHUT. - Arbitrary channel names or channel colors supplied by a mod.
- Deciding the separate FRAIL/crumbling mechanic.
Decisions
Channel metadata stays with the authored entity ID
An authored object may declare channel using one of the host's fixed channel
tokens. The normalized object retains that field through reset, restore, noun
transformation, CommonJS export, catalog installation, and data-only sharing.
The current noun controls participation: an entity participates as a plate only
while its noun is PLATE, and as a gate only while its noun is GATE.
When GATE IS CRATE transforms a gate, it becomes an ordinary CRATE, leaves
the circuit, and has no remembered open state. If a later rule transforms it
back to GATE, it rejoins using its authored channel and recomputes its state at
the end of that turn from the current plate and gate occupancy.
Pressure is occupancy, not entry
At the post-contact settled boundary, a plate is pressed when at least one other surviving entity occupies its cell. Words count, regardless of their properties. The plate entity itself does not press itself. A plate can therefore be pressed by a non-PUSH YOU object, a pushed word, or an automaton actor.
For each active gate, openness is recomputed as:
pressed(channel) || occupiedByOther(gate cell)
The occupancy term is the jam rule. It prevents crushing and keeps a gate open until the cell is empty. There is no persistent gate bit whose value can differ from this settled projection.
Movement reads the prior settled projection
Before player or automaton movement, the engine derives gate blockers from the
prior settled state. A closed active gate rejects entry as an unconditional
STOP, regardless of GATE properties or other rule predicates. An open gate
has no movement property. Gate changes never occur mid-turn, so pressing a
plate does not permit crossing the gate during that same turn.
After movement, rule transforms, automata, and SINK/DEFEAT contacts complete, the engine recomputes active plates and gates. A destroyed presser therefore releases its plate on that turn. A gate transformed away is removed from the projection; if transformed back, its state is recomputed from the final cells.
Events describe settled changes
Settled results add these bounded arrays when a value changes:
gateChanged: [{ id, open, jammed }]
plateChanged: [{ id, pressed }]
jammed is true when the gate is open because another surviving entity occupies
its cell while no channel plate is pressed. An active/inactive noun transition
may emit a false/closed change for the prior circuit member so presentation can
remove its state marker. Event records use stable authored IDs and are cloned
before returning to callers.
Channel markers are neutral shape data
The host maps its fixed channels to neutral shape markers such as ▲, ●,
■, and ◆. They are drawn in the foreground color and do not use property
colors; a pink or blue gate would be read as DEFEAT or SINK. The renderer may
show the marker on plates and gates and list the channel in the ledger, but
shape mapping is presentation data derived from the validated channel token.
Solver identity remains memoryless
Channel is static authored metadata and current gate openness is derived from
the settled object state. The solver codec must not add a hidden mutable open
bit to the search key. Instead, the gate mechanic registry declares its
deterministic derived projection and the codec fails if an implementation tries
to introduce an unregistered dynamic gate field. Public step() and the fast
solver transition must derive the same prior projection and produce the same
post-contact events.
Risks and mitigations
- A gate is treated as a normal STOP object. Keep gate blocking in the movement mechanic boundary so rule precedence cannot reopen a closed gate.
- A presser disappears during contacts. Recompute only after contacts and add a SINK/DEFEAT release fixture.
- A transformed gate retains stale state. Derive participation from noun every turn and clear inactive projection entries.
- The solver encodes derived state inconsistently. Add same-board parity tests and reject unregistered mutable mechanic fields.
- Channel colors imply properties. Keep shape markers neutral and test the presentation payload separately from property palette colors.
- Adjacent plate and gate trivialize a level. Keep the content warning in world authoring and validate only structural channel consistency here.
Migration and rollback
- Add channel metadata validation and data-boundary round trips.
- Add prior-settled gate blocking and post-contact recomputation.
- Add events, reset/Undo/restore, and public/fast parity fixtures.
- Add the D1–D3 and transformed-gate proofs to Crate Works after solver acceptance and design review.
Rollback removes the gate mechanic registration and leaves ordinary objects, rules, and levels valid. A level using channel metadata must not be bundled until the host feature is available.
Open questions
- Should an active gate or plate with no matching channel partner be a load warning, a validation error, or an allowed inert circuit?
- If a gate is destroyed rather than transformed, should the event include an
inactive
gateChangedrecord or only the existing destruction record? - If multiple entities enter and leave the same gate cell during one accepted turn, is final post-contact occupancy the sole jam evidence? The current proposal assumes yes.
- Should channel tokens be exposed in pack vocabulary or remain metadata-only?