Lane
One execution lane: a tick source (a game method a Mixin injects at RETURN — the "heartbeat") whose every fire steps the lane's active evals once, on that source's own thread, so a step has exclusive access to that side's game state. Three lanes exist (Lanes): server (server tick), client (client tick), render (render frame) — identical machinery, different heartbeat.
Readiness is asked, never timed: a LiveProbe answers from the physical side and from the tick source itself, so a stall is not death — a paused game, an autosave or a slow /tick rate stays ready — and a source that really has stopped says so at once, with no window in which a submission can join a queue nothing will pump again. A remote-connected client has no local MinecraftServer, so its server lane is simply not ready.
An eval is reaped for exactly ONE reason: its heartbeat will never fire again, which would hang the caller blocked on its future. A world unload, a dimension change, a server switch all leave the heartbeat firing, so the eval keeps stepping and ends on its own terms — finish, throw, watchdog, or cancel. That one boundary can't be seen by the stopped pump itself, so it arrives from outside as reapOnStop (MinecraftServer#stopServer; onDisable on Paper). Client and render have none short of JVM exit.
Properties
Advanced only by reapOnStop; offerOrReap compares against it to kill a straggler still compiling when the heartbeat stopped for good.
What the last heartbeat handed in — the MinecraftServer on the server lane, the Minecraft on client/render; null before the first pump. Republished every pump because isReady and run_command read it from the HTTP thread, and both must get a current value on an idle lane too.
Functions
Which timeout kill-id lane this is: the server lane runs on the Server thread; the client and render lanes share the Render thread → RENDER. Known from the lane name at submit time, so it's baked into the script's inlined GETSTATIC at compile/instrument time (no runtime thread sniffing).
Every route into active: the compile-completion handoff on the short-lived compile thread once EvalTask.start finishes compiling, and stepAll's flush of an eval it stepped but didn't finish. Publish the task into active, then re-read the epoch it was bound to at submit. Epoch unchanged: it waits for the next pump. Epoch advanced while it was compiling: it's stale, so pull it back out and kill it here, completing its future — otherwise the blocked caller hangs on a queue that will never be pumped again.
Pump the lane once per heartbeat fire — called by the lane's Mixin (MixinMinecraftServer / MixinMinecraft) at the tick's RETURN, on that side's own thread. Republishes self as the lane's handle, then steps each active eval once. Public so the mixin (a different package) can call it.
Kill and drop every active eval. Safe from any thread: drains concurrent queues; kill is idempotent. Two callers: an auth revoke (on the pump thread, which keeps pumping and so self-heals any straggler still compiling), and reapOnStop.
The lane's one terminal boundary, signaled from outside the pump: MinecraftServer#stopServer (Paper: onDisable). Past it the heartbeat never fires again, so every queued eval would hang the request blocked on it — including one still compiling, which will offerOrReap itself into the queue a moment later. Advance the epoch before draining — see offerOrReap for why that pairing strands nothing. Server thread only, and the sole writer of currentEpoch.
Step every queued eval once, in order, under ONE timeout budget for this tick: they run serially on this one tick thread, so their combined time is what would freeze it. The guard inlined into each script reads this lane's kill-id field, which beginFrame's watchdog writes when the budget elapses (see TimeoutGuard). Drains to empty, so an eval that finishes compiling mid-pump runs this tick instead of waiting out a heartbeat.
Schedule code on this lane. It compiles off the tick, joins the lane once compiled, and is stepped every heartbeat until done. It's bound to the epoch current at submit: if the heartbeat has stopped for good by the time it finishes compiling, it's killed rather than queued forever. The returned EvalHandle carries the result future (callers block on it — block-until-done) and can cancel the eval (the client-initiated notifications/cancelled path).