Build a rule. Write a test that can catch it.

Old input.
New consequences.

Implement an admission policy and write an HTTP test that detects a broken one. Keep legal retries working. Your code runs in a real local server; your test sends the same requests as the browser.

Owned teaching project · protocol robustness and false-positive control · workstation required to edit and execute; phone reading supported

01 / WHAT CROSSES THE BOUNDARY?

A request proposes an intention.

A process is a running program with its own state. The browser and Node server run separately. Changing a browser variable does not directly change the server's cargo. A request is a message crossing that boundary. The server decides which message affects its state.

Clientdirection + interaction
HTTPparse four fields
Admissionnewer sequence?
Tickmove, then interact
Stateserver position + cargo

A sequence number orders this session's inputs; it is not a timestamp. The server accepts a number greater than the last admitted number. A repeated or older number is stale: it must change nothing. Numbers may have gaps.

A tick is one 50 ms simulation step. An intention admitted at tick T stays active through T+4. At T+5 it expires. A fresh intention replaces the direction and renews that lifetime. Sending more requests cannot buy extra steps within one tick.

02 / WORKED TRACE

Acceptance and application are different decisions.

This example begins at (1000,1000). East adds 250 mm to x per active tick. It is a worked example, not a scored prediction.

TickRequest / stepConsequence
T0seq 10, east; no interactionAdmitted. Expiry is T4.
T1–T2Two server ticksx=1500, y=1000.
T2seq 9, west; interactionStale. Direction, expiry and pending interaction stay unchanged.
T3–T4Two more ticksx=2000. No interaction was staged.
T5No fresh inputx stays 2000. No catch-up movement.

Now imagine the client lost the response to seq10 and sent it again. The retry is stale, but that says nothing about the player's intent. Counting every retry as cheating would punish a normal recovery path.

03 / YOUR TWO ARTIFACTS

Implement the policy. Author the scenario.

From the reference project directory:

npm run order:prepare

Change into the printed artifacts/order-workspace directory. Read lab/order/LEARNER.md. Record your predictions in response.md before editing. The prepared copy contains an incomplete policy and scenario; the author solution and judging fixtures stay outside it.

  1. admission.mjs exports admitInput(state,input,tick) and movementActive(state,tick). Implement strictly newer admission, unchanged stale state, T+4 expiry, latest direction and coalesced interaction. Leave the engine's movement, score, parser and clock alone.
  2. learner-scenario.mjs exports async scenario({base,advance}). Use supplied HTTP helpers and ordinary assertions. Send a newer direction, then an older conflicting input, advance the owner test clock, and inspect authoritative state. Also test expiry, same-tick renewal, duplicate retry and state polling. At least one test must catch a wrong state even if the response text looks plausible.

The bounded advance function belongs to your owner-side test harness. A gameplay client receives no such capability. The server has no HTTP time-control route.

npm run order:check -- --assistance "none"

Use an accurate help declaration, such as “read the worked reference” or “used an AI hint.” The command records the submitted files, response, prompt version, seeds, help, runtime identities and actual results. Each revision gets a new attempt; earlier attempts stay intact.

BEFORE THE INDEPENDENT SCENARIO

Turn a returned value into an assertion.

An assertion compares an observed value with a contract. The prepared guide includes a complete M1 remote-pickup example, then a missing-assertion exercise. It introduces async, await and the arrange → act → observe → assert sequence. Complete that practice before writing ordering tests. Waiting for HTTP does not advance the owner clock, and HTTP 200 does not prove a gameplay effect succeeded.

04 / A PASS MUST DISCRIMINATE

“It ran” is a weak test.

The checker evaluates your two artifacts independently. Trusted fixtures test your policy. Your scenario runs against two correct implementations and deliberately wrong implementations. An empty scenario misses defects. A scenario that always throws rejects correct code. Neither passes.

Your policy

Must preserve legal state under the declared schedules, including ordinary retries and button re-presses.

Your scenario

Must accept both correct implementations and catch the specified wrong states. A crash or timeout is a broken run, not a detected guard defect.

Expect separate results for duplicate admission, stale interaction, early/late expiry, reads renewing intent and retries being counted as findings. Inspect the first failed criterion and its observed/expected state, then repair the relevant artifact. Keep the raw output for investigation.

A local workspace is under its owner's control. This checker helps you preserve and examine your work; it is not a tamper-proof credential or a sandbox for hostile code.

05 / TRANSFER THE REASONING

Explain what the evidence leaves open.

Complete response.md with the original predictions and later repairs. Explain why a stale input must not stage an interaction, why a state read must not renew movement, and why a human re-press can be a false positive for a naive detector.

Then consider an owned replay scrubber receiving {seq, frame} seek commands. Transfer newer-command admission and read-only observation to it, and explain why a four-tick movement lifetime does not automatically apply. Give one stale-command test and one read-only polling test. This written transfer needs review; the checker does not mark your prose correct.

In this instanced courier game, sequence and expiry enforce control semantics. They do not yet prevent a timed score advantage. Server-owned pickup and score still prevent unearned state. Keep those claims separate.

Reading pointers

The lesson and exercises are original. For systems context, see Stewart N. Weiss, System Programming in Linux: Chapter 1 “Processes,” Chapter 12 “Why Do We Need IPC?” and Chapter 14 “Introduction to Client-Server Applications.” The Linux examples are context, not setup instructions for this Node lab.

For the actual runtime APIs, use the official Node child-process and HTTP documentation. A Node child-process fork is not the Unix C fork interface. No kernel installation or OS-security change is required.

Return to the live Courier Lab →