Spawn
playmakespawnjam
⌘K
visitorclaim namesign in
sign up
playmake
spawn / aboutwhat we're building

pinned

start herewhat spawn isfaqfrequently asked questionsthe betthe spawn bet

updates

engine v6.0One PlaceSep 5, 2026engine v5.2LumeJul 10, 2026engine v5.1ConnectionJun 18, 2026engine v5.0For RealJun 4, 2026engine v4.6AtelierJun 1, 2026engine v4.5Surface TensionMay 22, 2026engine v4.4SolidMay 15, 2026engine v4.3GroovyMay 13, 2026engine v4.2ContinuumMay 9, 2026engine v4.1FoundationsMay 4, 2026engine v0.1GenesisApr 29, 2026

pinned

what spawn isstart herefrequently asked questionsfaqthe spawn betthe bet

updates

One Placeengine v6.06d agoLumeengine v5.22mo agoConnectionengine v5.12mo agoFor Realengine v5.03mo agoAtelierengine v4.63mo agoSurface Tensionengine v4.53mo agoSolidengine v4.43mo agoGroovyengine v4.34mo agoContinuumengine v4.24mo agoFoundationsengine v4.14mo agoGenesisengine v0.14mo ago
← All posts
← All posts

engine v5.2.41

Engine v5.2.41

September 11, 2026

A patch in the Lume line.

Everything timed in seconds now lasts the time you wrote (shake, fades, zoom and sprite frame rates ran up to 1.75x fast before), a click in god mode no longer resizes a shape, textures on small primitives and on phones draw the right way up, a campfire no longer shrinks every other particle on screen, a floor Savi swaps for a model stays solid until the model is ready, characters report their wall and floor touches, big worlds finish loading their textures on a slow connection, star and moon fades no longer stutter, the bug-report button no longer freezes the game, a player whose tab died no longer leaves a ghost behind, and multiplayer physics runs only where someone is.

what's new

  • When a script writes a very large value to another player's object and then a small one in the same step, only the large write now fails, and the message names that write. Before, the small write failed too and the message said it was the one that was too big.
  • A player or NPC character now reports its collisions properly: walking into a wall fires the collision once, with the contact point and the wall's facing; landing on the floor fires once when you land; touching the same thing again fires again. Before, wall hits arrived late and empty or not at all, and standing still on the floor fired at random moments.
  • In god mode, clicking on a shape no longer changes its size. Before, a click near the edge of a cube's face could squash or stretch the cube, and two clicks could flatten it to a slab. A click now only selects; you have to drag to resize.
  • When the game gives up on a bad connection mid-stream, it now drops the rest of that stream at once instead of logging a burst of extra reconnect errors first.
  • Switching tabs while a game loads no longer makes its saved data come up empty when you come back. Before, a tab left in the background could return to a game whose scores and saves had not loaded.
  • On a computer that struggles to keep up, the game's color grade no longer flickers on and off. Before, the engine would switch the grade off to lighten the load on that machine and then switch it back on a moment later — sometimes because it had decided the grade was not the cause, and sometimes by mistake, right after the switch-off had actually helped — and then repeat the cycle, so the whole screen kept changing color while you stood still. Now, when switching the grade off helps, it stays off on that machine until you or Savi change the look; when it does not help, the engine switches it back on once and leaves it alone.
  • Switching tabs for a while no longer makes a game's AI-powered characters fail to answer when you come back. Before, a character that asked for its next line while you were away could come back with a "timed out" error even though the answer had arrived.
  • A vehicle you are driving (or any object a script has moved) no longer jumps back to where it was placed in the editor when a change to the ground is saved — a new road, a flattened pad, a terrain script edit. Before, saving any of those put every moved object back on its original spot, with the driver still inside.
  • When a texture is downloading unusually slowly, or is waiting its turn behind many other texture downloads for a long time, the engine now says so once in the game's logs instead of staying silent — nothing in the game needs changing when you see it. A texture that nothing in the world is asking for any more no longer takes a download turn ahead of one that is.
  • On a slow connection, big worlds now finish loading their textures instead of getting stuck. Before, a texture that was still downloading after 30 seconds was thrown away and requested again from scratch, over and over, so on a busy line some floors, walls and effects never got their real look — walls whose texture never arrived did not appear at all. Now a download that is still moving is left alone until it finishes, textures are requested a few at a time in the order the world asked for them, and they go ahead of the much larger 3D model downloads on the line, so surfaces get their real look early in the load instead of at the end.
  • When your game's image generation hits its rate limit, Savi now hears that it is a limit — not a broken texture — and when it lifts, textures load without an extra stalled retry.
  • Resizing or adding a rectangular flattened pad and then saving no longer makes every scattered tree and bush in the world blink out and grow back. Before, a saved pad could re-plant the whole world for a moment.
  • Saving a script no longer makes the trees and bushes in your world blink out and grow back for everyone connected. Before, some saves made the engine rebuild the whole ground and re-plant every scattered tree even though nothing about the terrain had changed.
  • Fading the stars or the moon over time — brighter stars as dusk deepens, a milky way that comes up slowly, a moon that dims toward dawn — no longer stutters. Before, a slow fade could hitch every couple of seconds. The night looks the same at every step; it only gets there smoothly.
  • A fast object no longer reports hitting the ground while still in the air at a terrain edge. Before, a plane or a thrown ball crossing between stretches of ground could get a "hit the ground" event metres up, with no contact point, and scripts that crashed or exploded on it fired for nothing. Real landings still report where and how hard.
  • When you delete the last thing that used an animation clip, the clip leaves your game's saved data too; if you use it again later, it comes back. Before, clips from a deleted cinematic stayed in the game forever.
  • A script that runs away in a multiplayer room is now paused for 10 seconds and then resumes on its own, the same as in a singleplayer game, so the room stays smooth for everyone.
  • When Savi looks at your game, she now sees the images in your game's HTML — icons, portraits, fighter cards, background plates — the same way players do. Before, an image loaded from your uploads showed on screen but was blank in her view, so she could send you hunting for a bug that was never there.
  • A comment's automatic screenshot now shows the images in a menu, shop or dialogue that was open when the comment was left, instead of empty boxes where they stood.
  • While you are building, clicking a creator tab's panel — its title, a label, the space between controls — no longer also clicks the world behind the panel. Before, that click could select, place or paint something you never aimed at.
  • A creator tab that builds its own panel (a drag-and-drop editor, a floating window) now looks right the first time you open it in a session. Before, the first open of such a tab in a fresh session showed plain unstyled text in the top-left corner until you opened any other tab once.
  • When a shape you generated is invisible for one player because their copy came out different from the saved one, Savi can now read the reason from the game's own log and tell you what differs, instead of only being able to say it didn't match.
  • When Savi rebuilds a room's shell in one edit — replacing a floor made of simple blocks with a 3D model that carries its own collision shape — the old floor now stays solid under anyone standing on it until the model's collision shape is ready, then hands over. Before, the floor vanished the instant the edit landed and players standing there fell through the world while the model was still loading. If a model's collision shape never arrives, the old floor lets go after fifteen seconds.
  • When you remove a behavior from an object, or edit its script, the old script's event handlers now stop everywhere, including on players' tabs that were not running the object at that moment. Before, an object whose behavior you had removed could still react to events after another player left the room, and an edited object could react twice to each event until you saved again.
  • If you edit a script while another player is running the room and the room later comes back to you, an object's event handlers from that script can be quiet until you save the script once more. Savi now sees exactly that in the logs and can tell you to save again, instead of telling you to restructure a script that was already right.
  • Objects a place creates in your first moment inside it now appear — for you and for everyone else in the room. Before, when you arrived in a freshly made place, those first objects could be dropped, or exist only on your own screen.
  • A campfire's smoke column no longer makes the whole game's particles shrink. Effects are now measured by how much of the screen they really cover, from the particles actually drawn, instead of assuming every puff is at its largest size.
  • Custom-shaped objects that a busy scene left solid but invisible for a player — you could bump into a bench you could not see — now come back on their own once the scene gets lighter, and keep retrying on a slow schedule until they do, instead of staying invisible until the page is reloaded.
  • A model whose download is cut by the network partway through is now retried instead of being reported as a file that cannot be read.
  • When a model's size can't be read, Savi no longer calls the file broken or asks you to re-add it. She says what happened and what comes next: the size is read again when the game next loads, or when the model is replaced. A file over the platform's size limit is told so, without a guessed number.
  • When a model file cannot be read, the message now tells the true case apart: a file that is really over the platform's size limit says so and how far over it is; a file whose header does not describe its contents says that instead of asking for a smaller export; a file that ends early says it ends early. Each message ends with the one thing to do next — a smaller export for a file over the limit, a re-export and a replaced model ref for the others.
  • A character you export from Blender with many animations baked in now loads with its size known; before, a file with a large set of animations could be reported as "malformed" even though it was fine, and physics and decoration around it used default sizes for the rest of the session. A model's size is read from the file the platform actually serves: a file over the platform's model limit is told so, and a file whose header does not match its bytes is told to re-export.
  • An object whose shape follows the ground, if it is created a moment before its place's terrain is ready, now waits and builds against the real ground once the terrain is there, instead of building flat. While it waits it is not drawn, and the logs Savi reads say which object is waiting on which place's terrain.
  • If your game tab was in the background for a long while in a busy room, it no longer takes over running the room the moment it comes back — it first catches up on everything it missed, so nobody's world gets reset to what your tab last saw.
  • Savi no longer reports an object missing just because the screen she asked was behind the room — her eye now knows when the tab it asked has not caught up yet.
  • Weak laptops no longer get extra shadow work they were not asked for.
  • When a script writes a very large or very deeply nested value to an object another player's game is running, the write now fails at once with a message in your logs that says how big the value was, what the limit is, and what to do next. Before, the value looked like it landed and then quietly vanished about five seconds later with no message.
  • When Savi looks for an object the screen she asked has not caught up to yet, she now learns that in the same look instead of asking twice.
  • A material script can now set material.color = new Color(...) (or a hex like 0xff8800, or "#ff8800") the way it works in three.js. Before, that line quietly broke the material.
  • A shape given a number it cannot draw — a size that came out as NaN, a million segments, a curve with one point — now draws with that value fixed up and tells Savi what was wrong, instead of vanishing or stalling the frame.
  • Ground decorations with an impossible size in one item keep rendering; only that value falls back to its default.
  • When a change to another player's object never gets an answer because that player's tab is in the background, Savi's log now says exactly that instead of a bare timeout.
  • When frames get slow and the engine has to switch off a custom see-through material — a glow, a haze, an atmosphere around a planet — the object no longer turns into a solid gray shape that hides everything inside it. A see-through material now simply stops drawing until frames recover (a plain translucent one shows as a translucent shape instead), so the world behind it stays visible.
  • When another player removes an object that your tab used to be in charge of, your tab no longer repeats that removal back to the room. Nothing changes on screen; the room just carries one record of the removal instead of two.
  • Pressing the bug-report button no longer freezes your game. On slower computers with a lot of art in the game, packaging the report used to stop the game for a minute or more, and the screen then said the game had crashed when it had not. The packaging now happens on the side while you keep playing.
  • In multiplayer games, physics now runs only in the areas someone is actually in (or that the game is hosting for you), so a game with many areas no longer spends time simulating the empty ones — and characters standing in an area nobody has visited no longer fall through ground that was never built. Singleplayer games keep simulating every area, as before, so moving platforms, spawners, and patrols in areas you are not in keep working while you are away.
  • When physics is slow, the performance note Savi receives now says what was actually being simulated — how many moving objects, scenery pieces, and characters, across how many areas — instead of always blaming falling props, so the advice matches your world.
  • A pond's bank is now complete all the way around. Before, at some angles the bank stopped short, and on a slope the downhill ledge ended in a straight cut — both now follow the pond's curve.
  • When Savi previews a sign on its own, the preview now shows the sign's board instead of answering that there is nothing to preview. The lettering still only appears in the game scene, and the preview says so.
  • When Savi looks at a piece of scripted geometry whose script has a loop that never ends, your game no longer freezes and the tab no longer dies. The look comes back after five seconds and tells Savi which script did not finish, so she can fix it, and everything else in the picture still renders.
  • If the game server hits an error while a player is connecting, the player's game now reconnects and joins again on its own, instead of ending up in a world where nothing ever moves.
  • When the picture has to rebuild itself after a hiccup in the connection between the game and the screen, custom-shaped objects that had settled in place — terrain pieces, decorations, meshes a script built — now come back instantly instead of vanishing for a couple of seconds and being rebuilt one by one.
  • Long rivers no longer make the terrain take many seconds to appear: a world with dozens of rivers now finishes its ground in well under a second, with every river and pond at the same water level as before.
  • A camera moved by a script now moves as smoothly as the rest of the scene. Everything timed in seconds — screen shake, camera punch, zoom, hit-stop, music and light fades, highlight pulses, sprite frame rates — now lasts the time you wrote. Before, all of these ran about one and a half times too fast for every player on every screen, up to 1.75×. A camera follow you tuned by feel may now feel a touch slower; nudge its rate up if so.
  • While Savi is building in your world and you are not in it, scripts that save game data into the world itself (with withPersistence) still change the running world, but those particular saves are not written down and will not be later. The running world keeps those changes only until it restarts or is reset from its saved version. Saves the game makes while you have it open in your own tab are written down. The engine now says exactly that in the logs Savi reads, so she can tell you plainly instead of hunting for a permission problem that does not exist.
  • When Savi swaps your game to a different starter while you are in it, the old world now clears out of your tab and the new one appears, instead of the old scene staying on screen until you reload.
  • Ground that was still being built when your connection hiccuped no longer gets thrown away and rebuilt from scratch: the engine now measures a build's waiting time by the ticks your game actually ran, so a reconnect cannot make every in-progress piece of terrain look overdue at once.
  • Top-down games that took the previous update while a room was open could keep an old wall shape in that room: walls Savi drew still let players walk through them even though the update fixed walls. Walls now take the fixed shape in every open room the moment the game runs on this version, and a wall with its own drawn outline keeps that outline. If you are on the previous update and a wall is still walk-through, ask Savi to restart the room — the room rebuilds from your last save with the fix in place.
  • Textures on primitives that used to draw upside down — small ones on desktop, all of them on phones — now draw the right way up. Textures on custom-built (scripted) shapes now draw the right way up too, on every device and at every size. If you flipped an image or a drawn texture to work around either, flip it back.
  • When a script's write to another player's object is too large or too deeply nested, the message now says that write changed nothing, instead of saying nothing changed on the object — other writes in the same step can still land.
  • When your game tab is hidden and Savi looks at your screen, she now hears that the tab is hidden and that the look works again once you bring it back — instead of a message that made it sound like the renderer was broken.
  • In a voxel world, when two flattened pads — or a pad and a road — overlap, everyone in the room now sees the same ground after a save. Before, a player who joined after the save could stand at a different height than the players who were already there.
  • When part of your voxel world sits too far above or below a player to be drawn for them — a tall planet, a very deep canyon — the game now leaves Savi a note saying exactly which ground did not draw and that nothing in the world changed, so she can tell you what you are seeing instead of hunting for a bug.
  • When a player reconnects to a busy room, another player who is still in the room can no longer vanish from their screen. Leftover objects that were removed while nobody was around now stay gone for everyone who joins later, instead of coming back each time.
›technical notes
  • A basis leaf over the per-intent value wall is thinned out of the basis sender-side, so the wall's refusal always describes the write, never a value the writer only observed (ledger 3100 fix-forward). recordTrackedStateRead and the two own-write adopters record every primitive leaf a cross-writer script reads on the target, and the adjudicator's parseBasis measures each basis value against the same 64 KiB wall as the set value — so a script that wrote a 70 KiB string and then hp = 1 to another player's object in one invocation had BOTH writes refused value_too_large, and the writer's ring said the one-byte write "carries 71,680 bytes … write less into it". intent-context's one basis door (upsertRead) now drops a leaf whose measured bytes exceed MAX_INTENT_VALUE_BYTES — the module header's own rule (a thinner basis is a more permissive guard, never a correctness loss; the 16-entry cap's class). The cost is that leaf's stale-basis protection: a write premised on it is no longer refused basis_mismatch when that leaf changed under the writer. The adjudicator keeps measuring basis values as a forge guard. Also: the folded multi-write row names the LARGEST measurement in the episode ("the largest carries N bytes" / "the deepest carries …") instead of "each carries" the first; and the seat that refuses an intent at the wall emits one relay.intent_value_wall structured line (author, code, measured, cap, targetId) — the instrument that says how often honest rooms reach the wall.
  • A physics: "character" body's onCollide touches on rapier now come from its own character controller (ledger 3082; the character residue of ledger 3076). A character is a rapier KinematicCharacterController holding its capsule offset (1 cm by default) off every surface it presses, and rapier's contact prediction reaches 2 mm, so the narrow-phase pair a pressing character forms with a static wall almost never carries a manifold point — under the manifold-only touch rule (#14366) it got one late { impulse: 0 } event before that landing and nothing after it, while tome/types.ts says onCollide works across dynamic/kinematic/static. The controller itself measured every hit (computedCollision: the obstacle's collider, the witness point on it, its normal, the remaining translation), and it knows what it stands on (groundEntity, resolved by its axis support ray). engine/physics/rapier/pair-touch.ts — the one home for what touching means on rapier — gains the controller rule beside the manifold rule: (1) every obstacle the controller's motion pressed into this step (translationDeltaRemaining · normal1 ≤ −0.1 mm; the depth bound drops the slide-remainder micro-hits a near-flat floor projects into an adjacent wall, ~1e-7 m, which flipped in and out of the hit list tick to tick) is touching the character, with the witness point and the obstacle's normal as the contact geometry; (2) a grounded character is touching its support entity on every tick it stands there — standing IS touching — with the axis support ray's hit as the geometry (CharacterControllerHandle.groundHit, kept by probeSupportBelow's axis rays, which now use castRayAndGetNormal). Both rapier collide lanes in tome/systems/physics-dispatch.ts (the server loop and the client-auth lane, adopts included) fold these pairs into the same touching set and begin-edge baseline as the manifold pairs, AFTER the manifold pass for the same entity, so a pair the manifold already measured keeps the manifold's contact (a dynamic ball pushed by a character has a real solver contact; a ball rolling into a standing character is unchanged). Contact convention matches the manifold path (buildControllerContact: normal entityA → entityB, invertContact for entityB's hook); impulse is 0 — the controller resolves by displacement and the solver applied none, the same 0 a kinematic-style manifold reports. Consequences: a character pressing a static wall fires onCollide once per touch episode with the point on the wall and the wall's normal, on both hooks (the wall's own onCollide sees the character too); leaving and returning fires again; the floor fires once at the landing and never re-fires while the character stays grounded — the pre-existing avatar-floor flicker (a handful of impulse-0 begins per 480 ticks, equal on both sides of #14366) is gone at its root, because the support pair never leaves the set while the character stands. A character walking into a KINEMATIC body (an NPC, a mover) usually does NOT fire: rapier's controller matches the character's motion to every nearby kinematic body's velocity (its moving-platform rule, applied along the contact normal to any kinematic collider inside the ground-prediction band, ~2 cm), so a head-on press into a stationary kinematic capsule or box is absorbed there with no cast hit and no computedCollision — the character stalls 1.3–1.4 cm from it, silently (landed-look probe: 0 hero←npc events on this version and on its parent; a hit is recorded only when one substep's cast reaches the body from outside that band, e.g. a glancing approach). A press slower than about 5 cm/s is also not stable: between ~1 mm/s and ~2 cm/s the wall hit drops in and out of the controller's list tick to tick and the floor's tilted cast normals inject 1e-4–7e-4 m of horizontal slide remainder above the depth bound, so the pair flickers (30–50 begin edges per 300 ticks in the probe); at 5 cm/s and above (any walk, any analog deflection outside a dead zone, hugging a wall diagonally) the pair is continuous and fires once. A character whose spec physics stops being "character" releases its rapier controller handle the same substep (updateCharacterControllers → releaseStaleControllers), so its last hit list and support cannot be read as a standing touch after the flip. Red-first engine-path pins on real rapier with the production step order (controllers inside stepPhysics' substeps, then dispatch) and the taught motor: wall press ×2 with point x = face, normal +x (parent: zero events); floor once at the landing (parent: two mid-run flicker begins in 180 ticks); a ball rolling into a standing character on the manifold path; the support rule under a motor that never presses while grounded, through the settled-stance noop skip, and across a jump whose landing arrives exactly at the offset. Named residue: a hosted wall's own onCollide still does not see a REMOTE player's character (replicated pose, no controller step on the host) — the same silence as before, now named; getTouching()/isTouching() still read the raw enumeration (decision surface, ledger 1945). interaction-island.ts's rapier adapter keeps the manifold rule alone (its claim trigger's avatar-kicks-ball touch has a solver contact).
  • A god-mode handle press that releases with the pointer still runs no drag(), fires no release(), and commits nothing (ledger 2769 — the click-squash half of gfta's 'drag to scale doesn't work good', thread 1543013163216150579). Every drag op now freezes the press pointer NDC (GodModeAuthoringOperationValue.pressNdc) and latches dragArmed the first tick the pointer leaves click-to-select's tap budget (RMB_TAP_MOVEMENT_THRESHOLD, 0.01 NDC L1) around it — so a gesture is a tap to both or a drag to both. Until the latch, tickHandle (god-mode/systems/handle-ops.ts) runs no drag(); a release that never armed skips release(), the settle sound and the move-telemetry row, and its gesture commit diffs an unchanged envelope (no spec write, no undo entry). A handle that also declares click gets the click, as before. Mechanism it removes: the hover extrude handle on an unselected cube face reads its drag with rayToAxis along the face normal, whose gain is 1/sin(angle between the view ray and the normal) — for a face seen nearly head-on a hair of ray difference between the press tick and the release tick is metres of scale, committed on release; and on a fine pointer the canonical ray is renderer-authored a frame behind the pointer, so a click right after a move carried a press ray aimed where the pointer WAS and a release ray a whole move away. Measured on 5.2.4x master bytes in real Chromium: one click scale.z 1→1.33, the next 1.33→0.14, six clicks ended at 2.28; in-process, a 5 mm (one-pixel) ray difference at 1.2° wrote 11.6 cm. The tap test reads pointerNdc, never the ray, for exactly that reason (the old ray-cone wasTapGesture for drag+click handles is replaced; it also never worked under ortho, where the pointer moves the ray origin). The hover extrude handle's anchor was already effectively press-frozen through the op's frozen hit (op.hit.pointWorld) — the row's 'fresh at' hypothesis was not the mechanism; the probe with identical press/release rays wrote nothing before this change. Red-first pins in default-editors.test.ts ("hover click on a cube face writes nothing"): a one-pixel-off release (parent: scale.z 1.116), ten clicks (parent: collapsed to the 0.05 MIN_EXTENT floor), and a real 30 cm drag still extrudes. terrain-anchor-commit.test.ts's two zero-move-touch pins now read the click's true no-op (the live projection stays as found; the parked-entity residual undo entry is gone for a zero-move touch). God-mode input fixtures that drive drags by moving the ray now keep pointerNdc in step with it (test-utils.ts pointerNdcFollowingRay; the downRay-style helpers carry an NDC) — a fixture pointer that never moved would read as a click at every frame. Named residue, not changed here: the 1/sin gain itself — a real 13-pixel drag on a face seen 1° off its normal still writes ~2 m — is a design question for the god-mode UX pass (2768), and the one-frame press-ray lag on fine pointers still stamps that lag into the first drag frame's delta.
  • A clock read inside run_script is never counted as a world write (ledger 2746). On the relay tier with an armed room clock, the authored clock verbs (api.getTick, api.seconds(), getWallClockTime / getWallClockTimestamp) resolve the room tick once per local tick by writing tome/relay-room-tick-latch (tome/tome-clock.ts getRoomTick). Inside an exec that write goes through the transaction overlay, and the resource had no merge-strategy entry, so it rode the log as a plain lww patch: a readOnly probe whose only clock read was the first of its tick answered readOnly: 1 world write and 0 SQL writes were discarded, and a write-mode probe with the same read carried worldMutated: true and the frozen-read note. Whether it fired depended on whether a host behavior had already latched that local tick, so the count looked spec-version-correlated — Savi's own instrumented proof (a recording Proxy around api, every call a read) still saw the write, filed it as the engine miscounting her pure read, and a debugging pass burned on it. The latch is per-local-tick scratch, the tome/tick class: valid to read at the exec's tick, meaningless to merge at a later one. It is now skip in exec/merge-strategies.ts. Nothing else moves: the read still answers in the room's domain, and the live world keeps latching its own ticks. Red-first pins in exec/__tests__/world-mutated-signal.test.ts (the exact lane — runIsolatedExec over a live world with an armed RelayRoomClock; the SnapshotWorld lane never saw the write because the clock is a class instance the plain-data gate drops) and in relay/__tests__/relay-script-exec.e2e.test.ts (a room-truth host answering a readOnly clock probe with no discard note).
  • A close() issued from inside a coalesced messageBatch stops the rest of that batch (engine/client/worker/private-client-transport.ts; ledger 3074). 5.2.40 taught the private room transport to drop a closed dial's traffic (closedByOwner), but the bar was read once per batch: when the handler's own verdict on entry k hung up — the relay welcome's join refusal, failRelayJoin → 4438 — entries k+1…N of the same batch were still delivered to the handlers of the socket they had just condemned. Each re-entered the runtime's first-frame sniff (wire mode back to "undetermined"), resolved kernel (not a welcome), failed the kernel parse, decoded as relay speech, and closed 4437 again. MechaBlade's live seat (pinned 5.2.23, whose transport had no bar at all) logged 8–325 relay-grammar frame on a kernel-mode socket closes per redial this way; on 5.2.40 the same shape still bleeds up to the batch budget (63). The bar is now re-read per entry, so the frames behind an owner close reach nobody. Pinned in browser-host/__tests__/room-transport-bridge.test.ts (red on 5.2.40: four deliveries where two were owed).
  • A GameDB relay-lane reply settles its api.sql promise at socket receipt, never through the ordered ingress queue (ledger 3084). A player seat's api.sql rides the relay's gamedb RPC lane: tome/api/game-db-relay.ts parks the promise in byRequestId with a wall-clock deadline (RELAY_GAME_DB_TIMEOUT_MS, 30 s) that the sim-tick sweep (tome/relay-game-db-sweep, simulation 124) adjudicates with Date.now(). The RPC_RESULT used to come back as a relay.rpc.result ingress row, drained in arrival order beside every peer frame under the per-tick budget (netcode.ts INGRESS_DRAIN_BUDGET_MIN_MESSAGES = 128, then 8 ms). So delivery ran on the sim's clock while the deadline ran on the wall's, and the two disagree whenever the drain cannot run: a hidden tab parks the frame loop (runtime-worker.ts shouldSelfScheduleWorkerRuntimeFrames) while its socket keeps receiving; at resume the first tick drains one budget floor of a thousands-deep backlog, then the sweep rejects every call whose 30 s passed — with its answer a few thousand rows back in the same queue, applied later to nobody (applyRelayGameDbResult drops an unknown id). The Neighborhood, 5.2.40, creator tab hidden 13:02:36–13:04:26Z: ~30 boot-time reads and writes (kat_rep INSERT, dcar_trunk, golf_best, the street's clock/work/pet reads, four CREATE TABLEs) rejected GameDB relay lane timed out after 110–122 s in one tick, and the game's lanes started on empty state. Fix: the transport hands a gdb- result straight to the lane on arrival — room-runtime.ts onRpcResult → the new ClientRoomRuntimeHooks.settleRelayRpcResultOnArrival (runtime-worker: the mounted world) → netcode.ts settleRelayDoorReplyOnArrival → applyRelayGameDbResult. Delivery and deadline now share the wall's clock; the sweep is left with the replies that never came. Behavior callers see the settled value at the next tick boundary exactly as before (sql-api.ts deliverAtTickBoundary → tome/sql-settle), the socket event and the frame are one thread so the table is never touched mid-sweep, and every other RPC lane (purchase, incident, dm, the forwarded-job bridge) keeps the queue byte for byte. Unset hook = today's queue (no simulation mounted yet: the sweep that would judge the reply has not run either); the queue path in handleRpcResultRow still settles a door reply that reaches it. The relay multi-client harness mirrors the seam. Red-first pin relay-gamedb-reply-hidden-tab.e2e.test.ts: 30 behavior-context api.sql reads from a player seat, the tab parked while a peer queues 200 rows and the door answers, 110 s on the wall, one resumed tick — parent: 30 api.sql failed: GameDB relay lane timed out after 110s runtime-log lines (the reporter's exact line); fixed: zero, every read answers the seeded row; a visible-tab boot control and a lost-reply control (the sweep still rejects typed at 31 s).
  • The look-park flip loop is closed on both of its paths (ledger 3065). renderer/frame-budget-report.ts parks the look as step 0 of every GPU-attributed fallback episode. On a tab that hovers around the 40 ms fallback line the previous version flipped the whole screen between the authored grade and the neutral frame, park then restore, over and over — one client only, since the other players' tabs never cross the line (BT's Emberfall desktop tab, 09-04: three park/restore pairs in three hours on the getLogs rail — park ~56 → restore "still ~40", park ~116 → restore "still ~41", park ~56 → restore ~54 — invisible while the seeded look was a passthrough, a visible flip from the moment Savi wrote a real grade into scripts/look-default.js). Two mechanisms produced those pairs. (A) A futile look park was forgotten. When the settled fused signal shows the park recovered nothing, restoreFutilePark returns the look and disarms the machine; the disarm forgot the verdict, so the next fallback event (the guard's recover-then-recross, or the governor's calm-then-sustain parkRequest) opened a fresh episode that parked the SAME look again, settled, found the same futility, and restored it again. The machine now keeps futileLook, the identity of the look the futility verdict restored — script ref + source hash (getLookScriptHash) + the active heavy vocabulary effects — across its own disarm; advanceParkEpisode's look step skips a look whose identity matches. A script edit (new hash) or a newly enabled heavy effect (dof, chromatic aberration, scanlines, blur) is new work and gets its one trial again; a renderer restart clears the memo with the rest of the machine (resetScriptedMaterialParkMachine). The 56 → 54 pair is this shape. (B) A held park was judged against itself. The other two restores cannot be futility verdicts on this engine: 40 from a 56 opening and 41 from 116 are credit-band values (≤ PARK_CREDIT_RATIO 0.85 × the opening), which the three-way verdict holds, never restores. They came from the held phase. The look park DELIVERED (the fused signal came back under the line), holdParkEpisode cleared the opening anchor (debt paid) and the settle clock, and the next over-line reading in the held phase — with parkActionSettled trivially true — re-entered advanceParkEpisode, which anchored preParkFrameMs at the current post-park cost, found nothing left to park, and judged that cost against itself: never growth, never credit, so futile. A fresh anchor equal to the current reading can only ever say futile, so one over-line reading after a hold restored a park that had delivered, with the restore sentence "didn't recover the frame rate (still ~41ms with everything parked)" false as spoken; the same hole returned every held scripted material in one sweep before any staged recovery ran. Now only a step that actually parks something anchors an opening (anchorOpening), and over-line evidence that finds everything already parked with no opening on the books holds instead of judging — paced by the settle window like a credited hold, materials still stage back when the world calms into the band, the look keeps its script-edit path. The evidence unit is unchanged: one settled reading of the guard's 5 s fused window, the same unit every other verdict in the driver uses; no sample-count rule was added. Through path (B) the (A) memo would also have frozen a look whose park delivered, leaving a slow machine over budget for the session with its first lever gone; it now records only real futility trials. Pins: BT's rail (park at 56 → held under 40 → one reading at 41 → the look stays parked through sustained over-line readings and a fallback event landing on the held machine; restored on the previous version), the material shape (held at 33 → one reading at 45 → both materials stay parked, then stage back when the world calms), the (A) memo (the unchanged look never re-parks across two later fallback events, a hash change re-arms one trial whose futility is remembered in turn, a restart clears the memo, a new heavy effect re-arms).
  • A forwarded-job reply on the relay llm lane (ljob-) settles its rail entry at socket receipt, never through the ordered ingress queue (ledger 3088 — the same class as 3084, one table over). A behavior's api.job("llm:chat" | "llm:generate") on a relay room rides the forwarding facade (tome/systems/job-forward.ts withSingleplayerJobForwarding): the rail entry carries a wall-clock timeoutAtMs (deadline + 20 s, default 130 s) that the sim-tick response pass (tome/systems/job-response.ts, simulation 125) adjudicates through jobs.status() with Date.now(). The reply's RPC_RESULT used to correlate only in netcode's FIFO drain (handleRpcResultRow → relayPendingRpcs → translateRpcJobResult → the job.response control → applyJobForwardResponse), drained in arrival order beside every peer frame under the per-tick budget (INGRESS_DRAIN_BUDGET_MIN_MESSAGES = 128, then 8 ms). So delivery ran on the sim's clock while the timeout ran on the wall's: a hidden tab parks the frame loop while its socket keeps receiving; at resume the first tick drains one budget floor of the backlog, then the facade answers error for every rail entry past its window and the callback gets forward_timeout — Job "llm:chat" timed out waiting for the server response after 200s — with the model's answer a few hundred rows back in the same queue, applied later to nobody. Fix: the correlation table now lives in the netcode mount's scope (one per mount, shared by both doors), the mount hangs an arrival settle on the world (ClientRelayBridgedRpcArrivalResource), and netcode.ts settleRelayDoorReplyOnArrival — the door 3084 opened (room-runtime.ts onRpcResult → settleRelayRpcResultOnArrival → runtime-worker's mounted world) — routes an ljob- frame through it: the same job.response control, the same applyJobForwardResponse, ahead of the queue. Delivery and timeout share the wall's clock; the facade timeout is left with the replies that never came; the callback still fires inside the sim tick exactly as before. An uncorrelated bridged reply (already settled, evicted, a reset) returns false and rides the queue as today; the queue path still settles any bridged reply that reaches it. Purchase, incident, and dm lanes keep the queue byte for byte. Not the same line: relay-purchase.ts PENDING_TTL_MS (10 min) prunes stale pending purchases only when a NEW purchase begins or a host suggest arrives (sweepStale at beginPurchase / handleRelayPurchaseSuggestFrame), never at reply arrival or on a tick — a purchase reply that drains after resume still finds its entry. The relay multi-client harness mirrors the seam and now applies job.response to the rail entry as runtime-worker does. Red-first pin relay-forwarded-job-reply-hidden-tab.e2e.test.ts: one behavior-context api.job("llm:chat") from a player seat, the tab parked while a peer's 200 rows and then the model's answer reach the socket, 200 s on the wall, one resumed tick — parent: Behavior error in job: Job error: Job "llm:chat" timed out waiting for the server response after 200s and an ok: false callback; fixed: zero failures, the callback gets { text }; a visible-tab control and a lost-reply control (the facade still fails typed forward_timeout at the window).
  • A terrain re-apply no longer re-drops a spec object that runtime code moved with an absolute position (ledger 3085 — Time for Work, 5.2.40, savi filings b831b9d9 + 0fddb7cb: a driven Isuzu truck jumped from the farm back to its authored yard spot, 3 km away, with the driver still seated). The truck's spec row says feetPosition: { x: 28, y: { terrain: 0 }, z: 17 }, and its drive script writes a numeric feetPosition every tick. That write disarms the live TomeTerrainAnchor (property-helpers syncTerrainAnchor — the anchor pins an entity to a fixed x/z, so an absolute write removes it), which is the runtime's own fact that the object left its row; the runtime re-anchor system (tome/systems/terrain-reanchor) already visits live anchors only. The spec-apply pass (interpreter.ts refreshTerrainAnchors) ignored that fact: whenever applyTerrainSpec reported the terrain updated, it re-dropped EVERY terrain-relative spec row in the place from the ROW's position through updateTerrainAnchoredEntity, whether or not the live entity still sat there. On 5.2.40 the trigger was the re-spelled marks map of ledger 2808 (a kiln fold in jsonb key order vs the in-memory doc in authored order read as new terrain → full reinstall → terrainUpdated); the reporter's client folded spec v306 at 13:37:50Z, took the 169 ms two-pass apply, dirtied every chunk, and put the truck (and both forklifts, { x: 0, y: { terrain: 0 }, z: 4 / 8 }) back on their authored spots — the exact pose (28.00, 0.30, 17.00) his telemetry then reported. 2808's marks fix (b8bd7d5b6a, aboard 5.2.41) removes that particular spurious reinstall; a REAL ground edit (a new road mark, a flatten pad, a generator change — a dev room's daily work) still took the same path and still teleported every driven vehicle home. Now the pass reads the LIVE anchor: an entity with no live anchor is skipped, and one a script moved with a terrain-relative write re-seats at the script's x/z, never the row's. An authored edit of the row still lands — updateObject writes the new row position and re-syncs the anchor before this pass runs — so terrain-revision-resnap.test.ts's ledger #480 pins (unmoved boat, spline segments, scatter children re-snap to the new ground) are unchanged. This is the rule ledger #186 closed for players ("a teleport-to-spawn disguised as a height fix") applied to objects, and the ledger 2921 expectation a fold holds for rows it did not touch. Red-first pins in terrain-revision-resnap.test.ts: a boat driven to (300, −900) with a numeric-y write stays there across a ground change (parent bytes put it back at (4, 4)); a boat moved with a terrain-relative write to (12, 12) re-seats at (12, 12) with the new height (parent bytes put it back at (4, 4)). Named, not changed here: the applyTerrainSpec decorations-only branch still compares JSON.stringify(existing) !== JSON.stringify(next) — the spelling-sensitive compare syncTerrainDecorations already replaced with specValuesEqual (dump 97f8b3c0) — and reports "terrain updated" when it fires; with this change that only costs a chunk rebuild, not a teleport, and it belongs to 2808's lane.
  • A moving texture attempt has a diagnostic bound, a parked attempt has a word, and a parked attempt nobody waits on any more never takes a slot (ledger 2714 follow-up, findings F1 and F3 of the landed-look on the stall clock + transport window). The stall clock (TEXTURE_LOAD_ATTEMPT_TIMEOUT_MS) never abandons a download that keeps moving — by design — so after the window landed a moving attempt had no upper bound and a parked attempt had no diagnostic under any shape: an attempt fed progress every 25 s lived an hour with zero warns, and eight such tricklers held the 8-wide window while a ninth demand read loading for an hour with no word and no reachable texture-load-failed (a parked attempt never fails, and the exhaustion teaching is gated on a failure episode). Three changes in lume/assets/service.ts. (1) TEXTURE_LONG_ATTEMPT_WARN_AGE_MS (10× the stall timeout, 5 min — sized from the bytes: the largest texture the cook ships is ~6 MB, the thinnest line the window is designed for gives each stream ~30 KB/s, which moves 6 MB in ~3½ min; an attempt still arriving past this age is under ~20 KB/s on the largest texture or under 1 KB/s on a typical one): an ADMITTED attempt still moving at this age since admission gets ONE console.warn — This texture has been downloading for N min and is still arriving; nothing in the game needs changing. — with downloadingForMs, bytesSoFar, progressSignals, sinceLastProgressMs on the data object. Never an abort. LumeTextureLoadContext.progress now takes an optional byteCount; readResponseBytes passes each body chunk's length so bytesSoFar is real on the production loader (stub loaders that call progress() bare still work). (2) TEXTURE_PARKED_WARN_AGE_MS (= the 60 s exhaustion teaching age): a PARKED attempt this old whose record still has a live consumer gets ONE console.warn — This texture has waited N s in line behind M other texture downloads and has not started yet; nothing in the game needs changing. — with parkedForMs and aheadInLine (the window plus the parked attempts in front of it) on the data object. A park nobody waits on stays silent. Both clocks ride the existing sparse deadline sweep (expireWedgedLoadAttempts folds the long-attempt and parked-age wakes into nextLoadDeadlineAt; a park arms its wake at park time because a parked attempt has no deadline of its own). LumeTextureActivitySnapshot gains parkedAttempts and oldestParkedMs, and the debug snapshot's textureStats gains parked / oldestParkedMs (F2 inspector "Tracked Textures" rows and the {op:'everything'} memory mirror show them) — the parked-forever state has a number. (3) Order fix at admission: a parked attempt that was demanded — the record had a live consumer at startLoad, OR a consumer subscribed / retained while the attempt sat parked (noteDemandOnParkedAttempt, called from subscribe, subscribeTextureAsset, retainCurrent) — and whose demand has all left by the time its slot comes is dropped without a loader call — needsLoad stays set so the next consumer revives it — a getTexture through requestLoad (the primitives store's own first call), or a bare subscribe through reviveDroppedLoadIntent — and the slot passes to the next waiter. Before this the dead demand downloaded ahead of live demand behind it, the exact inversion the window exists to prevent (probe: window 1, a/b/c demanded, b's only subscriber leaves while parked, a settles → the slot went to b). A park that never had a consumer keeps its place — an eager manifest preload, a warm hint, a poll — the first-attempt license is unchanged; only demand that was there and left is dropped, eager or not. demanded is set at start and by any consumer that arrives while parked, because every JIT route starts the load on getTexture with no consumer yet and registers its consumer after (primitives/store.ts texturePlacementInputs calls getTextureAsset then watchTexture; lume-assets.ts getTexture the same). The first cut read the flag only at start AND exempted eager parks; the product receipt on it showed a destroyed box's dead park admitted and fetched (90 KB) while the next live box stayed parked, and the in-process rerun on the real store showed both defeats: the store subscribes after it starts the load, and on the product every material texture IS an eager manifest entry (apply-render-manifest.ts registers each smart-resolved texture with no preload flag, which the service reads as eager), so the eager exemption swallowed the rule for every texture a creator draws. admissionWaiters now holds the attempts themselves (each carries its wake), which is what makes the park census O(1). Red-first pins in service-load-window.test.ts: a 25 s / 1 KB trickle for an hour gets exactly one long-attempt warn with bytes and age, no abort, and still publishes; the warn fires at the bound (not at the next stall wake) and once; eight tricklers plus a ninth demand, ticked to 90 s, produce one warn naming the ninth with aheadInLine: 8, the snapshot reads parkedAttempts: 1 with the oldest age, and the count drops to 0 when the park is admitted; a park with no consumer gets no word; unsubscribing every consumer of a parked demand makes it drop at admission and the live demand behind it dispatches in its place, and a later subscribe revives it; the same in the store's own order (getTexture first, subscribe after) through both the asset rail and the listener rail; eager and never-demanded parks keep their place; readResponseBytes reports each chunk's byte count. On master's bytes: zero warns in the trickle hour, zero for the parked ninth, loadCalls reads [a, b] for the dead demand. A second pin runs the REAL texture service under the REAL primitives store (primitives/__tests__/texture-park-drop-integration.test.ts): three textured boxes on a window of 1, removePrimitive (the DESPAWN handler's call) on the second while its texture is parked, the first settles → the loader sees the third box's texture, not the removed one's; the removed record reads pending with nothing fetched (which also proves the release path — a consumer leaked past removePrimitive would have dispatched it), and a new box on the same texture revives it. Four interleaves: the JIT route (boxes demand first), the manifest route in the product's order (the manifest registers every texture eagerly, then the boxes draw), the other interleave (boxes first, then the manifest's versioned url restarts each park eager), and an eager park that never had a consumer keeping its place. On the first cut's bytes the JIT and both manifest pins read […, stone]. Not changed: live-demand-first admission (F2) stays a design question on the row; the stall clock, the window size, and the fetch priority hints are as landed. The two new sentences are drafts in ravi's shape — her cut lands after.
  • The texture attempt deadline is a stall clock fed by loader progress, and texture attempts ride a bounded transport window (ledger 2714; EverSpark's login, dumps 6b274b3b and ba98ec2c). lume/assets/service.ts abandoned any in-flight texture load 30 s after it started (TEXTURE_LOAD_ATTEMPT_TIMEOUT_MS, the dig 2d2283b9 wedge deadline), aborted its fetch, and handed the record to the retry ladder. On a 3,000-object world booting over a ~10 Mbps line (dump cee78588: connection {rtt:50, downlink:10}; the rig's boot requested ~370 MB across ~1,000 /cdn/ requests) every stream shares the pipe, so a healthy texture honestly downloading at a few KB/s outlived the whole-attempt budget: the deadline threw its bytes away mid-body, the ladder re-fetched it into the same saturated pipe, and the texture never settled — [client-reported texture-load-failed] … still failing to load after 60s — last error: load attempt timed out after 30002ms without settling on a dozen cdn textures and the engine's own circle_05.png, and the walls (boxes whose albedo was pending) drawn as nothing. Three changes. (1) LumeTextureLoadContext.progress: the production loader (createLumeKtx2TextureLoader) reports movement after the Magic CDN probe answers, when response headers land, on every body chunk (readResponseBytes reads the body as a stream instead of arrayBuffer()), and when the decode finishes; each signal re-arms the attempt's deadline to now + timeout. A moving download is never abandoned; an attempt with no movement for the whole timeout still dies exactly as before (the hidden-tab wedge — the clock is still the tick clock, so a frozen rAF pauses it and the first resumed tick judges the span at once). The abandon warn now reads passed its 30000ms stall deadline (Nms with no progress, Mms without settling …); the record's lastError text is unchanged. (2) TEXTURE_LOAD_ATTEMPT_WINDOW (8, config loadAttemptWindow): at most that many attempts are on the transport at once; further attempts park in the service's own FIFO, in demand order, with deadlineAtMs +Infinity — a parked attempt has nothing to judge and is never abandoned — and are admitted as slots free (the abandon path and the settle path both return the slot). Before the window every demanded texture hit fetch in the same frame and sat in the browser's own stream queue, where a request that had not left the browser showed no progress and would have died at the stall deadline too, re-queued behind the next burst. A free slot dispatches synchronously (the loader call stays observable in the same frame, as every existing pin assumes). Scripted bakes and builtin ids bypass the window (no transport). pendingTextureCount / activeAttempts count parked attempts (they are in-flight to their consumers, state loading). A parked attempt whose record changed source (generation bump) or was disposed drops at admission and hands the slot on. Red-first pins in service-load-window.test.ts: progress at 8 s intervals keeps a 10 s-deadline attempt alive for 40 s and it publishes; silence for the whole deadline after movement abandons at that age of silence, not the attempt's; a window of 2 with four demands dispatches two, parks two with no clock, admits the parked pair in order when the admitted pair is abandoned, and their deadline starts at admission; a stale parked attempt drops and passes its slot; scripted bakes bypass; readResponseBytes reports one progress per chunk and returns one exact-fit ArrayBuffer (the decode transfers it). On master's bytes the two stall pins fail (aborted reads true at 11.5 s on the whole-attempt clock). (3) The browser's fetch priority hint rides AssetFetchInit.priority (asset-fetch.ts): the texture lane's probe and payload fetch ask "high", the model payload fetch (renderer-asset-service.ts) asks "low" — geometry is the bulk of a big world's boot bytes (the rig's boot: 1,061 glb requests / 302.8 MB against 472 ktx2 / 116 MB), textures are what every surface waits on, and the browser dispatches its per-host queue and weights its HTTP/2 streams by the hint; routed hosts (the server isolate) may ignore it. Measured on the real product (second stack, headed Chromium, the arkcaves clone of EverSpark's v22010 spec, every /cdn/ request served production bytes streamed through one shared 1.25 MB/s line with 50 ms RTT, 165 s after navigation): on master's bytes the renderer worker logged 255 load attempt passed its 30000ms deadline aborts (66 distinct textures, first at +108 s), texture-load-failed after 60 s on 25+ textures, the texture service ended ready 28 / loading 9 / failed 56 of 93, and the walls' albedo (texture-cavern-ceiling-jagged-rock.png.ktx2, 324 KB) was requested at +78 s and never settled in 230 s — each attempt died at 30 s with the body ~75% delivered and the retry started over; on this version the same boot logged 0 deadline aborts and 0 texture-load-failed, the service ended ready 93 / loading 0 / failed 0, the walls' albedo was ready at +26.9 s (first paint +15.9 s) and every wall-family texture at +32.3 s. Not changed: the model lane has no deadline and no window; the audio lane is untouched.
  • A quota window's last half-second is the network's, not the tombstone's (ledger 2654). engine/assets/magic-cdn-async.ts keeps its per-URL verdict tombstones on wall time (Date.now()), while every consumer ladder parks on its own clock — the renderer frame clock sampled at the tick before the failure landed (lume/assets/service.ts textures, renderer-asset-service.ts models), a setTimeout (audio/resources.ts), Date.now() read later (physics/systems/collider-assets.ts). A ladder's re-probe therefore arrives a few ms BEFORE the wall clock agrees the window is over; the tombstone answered it locally with retryAfterMs = untilMs - now (single-digit ms), the ladder parked on that leftover, every lane's park line rounded it to 429 window holds for 0s, and only the next tick reached the network (prod kiln-browser, 14 d: 70 rows across the texture, model and audio lanes; one staging texture wore the line at every hourly lift). getActiveVerdictTombstone now treats a tombstone inside its last VERDICT_TOMBSTONE_EXPIRY_GRACE_MS = 500 ms as expired — exactly the leftover set that rounded to "0s", well under the smallest window the layer mints (the 1 s Retry-After floor, the boot lane's 2 s rung). The early re-probe goes to the network and gets the server's fresh verdict (a full window under sustained pressure, ready when it lifted). Pinned in __tests__/magic-cdn-async.test.ts; three existing boundary pins move from window − 1 ms to window − 500 ms.
  • The texture lane's quota park speaks the platform-state verdict. lume/assets/service.ts parked quota 429s with the model lane's shape (attempts frozen, one re-probe at the server's deadline) but told Savi nothing: its trace was the renderer console's park line and an error-level Failed to load texture … 429 row per denied fetch, so a sustained cook-queue window read as a texture that keeps failing. model-quota-park-report.ts now carries one lane-agnostic episode latch dressed in lane words — createModelQuotaParkReporter (byte-identical message and data) and the new createTextureQuotaParkReporter, which the texture ladder's quota branch calls; the report is texture-quota-parked (allowlisted in tome/engine-diagnostics.ts, classified in cf-studio-chat's dm-lane as texture_quota_parked), once per pressure episode across all textures, with the server's own reason, one UTC resume clock, and "Scripts and texture refs are fine — no need to debug or regenerate". The per-fetch 429 row is a warn (rate-limited (429) — quota window pacing applies), the model lane's ledger-1740 downgrade. Pinned in __tests__/model-quota-park-report.test.ts (145 re-denied rounds stay one verdict) and lume/assets/__tests__/service.test.ts.
  • The terrain change-signature is spelling-independent at every depth, and carries only the part of the marks map's order that is ground (ledger 2808, second half — "I Shall Seal the Heavens", follow-up to the top-level key sort). The key sort of the marks map was one level short: buildHeightmapMarkSignature projected most fields into fixed-order literals but passed a flatten's and a clear-scatter's shape through raw (the voxel arms did the same with shape, template, flattenBelow; liquidMaterialSig with params; the envelope with lodRanges/meshing). A rectangle shape leaves the terrain door as {kind, width, depth} (zod field order) and comes back from kiln as {kind, depth, width} (Postgres jsonb: key length, then bytes); a path shape flips points/width the same way. The reporter's map carries ten rectangle-shaped marks, so a resized pad followed by a save still read as new terrain and re-planted every scatter bed. buildTerrainSignature now serializes through canonicalSignatureJson — JSON.stringify with object keys in code-unit order at every depth — so every raw passthrough, present and future, is spelled one way; the junk-field rule holds (a malformed field that changes still changes the fingerprint). TERRAIN_MARKS_SIGNATURE_VERSION 6 → 7. The residue the key sort opened is closed without touching the winner rule: resolveTerrainMarkEntries still applies same-kind marks in map order ("later flatten wins"), so a fold that reorders two OVERLAPPING flattens changes the carved height — after the key sort alone, connected peers kept the authored ground while a fresh joiner resolved the folded ground until recycle. The heightmap signature now carries marksOrder: every ordered [earlier, later] pair of same-kind marks whose reaches intersect (resolveHeightmapMarkReach in features/terrain/marks.ts, the resolveMarkBounds envelopes read from the raw mark and widened by the longest control segment where a spline can bow; unbounded reaches everywhere; clear-scatter is a union and stays out). A spelling flip of disjoint marks changes no pair and installs nothing; a flip that swaps two overlapping pads changes one pair and reinstalls — every peer moves to the folded ground together, as before. Pins in scatter-fold-identity.test.ts with a recursive jsonb speller: a rectangle flatten, a rectangle clear-scatter with rotation, a path-shaped flatten and a scripted-liquid params record each keep 12/12 children and the installed definition (0/12 before); the reporter's own 66 v267 marks (fixtures/ledger-2808-heavens-v267-marks.ts) with all ten rectangles resized through the real updateMark door, then the whole doc folded back in jsonb spelling twice — same revision, every child kept (a reinstall before); overlapping pads reordered → new signature and the ground at the overlap moves 8 → 4; disjoint pads reordered → nothing; overlapping clear-scatter reordered → nothing.
  • A spec fold that spells the terrain marks map in a different key order no longer reinstalls the terrain (ledger 2808 — "I Shall Seal the Heavens", 5.2.36, savi filing 65da1180: the whole forest re-planted on every save). buildHeightmapMarksSignature / buildVoxelMarksSignature (tome/interpreter.ts) walked Object.entries(marks) in map order, so the terrain change-signature carried the map's spelling: a kiln fold arrives in Postgres jsonb key order (length, then bytes) while an in-memory doc keeps authored order, and the same 66 marks spelled two ways read as different terrain. The mismatch rode the full-reinstall path: applyTerrainSpec returned "updated", markTerrainPlaceDirty(supersedeInFlight) dirtied every chunk (the [terrain/client-build] … stuck bursts right after each fold in the filing's console), and refreshTerrainAnchors → refreshTerrainScatter destroyed and re-minted every scatter bed in the place — 138 pines + 23 bamboo in the reporter's world, on a fold whose diff (game_specs v266 → v267) was four asset-metadata rows. Signature entries now sort by mark key in code-unit order (the rule decorationClearScatterMarks already uses), so both spellings produce one signature and a fold that changes nothing about the ground installs nothing. Red-first pin: scatter-fold-identity.test.ts — a jsonb-respelled marks map keeps 12/12 scatter children (0/12 before); alongside it the two fold shapes the reporter's room actually produced (a script-only save; a wisp adding 40 terrain-anchored static nav-wall boxes, v252 → v253) and the room-local second-spelling registry shape, all keeping every child. Real-stack receipt on master before the fix (block-1 second stack, the reporter's own v267 spec, real Chromium): four folds of those two shapes produced zero scatter despawns — the spelling flip is the one shape that re-minted, and it needs a room-local marks write between kiln folds to arise, which is why the bare replays passed. Named residue, not changed here: resolveTerrainMarkEntries (features/terrain/marks.ts) still orders same-kind marks by map insertion order, so two OVERLAPPING same-kind marks can carve differently under authored order than after the jsonb fold — that ordering is content the signature now deliberately ignores, and making the geometry spelling-independent (sort within kind by key) changes what "later flatten wins" means and wants a decision.
  • Fading stars.brightness, stars.milkyWay, stars.color, or moon.intensity no longer re-bakes the night sky or rebuilds the bright-star field (ledger 3072; Savi's engine-bug report on The Neighborhood, 5.2.40). The night key (lume/sky/sky-state.ts) was [starsIntensity, starsDensity, starsColor, milkyWayIntensity] at three decimals, so every write to any of them flipped nightChanged and the store marked the night equirect bake (the per-texel faint-dust lattice walk — 125 cells per texel at the 2048 tier), the CPU bright-star bake (two texture uploads), and the IBL capture. A game that ramped those knobs every ~0.02 street hours through an hour of dusk paid the whole night stack per write; the creator saw dusk and dawn as "a real choppy change". The bake did read the intensities — but only as multipliers: the texel was (milkyWay + halo) · milkyWayIntensity · starsColor + dust · starsIntensity · starsColor + floor. It now renders the two terms at unit intensity, untinted, into two layers of one rgba16float 2d-array (layer 0 milky way + halo, layer 1 faint dust; NIGHT_BAKE_LAYER_* in sky-radiance.ts), and the composite's sky_sampleNight applies milkyWayIntensity, starsIntensity, starsColor, and the floor glow from the Sky uniform at sample time over a bicubic tap per layer. The night key is now [starsDensity, starsIntensity > 0] — the density the dust gather reads and the stars-off edge the gather gates on (fable's F2) — and the three scalings plus the star color moved to the look key. The bright-star field (sky-stars.ts) derives from the density alone and re-bakes itself in compute() when the density moves; the store's stars.markDirty() is gone with the method. The IBL capture still refreshes on these writes, by the bytes: the capture face shader is the same sky_radiance composite reading the same uniforms (bright stars · sky.starsIntensity, the night sample, moonColor · sky.moonIntensity, the moonlit wash's moonFactor), so its ambient depends on them and a fade must recapture to keep the ground lit by the sky it shows — six faces at the tier's cube size plus the small-cube prefilter and the SH projection, the same work the 5 s heartbeat and the 1° sun cadence already run. The frame is what it was at every intermediate value: the bicubic weights sum to 1, so scaling the sampled layers and adding the floor after the taps equals baking them in; the only difference is where rgba16float rounds — each layer at its own magnitude instead of the summed texel's — which is finer for the dust than the shared-texel bake it replaces (sky-star-bake.test.ts). Cost: a second rgba16float layer of the bake's size (low 1 MB, medium 4 MB, high 16 MB, ultra 64 MB more) and four more bilinear taps per sky pixel and capture texel. Measured on the real product (headed Chromium under Xvfb on the nvidia L4, the reporter's high tier forced, the reporter's atmosphere and write pattern — 30 writes every 2 s moving all three knobs): before, every write declared 1 night-bake pass + 2 star-field uploads + 6 capture faces, the write frame's GPU envelope was 10.3 ms against 1.0 ms neighbours and the render-worker CPU 16.2 ms (max 23) against 1.0; after, 0 bakes + 0 uploads + 6 faces per write, the write frame 1.4 ms GPU / 1.1 ms CPU, and a density write bakes once (1 + 2). Dark-sky pixels away from star cores (the baked terms, ~240k px per frame) differ by at most one 8-bit step at brightness 0.5 and 1.0 and by two steps on 2 of 242k pixels at 0.25, mean 0.01; the rig's own same-build repeat differs by up to 194 on sub-pixel star cores (TAAU shimmer), so star cores are not resolved by that compare — the fetch path that draws them is untouched. Red-first pins: sky-state.test.ts (a brightness/milky-way/color fade is lookChanged only; the stars-off edge and the density flip nightChanged; a moon-intensity fade is lookChanged only), sky-store.test.ts (twelve fade writes through the production store declare zero night-bake passes and zero star-field uploads, six capture faces each; a density write bakes once), sky-radiance.test.ts (the bake text reads no sky.milkyWayIntensity, sky.starsColor, or * sky.starsIntensity — the gate is its one intensity read; the composite applies all three over the two layers and the floor).
  • A spline road's reach covers the bow of its resolved centerline, and a spline the resolve rejects falls back to points in the reach too (ledger 2808, review follow-up). resolveHeightmapMarkReach (the terrain change-signature's test for which same-kind marks depend on their relative order) widened a spline road's hull by its longest XZ control segment. The centripetal parameterization spaces knots by 3D chord, so a near-vertical segment (a long Y run over a short XZ run) bows the XZ centerline further than one XZ segment past the hull — the resolve's bounds then escaped the reach, and two such roads could be called disjoint while sharing a sample. The bow allowance is now the longest 3D control segment; a random sweep of realistic grades never exceeded a quarter of the XZ segment, so no realistic road moved. The reach also read a spline the resolve rejects (a point that is not a 3-tuple of finite numbers) as the centerline, while the resolve falls back to points; the reach now reads the spline with the resolve's own test. Pins in marks-reach.test.ts: reach ⊇ bounds for every heightmap mark kind across random geometry, for the near-vertical road (red before), and for the rejected spline (red before).
  • A rapier contact pair with no measured manifold point is not a touch, and never mints an onCollide begin edge (ledger 3076; the seam residue of ledger 2022). Both rapier collide lanes in tome/systems/physics-dispatch.ts — the server loop and the client-auth lane (collectClientAuthRapierEntityPairs) — built the touching set from narrowPhase.contactPairsWith, which enumerates rapier's contact graph: one pair per broad-phase AABB overlap, empty manifolds included. A streamed heightfield chunk's AABB reaches up to its highest sample, so a body flying over a flat strip was "touching" the chunk the moment its box entered the chunk's box — at the seam for horizontal motion, at the chunk's high-water plane for a drop — and the dispatch fired onCollide(chunk, { impulse: 0 }) metres above the ground (Savi's repro from The Neighborhood, 5.2.40: a 30 m/s sphere over a flat 6.0 strip, onCollide("terrain/stream/main/-3:0:0") at (−236, 10.59, 1.0), 4.6 m up, at z=0; the creator's 520-mass aircraft crashed on that event every takeoff at ≈(−226, 9.9, −2.7)). The 2022 landing made that payload honest (point/normal absent) but kept the edge. Now the touching set admits a pair only when rapierPairIsTouching (engine/physics/rapier/pair-touch.ts) finds a manifold point within CONTACT_TOUCH_EPSILON — the rule the interaction-island walk already applied, moved to one home and shared. Consequences: the AABB-margin pair stays out of the pair baseline too, so the real ground contact that follows is a begin edge carrying point+normal+impulse instead of a silent continuation, and every real re-contact on the same chunk is its own onCollide (the old rule fired once on AABB entry and never again while the body stayed under the chunk's high-water plane). A body resting across a seam keeps one continuous touching state per chunk it truly touches, through sleep (pinned). Real ground contacts are byte-identical (buildContact untouched; pins on point/normal). absentContact remains as mantle's residue only (its touch set can outlive the manifold that created it). Red-first sim pins on real rapier: Savi's sphere (parent: the phantom at (−236, 10.76, 0.0) with { impulse: 0 }), the aircraft shape (parent: the phantom at (−226, 10.32, −2.5)), the per-bounce edges (parent: one event in 240 ticks of bouncing), the seam-rest continuity; the 2022 seam pin now asserts no edge at all, with the enumeration itself as the positive control. Named residue, not changed here: a ball rolling on a flat heightfield hops ~1 cm at rapier's internal triangle edges and re-contacts every cell (measured: 24 begins in 10 s at 4–6 m/s, impulses 0.1–3 N·s for 5 kg); each re-contact is now reported as the onCollide it is — contact.impulse grades it against a landing (27 N·s in the same run) — and the hop itself is a sim question, not a dispatch one. getTouching()/isTouching() (tome/api/object-api.ts) still read the raw enumeration and keep listing near-contact neighbors as their doc says; that read is a decision surface and the ledger-1945 sibling, untouched here.
  • An authored clip leaves assets.authoredClips on the save that removes its last play site (ledger 3087). Before, the only reclaim was the library-budget sweep (pruneUnreferencedAuthoredClips, run when a mint breached a budget), so a deleted cinematic left its sampled clips (doom-soul.js#soulPose, humanoid-locomotion.js#panicStance, …) in the spec forever — patchSpec('assets') refuses the root and patchAssets is engine-internal, so no script could reclaim them either. Now the authored-clips fold seat (AuthoredClipsFeature — the server fold and the relay-wire client fold, the same worlds that mint) watches the applied spec generation and, once per new generation after the boot generation, runs pruneAuthoredClipsWithoutPlaySites: the budget sweep's reference law exactly (a live mixer channel, an identity string anywhere in either spec view, an in-flight offer, a pending mint all spare a clip), plus one gate — the identity must have no source left that could re-mint it (its script is gone from the registry or no longer mentions the function's name; for raw-tracks clips, no script carries the name). A declared-but-idle clip (a trigger-only one-shot, not playing at save time) keeps its slot; the budget sweep is unchanged and still reclaims it under pressure. Eviction is the sweep's three writes (derived component, null tombstones through the pending fold into both spec views and a verbatim patchAssets row — kiln stores the null), and one runtime-log line names what left. Re-authoring a play site recreates the clip: the function is re-sampled (raw tracks re-normalized) at its next play under the same identity and content hash.
  • The behavior-budget park now fires on the relay tier's room host (ledger 3099; found by 3094's measurement, WICKWORKS dump parked:null across ticks 45–3172). The watchdog's authority predicate was isAuthority = !isClient || isSingleplayerWorld(world) (behavior-update) plus a matching early return in recordBehaviorBudgetSample — the prediction-era rule that a multiplayer client never samples wall clock. On the relay tier (the default on every environment) the room host IS a client world — a browser tab or the headless standing shell holding the place's simulator seat — so no relay room could ever park a runaway update(): the host's sim frame stalled for everyone, the 10 s park was never consulted, and games chunked their own work against a park that could not fire. Under client-auth nothing runs twice, so the side running a hook is that entity's one simulator: behavior-update now brackets the watchdog pass and samples every update() it runs on every world, and the park-safety gate (isParkSafe) reads the run gate's own predicate on a multiplayer client (isClientAuthLocallySimulatedEntity — this machine owns the entity or hosts its place); the server keeps isServerOnlySimulated, singleplayer keeps "anything parks", the controller rule (a mounted entity never parks) holds on every side, and the singleplayer server mirror still records nothing. The park check moved after the run gate so a seat that migrates mid-park never lifts the park under the "a player took control" line, and the hold check (isBudgetParked) now re-asks only the controller half of the gate: a controller landing lifts the park and writes that line; scope loss (the seat moved) leaves the park held, untouched and silent, until the cooldown lapses or the next applySpec (fix-forward on reader 8e2e7819's F1 — the direct path used to print the line for a seat move no player caused). A peer's replica never runs update() (pinned), so a host park never parks twice. Red-first pins in behavior-watchdog-relay-host.test.ts (a relay host world parks a busy-spinning hosted manager in 3 real ticks and logs the park; a peer never runs or samples the replica; an unhosted place runs nothing; a seat that moves away mid-park stops at the run gate and leaves the park untouched with no "lifted early" line, and the seat returning inside the cooldown finds it still parked — #14450) and the rewritten client case in behavior-watchdog.test.ts (hosted manager parks, another machine's manager gets the diagnostic, a seat move leaves the park held and writes no line, a controller landing lifts it). No Savi-read string changed.
  • The frame self-capture renders the authored UI's images instead of confessing their absence (ledgers 2699, 2638, 2568). Savi's look target=scene and kiln's comment auto-screenshot both ride the realm frame's self-raster (tome/realm/frame/capture.ts): the frame clones its own DOM, inlines what the SVG-foreignObject raster cannot fetch, and paints. Two authored image shapes fell through. A cross-origin <img> without crossorigin="anonymous" — every /cdn/ image Savi writes as raw HTML — paints for players, but drawing it into the scratch canvas taints the canvas, toDataURL throws, and the walk degraded it to a layout hole ("keep the box, hide the content"). A CSS background-image with an external url() rode the clone untouched into the SVG raster, where nothing fetches — a transparent hole. Since 5.2.35 the capture counted both into an imagesNote; now it carries them. New capture-images.ts: the walk turns a live-PAINTED <img> the probe refused (naturalWidth > 0) into a fetch candidate at its currentSrc, and pairs every live element with its clone twin to read the computed background-image (self, ::before, ::after) of every element with a layout box, collecting the external url()s. After the clone detaches, the candidates fetch (the sandboxed frame can fetch what its <img>s loaded — /cdn/ serves Access-Control-Allow-Origin: *), ride as data: URLs, and swap in: src on the img, an inline background-image !important on the element (it wins over the sheet rule that authored it), a per-element rule in a capture-only <style> for pseudo-elements. Bounds are the fonts lane's: the clone walk's shared 24MB inline-data budget, a 1.5s wait bound run alongside the fonts wait (an unsettled fetch skips THIS capture and keeps running to warm the next), failed fetches evict so a later capture retries, and a per-mount cache keyed by absolute url so burst captures never re-fetch. The fonts lane and the images lane now share one fetch→data-URL cache module (capture-inline-cache.ts; fonts behavior unchanged, its tests untouched). The painted gate is a fidelity law: a never-loaded img or a display:none plate is a hole on the player's screen too, so it is neither inlined nor counted. imagesNote now names only what still could not ride, with the fact and the next move: capture blind spots: N image(s) still loading into the capture (look again in a moment) and N image(s) that could not be read into the capture and N image(s) too large to carry in the capture — no component words; the chat tool's Image caveat: prefix and "do not judge missing images from this frame" suffix are unchanged. Red-first pins: capture-images.test.ts (img swap + budget spend, background substitution leaving gradients and data: layers alone, pseudo rules, in-flight → hole+note → next capture inlines from the cache with one fetch, failed → hole+note+evict+retry, over-budget → hole+note, the note's word-list pin) and capture.test.ts (a painted taint-refused img is a candidate, not a hole; painted external backgrounds are candidates inline/sheet/::before; unpainted and data: shapes are not). Real-Chromium receipt: scripts/verify-capture-images/run.ts serves a page and a second ACAO:* origin, mounts the three shapes, runs the production createFrameCapture twice, and reads the PNG — red img, blue plate, green ::before, no note, zero cors fetches on the second capture. Pre-existing and unchanged: Chromium starts a detached cloned <img>'s own load (a cache hit under CDN headers).
  • A press on a creator tab's non-interactive surface is the panel's, never the world's (ledger 2751 — horse's report, dump 512bc084, engine 5.2.34). The creator render container (#tome-creator-ui) holds exactly the open render-path tab's authored html, positioned in the rail slot. It is the pointer-events:none plane, and only the interactive grammar opted in, so a click on the panel's header, a label or its padding fell through to <body>, forwarded overUi:false, and in god mode landed behind the panel as a select, a placement or a brush stroke — the "mod interface clicks pass through to the world" the creator saw on the Crew tab and his own boards. The frame base stylesheet (realm/frame/styles.ts) now carries #tome-creator-ui > * { pointer-events: auto; }: the panel's root element(s) take pointer events, so a press anywhere on the panel hits the root inside the container's data-input-capture="ignore" subtree and forwards overUi:true, exactly like a press on one of its buttons. The container itself keeps ledger 2618's law — a fitting panel leaves the slot's unused remainder to the world, an overflowing one takes the whole rect for its scrollbar. The id selector outranks an authored pointer-events-none utility on the root on purpose: a HUD idiom carried onto a panel must not reopen the hole. The game HUD plane (#tome-ui-container) is untouched. Red-first pins: the frame stylesheet rule (styles.test.ts), the computed grant on a fitting panel's root beside the container's kept none (integration.test.ts), and the real hit-test in the Tome realm browser gate (tests/browser/suites/creator-panel-seam.pw.ts: a Chromium click on the panel's title forwards overUi:true — parent forwarded false; the slot remainder and the world outside forward false, both sides).
  • An onMount creator tab is styled on its first open of a session (ledger 2764 — savi filing febbafce, the jukebox bench on 5.2.34). The authored stylesheet gate (fonts + base rules + the Tailwind Play runtime) ran only from the render lane's first class-carrying html; a lifecycle mount delivers html of length 0, so a session whose first creator panel was an onMount tab painted raw text top-left until some render-path tab loaded the sheet — then every reopen was styled, which is exactly the "opening any other panel once fixes it" the filing describes. The frame lifecycle host (realm/frame/lifecycle.ts) gains an ensureStyles dep it runs before onMount builds the panel's DOM; the frame runtime wires it to the render runtime's new ensureStyles() (apply-render.ts), the one gate both planes now share — idempotent, and it satisfies the render lane's own lazy flags. The Tailwind runtime's load scan compiles what onMount already built; later mutations ride its observer as before. A mount that compiles nothing or exports no onMount requests nothing (nothing paints). Red-first pins: the gate runs with the mount container still empty (lifecycle.test.ts), a creator frame that never received html carries #tome-ui-styles + the runtime script after a mount (integration.test.ts), and in the browser gate a mounted w-72 panel computes 288px with no render-path panel ever opened — parent measured the viewport width (creator-panel-seam.pw.ts).
  • A generated mesh's derive mismatch now reaches the room's runtime log with its cause split, from every client, under its own diagnostic code (ledger 2882; Savi filings b17e7efa / 7f0dbeba, Full Rights, 97 crown-* scripted primitives). The scripted-primitive ingest proved the cause of every derive mismatch (script-identity skew / replayed-tape nondeterminism / over-cap ground-digest divergence or nondeterminism / legacy-ground guess / plain nondeterminism, with the mint and local script hashes and ground digests) and printed it as a console.warn on the deriving player's console only; ecs-sync's wait relay rode the bespoke-geometry-underivable code with a body that pointed at "this player's engine log", fired only when a renderer confirmed the wait, and ran ~620 chars framed so the server's 500-char cap cut its tail. A world with no client attached — Savi's headless builder seat has no render channel — had no reachable diagnosis anywhere. Now the split rides the verdict row (ClientBespokeGeometryUnhealable.cause: the rung plus the six hash facts), the ingest reports the row on the engine.diagnostic rail at derive time from the sim realm under the flavour's own allowlisted code bespoke-geometry-derive-mismatch (error class, per-code storm count, server-console breadcrumb), ecs-sync's wait relay re-reports the same code + key + body (so the server-side dedupe folds both emitters into one getLogs row per entity+pointer), and the row's data carries cause, scriptContentSkew, mintScriptHash, localScriptHash, groundReplayed, mintGroundDigest, localGroundDigest. The derive-mismatch flavour no longer shares the underivable code whose body prescribes "persist it as a spec object" — wrong for an already-persisted object.
  • Coverage, honestly (landed-look on #14408): the rail admits 20 reports per client per 60 s and drops the rest with no retry, and the ingest derives every parked entity inside one such window, so a 97-object fan-out on one client lands ~20 rows and loses ~77 (the memo parks each entity after its one derive; nothing retries a rejected report). That is strictly more than the zero a renderer-less seat landed before, not full coverage; the cap is the rail's contract, not this row's to change.
  • The emitter reports only when the verdict CHANGED (landed-look on #14408, measured with a probe): a tape-less ground recipe (a pre-tape row, or an over-cap digest generator) re-derives on every ground-key move — any voxel carve in the place, a sculpt elsewhere in the terrain chunk under the object — and a re-derive to identical bytes and identical facts used to re-report the identical row, which past the server's five-minute per-key TTL re-landed as a NEW getLogs row for as long as the park stood. The ingest now compares the new verdict against the one standing on the entity (same pointer, same rebuilt signature, same cause split → nothing new to say: no warn, no row, no renderer forward); a ground converging through N states still mints N rows — the first and each change. Pinned red-first in ground-derive-skew.test.ts (five converging states → five distinct rows; a same-chunk dab between each → a re-derive and no row).
  • The closing sentence rides the rung, never the family (ravi's read, folded): "Re-requests do not heal this." was a clock claim printed under every rung and false for the rungs whose derive re-arms on its own. The nondeterministic rungs (ground-replayed-misaligned, ground-replayed-nondeterministic, ground-digest-nondeterministic, nondeterministic) close with "Re-requesting does not change this; the recipe itself needs a change." The re-arming rungs name the condition the code proves and no clock word — ground-digest-divergence: "The ground this player sampled is not the ground the mesh was built on; this player re-checks when its ground or the object's anchor changes; nothing to re-request."; legacy-ground: "This recipe holds no record of the ground the mesh was built on; this player re-checks when its ground or the object's anchor changes; nothing to re-request."; script-skew: "This player's generator script is not the one the mesh was built with; this player re-checks when that script changes or the object is saved again; nothing to re-request." No rung promises it clears: the re-run's inputs are proven to re-arm, its MATCH is not (a mint sampled against ground that no longer exists on this player stalls for good — ledger 2712). Body headroom for the entity id is 61 chars under the longest rung sentence (16-char signatures); a longer id loses the closing sentence's tail first, never the fact pair. Pinned per rung in engine-diagnostics.test.ts.
  • One mesh, one DM (ravi's read, folded): the flavour's own code gave one incident two DM episodes — the renderer's bespoke-geometry-underivable wait for a mesh, then the ingest's bespoke-geometry-derive-mismatch verdict for the same mesh. The two codes are now a DM mesh family: inside the live episode the error-class first-occurrence DM dedupes by the row's entityId, so a mesh already told under either code is not told again under the other; the later verdict supersedes in the runtime log (both rows land), never in the DM lane. A different mesh under the second code is a new incident and still takes that code's one delivery; the per-code storm count is untouched. Pinned red-first in engine-diagnostics.test.ts (both orders).
  • Data shape note: the emitter writes ten data entries and the runtime worker stamps two more (specRevision, specDbVersion), so the row arrives at the server's twelve-entry cap exactly — one more fact would silently drop specDbVersion.
  • A destroyed static's colliders stay solid while a static mesh in its place is still cooking (ledger 3059 — Veilhunt, medivhus: an eight-minute fall under a whole-list bake). Ledger 1642's rule ("never trade a collider for a hole") is per entity: getOrCreateHandle and the static sync keep a REALIZED static's stale colliders while its OWN replacement mesh resolves. A spec apply can move the floor across entities instead — updatePlace('lobby', { objects }) rewrote lobby-shell from a root with 21 primitive children (the floor was child lobby-shell-floor, physics static/box) to one root with model: <GLB> + physics { body: static, collider: mesh } and no children. The apply destroyed the box floor at once and the root's trimesh existed only after the client fetched and cooked the GLB; with terrain off and no world bounds the player under it fell for eight minutes to y −2.2 million. The rapier cleanup drain (bodies.ts cleanupRemovedPhysicsEntities) now carries the cross-entity half: PhysicsBodyConfig add/set edges feed a per-runtime watch (PhysicsRuntime.staticHold) of static mesh-kind configs in the drain's place with no realized body (geometry unresolved, or resolved but no handle carries the config's signature yet — the pre-step static sync runs before the drain, so the two agree within a tick except when realization itself failed, which reads as pending on purpose). When the drain retires a solid (fixed, non-sensor, no controller) static whose entity died or lost its config while that watch is non-empty, the body and colliders stay in the wasm world as a tomb, unmapped from colliderToEntity — a raycast that lands on it reports entityId: null, like the broad-phase sentinels (2970), and the character controller stands on it with no groundEntity. The tomb releases the tick every watched mesh realizes or leaves the world, or at a deadline of STATIC_HOLD_MAX_SECONDS (15 s, the same window the unrealized-mesh verdict treats as planned cook latency); colliderSetEpoch bumps at release so resting controllers wake exactly as a dispose wakes them. A mesh pending for longer than that window earns no hold (the watch ages entries out), so a permanently unrealizable model does not make later deletions sticky; a static removed with nothing pending disposes on the next tick exactly as before; sensor statics and place moves never hold; disposePhysicsRuntime releases every tomb. Pinned red-first in engine/physics/__tests__/static-hold-cross-entity.test.ts: a resting body over a destroyed box floor falls within three ticks without the hold, keeps its ground through a two-second pending window, the swap, and the deadline with it; the nothing-pending deletion, the aged-out watch, the two-step (root first, child seconds later) swap, the sensor exclusion and the runtime dispose are pinned beside it. Product receipt on a second stack (terrain-off place, box floor child under a root, standing player, the whole-list updatePlace to a GLB root with a mesh collider, the GLB and its cooked collider held 6 s at the network): the player's feet stayed at 0.01 through the whole pending window and landed on the crate's top when the trimesh realized 12 s later, in five of five instrumented runs; one earlier uninstrumented run on the same bytes fell about ten ticks after the swap with the hold engaged, a mechanism this landing does not name — noted as open, not closed. Mantle is not mirrored: its cleanup sweep (cleanupRemovedMantleEntities) is a separate seam, and rapier is the default. Not changed: out-of-bounds.ts defaults and worldBounds wording (a held decision on this row). The two console lines the hold writes (the sim realm's console ring rides Savi's read_client_logs and engine-bug dumps) are ravi's sentences: on hold, [physics/static-hold] The removed object stays solid until its replacement model loads (at most 15 s). Nothing needs changing.; on release before the deadline, [physics/static-hold] The removed object let go: its replacement is in place.; at the deadline, [physics/static-hold] The removed object let go after 15 s and its replacement has not loaded; the ground there is open until it does. Entity ids, collider counts, the pending ids and the ticks ride the log's data object, never the prose. The deadline line says "has not loaded", never "failed": the release path knows only that the deadline passed — collider-assets keeps its terminal-fetch verdict private and its per-entity failed status is also written for transient fetch errors that retry — so it cannot prove a failed load. The test pins the three sentences whole and the absence of component words (shell, booth, host, relay, renderer, collider, tomb, tick, static, cook, failed) from the prose.
  • An api.on ear dies with the behavior instance that armed it, on every machine that holds a copy, and a stale ear never runs (ledger 2624 — the graveyard-manager filing and its 08-29 double-delivery mirror). Event subscriptions, script-armed timers and schedule-override slots are local closures on the machine whose hooks armed them; nothing replicates them. The rebind sweep's atomic unit (tome/interpreter.ts teardownAndRerunOnSpawn) skipped the whole step on a client-auth OBSERVER — "an observer neither re-runs the hook nor tears down" — on the assumption that hooks never ran there. In a dev room the host seat moves between the creator's tab and Savi's builder shell, so a seat that hosted earlier holds wiring for every entity it simulated. A behavior detached (spec row behavior: [], api.removeBehavior) while the OTHER seat hosted left this seat's ears standing, silenced only by the simulator gate; the moment hosting returned they ran again, and emits advanced the state of an entity whose spec said it had no behavior. The same skip under a script EDIT left the old ear beside the one the recompiled module re-armed after regain — every emit handled twice, and the fault floor stays silent by design when a current-generation ear exists. Two halves. (1) The teardown now runs on every world, observers included: the scoped clear of subscriptions (with tombstones), script timers and override slots for the dying refs happens before the execution-authority gate; only the onSpawn re-run and the owned-child reconcile stay with the simulating seat, exactly as before. Unedited entities are never visited by the sweep, so an unedited ear still rides out a handoff and hears again on regain. (2) tome/systems/event-dispatch.ts: a subscription carrying staleGeneration is REFUSED — verdict "stale", handler never called — instead of delivered-then-faulted. It stays in its bucket so the stale-subscription fault floor keeps its loudness (one fault per (entity, script, event), re-raised per apply epoch), and its accounting is unchanged: stale beside a current ear stays silent, stale alone faults. The one pin that recorded the old "old closure still fires once" contract (rebind-sweep.test.ts, the rowless legacy dynamic) moves to the refusal. Red-first pins in ear-lifetime-detach.test.ts: the observer-window detach (parent: three emits after behavior: [] moved the state), the observer-window edit (parent: one emit handled twice after regain), stale-beside-fresh and stale-alone refusal (parent: the stale closure ran), plus the server-lane detach controls (green both sides) and the unedited-entity control. Named residue, not changed here: a seat that regains hosting after an edit landed while it observed has no re-run of the new onSpawn on that seat (nothing re-arms on host adoption; the deferred-onSpawn drain only covers first materialization), so onSpawn-armed ears are deaf there until a re-save or a rejoin — the tombstone fault makes that loud. That gap predates this change (an entity spawned during another seat's tenure has the same shape) and is a host-handoff ruling, not an ear-lifetime one. The tombstone fault tells the truth about why the ear is missing (review 72acc7e0). With the observer-side teardown in place, that residue routed into the WRONG fault: the tombstone sentence told the regained host the ears "were wired outside onSpawn … a plain re-save does not re-arm them — move the wiring into onSpawn, or reset the guard state", when the ear WAS in onSpawn and one plain re-save on the regained host does re-arm it (the reviewer's probe: drops 1→2 with the new marker after one save) — a cure that fails when followed, the exact trust bug the fault floor exists to kill. A tombstone now records WHY the ear is still missing (TomeSubscriptionTombstone.cause, tome/resources.ts), decided at teardown from the ear's own provenance (TomeEventSubscription.armedInOnSpawn) and this seat's execution authority: "handoff" for an onSpawn-armed ear cleared on a seat that did not simulate the entity (no re-run followed here; the wiring is right), "wiring" for everything else (armed outside onSpawn — class (c) — or cleared on the simulating seat, whose own re-run follows). Dispatch (raiseTombstoneSubscriptionFault) speaks one sentence per cause; the handoff one, ravi's words: event '<name>' has no live ears on this entity, but scripts/<ref> used to listen for it — these ears were cleared by a host handoff, not by the script — the wiring is right. Re-saving the script re-arms them. It names the re-save only: a rejoin re-arms the ear only when this seat hosts, or nothing does, at the moment the spec lands (dispatchSpawnObjectOnSpawn RUN/DEFER); a fresh seat that lands the spec while another seat's host row stands takes SKIP and nothing re-runs onSpawn on the later adoption — pinned as three rejoin shapes. A handoff tombstone that survives this seat's OWN later re-run (the handler is gone from the script, or arms conditionally) upgrades to "wiring" in teardownAndRerunOnSpawn, so the failed cure is never repeated. Red-first pins in ear-lifetime-detach.test.ts: the onSpawn ear edited while observing faults with the handoff sentence (parent: the guard cure) and one re-save re-arms it; the dropped-handler face upgrades after the host's own re-save (parent: the guard cure both times); the update()-armed ear edited while observing gets the guard cure at once from its provenance, and the guard face on the simulating seat itself keeps its sentence unchanged. The tome.behavior.event_torn_down_subscription log row carries cause.
  • A place manager's first-tick spawns in a freshly minted instance land, on the host and on every peer (ledger 3094, WICKWORKS filing e2324b44). Two relay-tier mechanisms, measured in the host's own console (client dump bfbfb06c): the instance's rows materialize at t=0, a pending intent on the manager gets the sender-side unhosted verdict at t+82 ms, the manager's api.spawn warns place … is not resident at t+85 ms, and the election seats the player at t+240 ms. (1) The arriving player's own script patched the manager's state one tick after it materialized (a cross-writer guarded write); the guarded-write lease trigger (tome/sim-lease-write-claim.ts maybeClaimSimLeaseOnGuardedWrite) admitted the manager (behaviors + place membership + no owner) and filed a claim, the optimistic overlay read the manager as locally simulated BEFORE any seat existed, its parked onSpawn drained and its update() ran, every spawn inside warned, and the claim — which no machine could adjudicate (relay claims adjudicate at resolveRelayAuthorityClientId, null for an unhosted place) — was lost, dropping the window's spawns with it. On a relay wire the trigger now files no claim when the authority walk resolves nobody: the write rides the intent rail as an unclaimed write does, and the hooks wait for the seat like every other unhosted remainder. Kernel rooms are untouched (their server adjudicates every claim). (2) At the seat tick the uploader's claim bootstrap-adopt (runtime-client.ts publishClientAuthEnvelopeAfterCommit) jumped its cursor to the log END, discarding the first host tick's own writes with the previous authority's ingested rows: parked-onSpawn spawns were rescued by the spawn capture, update()-made creates were not — a permanent local-only ghost on the host, missing on every peer and on the next seat. The adopt now drains from the ingest/simulation boundary: noteClientAuthSeatEdgeBeforeSimulation flushes the pending writes at the start of the simulation phase on a tick whose host stamp key changed and records the log position; the adopt skips everything before it (ingest) and drains everything after it (this tick's simulation). Pins: engine/runtime/relay/__tests__/relay-instance-entry-first-tick-spawn.e2e.test.ts — with the hub held for five steps (the field's RTT) and the player's script writing to the manager, no claim files before the seat, the manager's onSpawn and first update() run at or after the seat step, no not resident warn is logged, and both the onSpawn spawn and the update() spawn stand on the host, on the observing shell, and in the journal (red before on each fix's own assertion); a control keeps the wide rule where an adjudicator exists (a second human's write to the seated instance's manager still files a claim). engine/runtime/client/client-auth-upload.test.ts sharpens the claim-adopt pin: the pre-claim rows (ticks 1–2) still never upload; the claim tick's own simulation write now does.
  • The GPU fx census now measures what the view draws, and the fill governor acts on that (ledger 2829). The GPU backend's census entry used to be an estimate: alive × folded spec-peak size² at the emitter ANCHOR's view depth, frustum-tested as a sphere of max(2, peak) m around the anchor. For a death-coupled smoke column (Summit Buddies' camp-fire, size: attr("size").mul(curve([0, 0.8], [1, 5.2])), ~130 puffs alive per fire) that read ~100% of frame and 3.1 raw screens per fire from 10 m — the real fill, Σ size² over the puffs' actual ages and depths, is ~0.3 screens — so two camp-fires floored the governor at ×0.60 for every particle in the game (render-harness fx-census-campfire-near: 6.41 raw screens, scale 0.600 on the old bytes; 0.61 raw screens, scale 1.000 now). The emit pass now folds each particle it keeps after the frustum cull — its PRE-governor shaded size over max(0.5, viewDepth) — into a new per-population Coverage atomic (FxGpuPopAtomic.Coverage, fixed point FX_GPU_COVERAGE_FIXED_SCALE, reset in beginFrame, read back with Alive); the split emit kernel binds popAtomics as its 8th storage buffer (binding 7 after the terrain pair, binding 5 without it — the WebGPU default limit, the fused family already had it). FxPopulationCensusEntry.viewCoverage carries the measurement; the store uses it verbatim (no anchor sphere test, no anchor depth clamp) and keeps the center/radius/Σsize² estimate only for entries without it (the CPU backend). A culled emitter contributes exactly zero; a column drawn above an off-screen fire still counts. The GPU census also skips a population whose latest readback predates its segment install (the refreshPopulationLight law) instead of reporting the previous tenant's alive count.
  • The fill budget is re-calibrated to the measured scale: FX_FILL_BUDGET_SCREENS 1.5 → 0.78. The 1.5 was set on the old anchor estimate (which read the 30-fire burning district bench-fire-village at ~2.9 raw screens and governed it at ×0.72); the honest meter reads the same district at 0.845–1.22 over its camera orbit (mean ~1.02), so at 1.5 the fire-overdraw class the governor exists to bound sat at ×1.000 — ungoverned. The budget is chosen from per-frame sweeps over 1800-frame runs of both specimen fixtures on real WebGPU, not a short read: the two camp-fires from 10 m (fx-census-campfire-near) peak at 0.656–0.723 raw screens per run at steady state (six sweeps; the peaks land 20–22 s in, and the longest excursion above 0.65 lasted 120 frames), so 0.78 — the worst peak + 8%, ~3.5 standard deviations above the mean peak — keeps them at exactly ×1 at every frame rate on the map itself. A first re-calibration to 0.65 leaned on a 20-frame read (peak 0.61) and sat inside that tail: the fixture still read ×1.000 because the governor's 0.002 snap epsilon at the harness's 60 fps absorbs a single-frame overshoot under ~6.5%, but the same series replayed at 30 fps eased under ×0.995 and put the governor line in the fx note; a second (0.72, from two sweeps) was crossed outright by the third sweep. At 0.78 the district is over budget at every azimuth and governed at ×~0.876 over the orbit (fill ×~0.77), ×0.80 at its fullest azimuth. The two classes sit only ×1.17 apart at the tails (0.723 vs 0.845), so a hard size budget takes ~23% off the district's fill before it touches the camp-fires; shrinking the district harder is a different actuator, not a lower number. bench-fire-village's assertScene records every window frame and pins the district governed on the window MEAN (over budget, under ×0.95, never floored); fx-census-campfire-near now runs the full 1800-frame sweep by default, records its window, and pins the camp-fires ungoverned and never over budget on any frame; fx-fill-governor.test.ts pins the separation and replays both measured sweeps (fx-fill-sweeps.ts) through the governor's law at 60/30/20 fps.
  • The reporter's other two readings did not reproduce as engine defects on the reporter's own scene (render-harness fixtures fx-census-campfire-far, -behind, -probability, real WebGPU): from 60 m the live view read the smoke at 4% and the governor at 1; behind the camera it read 0; stepping when(flame.dies, p) 0.3 → 0.16 → 0.07 by program update moved the smoke alive count 135 → 62 → 38, monotonic. The census is driven by the LIVE camera only (the particles contributor's compute fold) — a scene-view capture from an independent camera still reports the player's view in its fx note, and the note's alive is the 3-second windowed PEAK, not the instant; both are what the reporter measured from.
  • A bespoke-geometry wait's budget park is a quiet period, never a terminal state (ledger 2669). lume/primitives/geometry-wait.ts parks a draw/mesh pointer's wait after BESPOKE_GEOMETRY_MAX_REPORT_ATTEMPTS re-requests (~3 minutes, ledger #983), and on the previous version the park's only re-arm edges were a moved pointer, the geometry arriving, a tab return, a retracted sim verdict, or a channel rebuild. None of them fires when the world simply calms down, and the sim frees settled scripted geometry for a marker and re-derives it ONLY when the renderer asks (tome/systems/scripted-primitive-ingest.ts attemptDueEviction; ecs-sync.ts dropRecipeBackedBespokeWait clears the marker on a report) — so 78 kind:scripted meshes that spent their budget inside a dense scene (22k objects churning; the derive drain and the channel both saturated) stayed solid-but-invisible after the scene emptied to ~200 objects, fourteen minutes and counting, until a reload. Two edges close it. Pressure eased: sweep(nowMs, pressure) now carries the primitives store's record count (plain + bespoke, store.ts sweepBespokeGeometryWaits); a wait parked at pressure P re-arms when a later sample reads ≤ P × BESPOKE_GEOMETRY_PARK_PRESSURE_EASED_RATIO (0.5) and at least BESPOKE_GEOMETRY_PARK_PRESSURE_MIN_DROP (100) records lower. Backoff: with no other edge a budget park re-arms BESPOKE_GEOMETRY_PARK_REARM_BASE_MS (60 s) after it parked, doubling per park cycle to BESPOKE_GEOMETRY_PARK_REARM_MAX_MS (15 min) — a permanently stuck wait costs one report ladder per 15 minutes forever, instead of the post-#983 silence forever. A re-arm hands the wait a fresh report budget (the shape resume() already gives a tab return) and keeps its cycle count (BespokeGeometryStall.cycle, 1-based; a moved pointer starts at 1 again). A sim-verdict park (park(): stale-pointer, derive-mismatch, underivable) is exempt from both edges — the sim proved the world cannot produce the bytes; its retraction, a moved pointer, or a tab return stays that wait's edge — and a verdict landing on a budget-parked wait upgrades the park so the backoff stops re-arming it. store.ts logs one line per re-arm batch naming the reason (lastRearm: pressure pair or backoff). Reporting (renderer/bespoke-geometry-miss.ts): the per-entity bespoke-geometry-wait-parked console line fires at an entity's FIRST park only and quotes its re-arm clock; waits that park again after a re-armed budget aggregate into one line per sweep; the getLogs diagnostic bespoke-geometry-parked carries ravi's sentence (count and id are its only numbers; the exit named twice; no retry count, no clock, no don't-list) with the retry count and cycle on data. Pins: 7 red-first on the tracker (pressure edge, ratio + absolute floor, doubling backoff to the cap, verdict exemption, verdict upgrade, lastRearm, cycle reset on a moved pointer), 2 on the reporter (once-per-entity line + re-park aggregate; the getLogs sentence verbatim with the component/status/clock words pinned absent). Measurement aid under the existing resetprobe arm (renderer/render-stream-probe.ts): __spawnDropBespokeGeometryForProbe(true|false) makes the mesh handler discard incoming geometry/bespoke[-client] value rows as if the channel had lost them, so a real-browser session can drive the ladder to its park on demand; a production realm never carries the hook (same gate and reason as the poison probe).
  • A backoff re-arm is a re-ask, never an escalation request — the park clock cannot re-open the stream-reset heal. The sim's #818 escalation epoch (ecs-sync.ts BESPOKE_ESCALATION_EPOCH_GAP_SECONDS, 120 s) dies after two minutes of request silence, and once a wait's sim retransmits reach BESPOKE_REFORWARD_ESCALATION_PERIOD every renderer report was an escalation request. The tracker's cycle-2 backoff is 120 s plus the 2 s warn window, so the cycle-2 → cycle-3 wake arrived 122 s after the last request, opened a fresh epoch, and the epoch's reset despawned the pointer and re-created the wait at cycle 1 — for a mesh no recovery snapshot can land (the heal-exhausted class ledger #983 bounded), three whole-world resets and one bespoke-geometry-heal-exhausted DM every ~10 minutes forever. Every report now names what re-armed its cycle (BespokeGeometryStall.rearm, relayed on BespokeGeometryMiss: null for a first budget, else pressure / backoff / resume / unpark), and queueBespokeGeometryReforward treats a backoff report as a re-ask: it queues the plain live-value retransmit and never touches the escalation set, so the renderer's clock alone can no longer open an epoch. A pressure re-arm, a tab return, and a retracted verdict are changed causes and escalate like a fresh wait. Pins: the sim harness (a backoff re-ask after the gap → retransmit, no reset, across three backoff cycles; a pressure re-arm after the same silence → reset), the tracker × sim timeline over twenty minutes (exactly BESPOKE_ESCALATION_MAX_SNAPSHOTS resets, all in the first epoch, one fault, the cycle-3 wake pinned past the gap), the tracker's cause per re-arm edge, and the relay carrying it. The aggregated bespoke-geometry-parked diagnostic's data.cycle is now the batch's range (1-3) instead of the first report's cycle.
  • glb-bounds: a body that dies mid-read is a transient fetch failure, not a broken file. fetchPrefix classified a fetch() rejection as TransientJobError but let a body-read rejection that was not our own abort escape raw (undici's TypeError: terminated after a connection reset). With no tag, no status and no code, the harness settled it execution_error, BoundsPrefetchFeature read that as permanent, and the creator's DM said the file could not be read. The body-read failure now throws the same TransientJobError as the rejection beside it, so the feature's backoff ladder re-asks instead of latching a session give-up and a DM about a healthy model. Found in the landed look at ledger 3071's fix.
  • glb-bounds give-up sentences: the closing words (ledger 3071). The over-cap DM's unknown-total branch (a browser cannot read a cross-origin Content-Range; the byte-at-cap probe only proves the file is longer) said the limit as a bare number that read as the file's size — it now says "over the <cap> limit" and no other number; the known-total branch keeps the excess ("6 MB over the 100 MB limit"). The generic give-up (a permanent failure with no parser code) carried the ops cause in the creator's sentence — the code, the status, "not transient" — and the "try re-adding" move; it is now one sentence: the read failed in a way a retry will not change, the file itself was not judged, it is read again when the game next loads or when that model ref is replaced. The HTTP-dead 4xx (the dead set of isDeadAssetHttpStatus minus the auth pair — 5xx, 408/425/429 and 202 stay transient) has its own sentence: nothing is served at that model's address, so there was no file to read; check that model ref, or replace it. It does not say the model may still render, because the renderer's model leg asks the same address — both rails reduce a ref to the page origin's /cdn/ door, pinned side by side for the rooted, bare, first-party-absolute and external-host ref shapes. The ops cause stays in the warn line's data. Both tails are pinned from the bytes: the give-up set is in-memory system state on the world instance, and it is keyed by the model ref string, so a replaced ref is a fresh key the DrawModel set-hook seeds into the needs-scan in the same session (and the same ref re-added is not). One table pin walks every bounds DM: none names the failure class, a code, a status, "transient", or "re-adding"; the only digits are the ruled over-cap numbers and the transient floor's "about 20 minutes"; "may still render" appears on every row but the HTTP-dead one. This supersedes the earlier changeset's line that the HTTP-dead give-up keeps its sentence. Words: ravi's (02:04 and 02:21 PT 09-04).
  • glb-bounds: the over-cap refusal reads the served file, not the header's claim; a lying header is its own case. The header reader refused a JSON-length claim past the platform's model cap as glb_over_cap, and the creator's DM said the file was larger than the limit with a number computed from the claim. Every platform-served GLB passed a door that enforces the same cap, so on a served file that claim is a corrupt header far more often than a big file — and "a smaller export" sent the creator to shrink a file that was not too big. The job now asks the served file: the 206's Content-Range total where the runtime can read it (server-side), otherwise one byte at the cap offset (206 = longer than the cap, 416 = not). A file longer than the cap is glb_over_cap with details: { fileBytes?, capBytes } — fileBytes is the served total when known, never the claim. A claim past the cap on a file that is not is the new glb_header_mismatch, whose sentence is "its header does not match the file" with the re-export move. glb_truncated now says "the file ends before its header says it should" (it said "its JSON does not parse"). A non-transient failure with no parser code gets the generic give-up sentence instead of a "not a GLB" class no instrument showed. The re-export move belongs only to these parser-classed codes — a file verdict. The ten-transient floor's sentence now says the file could not be downloaded and was not judged, and that it is read again when the game next loads (the give-up set is in-memory system state on the world instance, so a new load re-seeds it); it names no file move. The HTTP-dead give-up keeps its sentence. Sentences per ravi's rulings (00:59 and 01:33 PT 09-04). Pins: bytes → code for every parser code; the code rides the wire as payload.code; the over-cap measure comes from the served total, never the claim; a lying header on a small file is never the over-cap sentence.
  • The glb-bounds header reader accepts any GLB the platform serves, and a refusal names its case. The reader's ceiling on the JSON chunk was a private 4 MiB. A valid Blender export — a 191-bone Rigify rig with 43 baked clips, ~24k accessors, a 5.2 MB JSON chunk that glTF-Transform, three r182 and this same parser all read — was refused there, the refusal carried no status and no code, BoundsPrefetchFeature classified it permanent, and the creator's DM said "malformed GLB bytes" (ledger 3071). The ceiling is now the platform's model upload cap, read from @spawn/tome-schemas/upload-size-caps — the same table kiln's ingest doors enforce, so the number a creator meets at upload and the number the engine names agree. Two fetches at most: the 64 KiB probe learns the header's exact JSON length; a claim past the cap is refused right there (no cap-sized fetch toward a body the platform could not have served); a claim under it is fetched once, to the byte. Every parser refusal now carries a code on the job wire (glb_over_cap with {requiredBytes, capBytes}, glb_not_glb, glb_not_json_chunk, glb_json_unparseable, glb_truncated), and the creator's DM is composed from the code — the fact the parser knows, then the one move that changes it — never from the parser's message, which stays in the ops warn line. HTTP refusals and the transient give-up keep their existing sentences.
  • A ctx.groundY / ctx.groundNormal mint that runs while the place's declared terrain is not installed on this realm PARKS instead of baking flat ground, and the park is bounded: the object re-mints on the first ground-redrape pass after the definition installs, and the park speaks one line (ledger 3068; two landings). createEntityGroundSampler read sampleReplicatedTerrainHeight's refusal (null, ledger 1773 — no definition installed for the place) as "ground at my feet": 0 in script units. The recorder taped the zeros, the mint stamped them, and every realm replayed the tape faithfully — a flat mesh, agreed on everywhere, wrong everywhere, and nothing re-minted it because the tape IS the derive cache. The null carries two meanings and only one is flat ground: when the spec declares no terrain for the place — or a heightmap/voxel terrain with no generator, which the installer never installs — 0 is the honest answer (unchanged; the skill's "on flat ground groundY is 0 everywhere" still holds); when the spec declares a terrain that would install and the definition is not installed on this realm, the sample is REFUSED like the unresolved-anchor sample (ledger 2770): the derive defers (no tape, no pointer, usesGround stamped) and the mint marks the entity parked. The first landing left the re-mint to the redrape system's key flip alone, and its first-sight arm ("the mint that produced the current geometry just sampled the current ground") is false for a parked mint — in the common runtime ordering (a behavior's enterPlace queues the place's re-apply for the spec-update system at sim order 150 and spawns a ground-following primitive into that place on the same tick; the redrape runs at order 122 every sixth tick) the install beat the watcher's first sight 5 ticks in 6 and a def-less runtime spawn stayed parked forever, invisible, with no verdict (review ee4d4232, probe P1). Now the redrape system re-mints a parked entity on the first pass that finds its definition installed, in either order (scripted-primitive-ground-redrape.ts; the park mark is opened and closed at the one mint door, mintScriptedPrimitiveRecipe). Spec-declared objects keep the spec-apply terrain pass. The park waits for an INSTALL, and only while the place still declares a terrain that would install (review 7b5c01fb): when the declaration stops — the creator sets terrain: null, removes the generator field, or the object moves to a place with no terrain — the redrape read "no definition" as "still waiting" and the parked object never built, while a fresh spawn in the same place minted flat; now the same pass re-mints it against flat ground ([0, 0, 0], the honest answer for a place with no terrain, byte-identical to that fresh spawn), exactly one generator run, the park mark cleared by the mint itself, no second log row. A park mark keyed by entity id still outlives a despawn until the next redrape prune (≤6 ticks); a same-id respawn that parks inside that window gets no verdict line (a despawn hook would need the transaction-overlay guard tracked-state carries, so it is left to the prune). A park writes ONE warn row into the runtime log Savi reads (getLogs), code scripted-ground-waits-for-terrain, beside the terrain's own compile error when there is one: [Tome] scripted geometry (<script>): this object's shape reads the ground, and place "<place>" has no terrain to read right now, so the shape was not built — it renders nothing. It builds on its own once the terrain for "<place>" is ready; if that terrain has an error in these logs, fix the terrain first. — once per park, never per mint; wording: ravi's trailing read owed. The collider lane refuses the same way; when the geometry lane parked too, the re-mint's physics refresh rebuilds it (a collider()-only ground read with a ground-free geometry() still waits for the next physics pass — unchanged from the first landing). Pins in ground-derive-before-terrain-install.test.ts: declared-but-uninstalled mint → no [0,0,0] tape, no pointer; parked behind a generator that does not compile, then terrain: null / the generator removed / moved to a no-terrain place → flat mint on the next pass, one run, park closed, no second row; install after first sight → re-mint byte-identical to a builder that minted with the terrain installed; install BEFORE first sight → the mesh appears on the next redrape pass with exactly one generator run; the enterPlace + same-tick spawn ordering through the spec-update drain; the verdict line's sentence, count, and absence of component words; a generator-less heightmap keeps flat 0. What this does NOT explain: the incident's own derive-mismatch verdict (Savi filing b8a6cdac, Hoverline, engine 5.2.40) — the reporter's recipes carried 8- and 19-float tapes (well under the cap), so the joining client's ingest derive replayed the writer's samples and never read its own terrain; a cold apply of the reporter's spec on server and client worlds minted byte-identical tapes and pointers with the terrain installed first; and the boot-time "no definition installed" warn fires once on both realms from the first expansion pass (spline lowering before the terrain pass, healed by the re-expansion), so it cannot discriminate this class. No prod instance of a zero tape has been shown: the class is closed from the bytes, the incident's cause stays open.
  • The host tick-beat is withheld while the client's own ingest position reads far behind (ledger 2622, the engine belt — Pixel Nations Football 08-23). The beat proves "my sim advances"; the election reads it as "this client can host" (relay-place-elect's tick-liveness overlay, residents first). The field specimen split the two: a desktop tab parked for ~38 minutes kept its socket live and queued 78k relay rows ([relay-ws] ingest meter … queueDepth=70047 → 78408, journal rows never shed by design) while the spec lane — heartbeat pointer → HTTP fetch → one spec-sync tick — kept its version stamp at head. At resume the whole backlog replayed at "live" phase; the tab beat on its first drain tick, out-ranked the standing host-session as a resident ([relay-elect] host(main) -> 5016295e … was host-session), took the seat mid-replay, accepted and re-ran 45 of Savi's 14:01–14:34Z execs against a 38-minute-old world (the exec deadline is minted at accept), and restated the place from that mirror — the 14:40 world reset (516 tombs, 272 recreates). Now netcode/ingress reads the position fact back from the transport right after it reports the applied head (ClientNetcodeTransport.relayIngestPosition, the fact ledger 3052 put on identify/look results) and hands its own farBehind verdict to the beat driver (RelayHostTickBeatFn.ingestFarBehind); relay-tome-wiring skips the beacon while it holds. No new number: farBehind is the instrument's existing reading — the transport queue plus the deferred carry at the ingest confession's backpressure line (2,048 rows, one relay journal self-compaction window), or the oldest un-applied row waiting ~10 s. Skipped, not refused — the beacon's interval clock does not advance, so the tick the position reads current again beats at once and the seat moves honestly. Under the 15 s liveness window a young burst this deep costs at most a few withheld ticks, never a seat; a sustained backlog leaves the seat with whoever is current (the standing shell, or nobody — the place freezes rather than being simulated from stale state). Red-first pin netcode-host-tick-backlog.test.ts (parent: the beat fires on tick 1 over a 2,314-row carry — the specimen's shape; fixed: withheld while far behind, returns the tick the position reads current; a deferring-but-not-far-behind burst beats on tick 1 as before). The position read-back crosses the worker's transport wrapper (MultiplayerDebugTransport, the one object the runtime worker hands netcode), which forwards relayIngestPosition like every other relay seam — the first landing omitted that pass-through, so the gate read undefined on every real session and a tab 7,900 rows behind still beat 68 ms after resume (tide-box receipt, 09-03); the wrapper's seam-enumeration pin now names the seam.
  • The wrapper's seam list is derived from the transport contract, so this class cannot ship silently again. MULTIPLAYER_DEBUG_TRANSPORT_SEAMS classifies every optional method of ClientNetcodeTransport (satisfies Record<ClientNetcodeTransportOptionalSeam, …>, the seam union derived from the contract type), the constructor binds every "forwarded" seam in one loop, and the seam pin in multiplayer-debug.test.ts walks the table instead of a hand-kept list — a new optional transport method fails to compile at the wrapper until it is placed, and placed as forwarded it forwards with no further code. The host-tick pin runs every case in both mounts (bare, and through the wrapper the way the worker mounts it). The table surfaced four more seams the wrapper never forwarded (relayWorldSyncLiveMember, relayMemberHidden, relayFoldFingerprint, relayRequestPresenceRestate — netcode reads all four through the transport, so none has run on a real session); they are classified "held" and pinned as not-exposed, each to turn on in its own landing with product evidence, never silently.
  • identify_object and look results carry the answering client's ingest position — received vs applied (ledger 3052; the 2693 specimen). Savi asked the creator's tab whether a sign existed. The tab's socket had received the host's spawn 33,021 rows earlier and its sim had not applied it ([relay-ws] ingest meter … queueDepth=33021, "relay ingest backpressured … rows queued behind the sim"); identify answered NOT FOUND from the live render stores with no qualifier, and an engine fault was filed for a sign that existed. The relay session's cursor (lastSeenSeq) advances at socket receipt while the world applies rows from the netcode's budgeted drain, and no read surface carried the second number. New tome/relay-ingest-position.ts: the netcode ingress system reports the highest applied relay.peer.frame seq and its deferred carry to the transport every drain tick (ClientNetcodeTransport.noteRelayIngressApplied); ClientRoomRuntime.relayIngestPosition() folds it with the transport queue into { receivedSeq, appliedSeq, queuedRows, deferredRows, oldestQueuedForMs }; the runtime worker answers it over the sim debug rail (relay.ingestPosition), and scene-identify.ts / scene-view.ts stamp every result with the derived report as ingest. Two verdicts ride the numbers: behind (the sim's drain deferred rows, or the oldest queued row has waited ≥ 100 ms — a healthy between-ticks queue is not behind) and farBehind (the queue is at the ingest confession's 2,048-row backpressure line, or the oldest row has waited ≥ 10 s — the reload tail). Rows are the unit; ms are receipt-clock (rows carry no room clock). Absent off the relay wire and on engines predating the field. Pins: relay-ingest-position.test.ts (verdicts, the 2693 depth, the sanitizer, the mirrored constant), room-runtime.test.ts (received advances at receipt, applied waits for the sim's report, the carry counts as queued), netcode-ingress-budget.test.ts (the per-tick report with a deferred carry).
  • The integrated-desktop shadow floor is a cap, not an assignment (applyDeviceShadowTier in both twins: renderer/lighting-quality.ts and lume/lighting/quality.ts). resolveShadowFloor answers "medium" for every confirmed integrated desktop (Apple, Intel, Qualcomm, ARM, AMD APU), and the fold used to ASSIGN medium's shadow rows to whatever tier the session resolved. The floor shipped as a cost cut when integrated desktops always resolved high/ultra; the gpu-bench verdict now sets low as the base tier on most Intel desktops, so the same fold raised a low session from low's rows (one 1024 sun map to 60 m, no local atlas) to medium's (two 1024 cascades to 100 m, a 2048 atlas, 8 shadowed locals, 2 atlas renders per frame). "single-sun" and "medium" now compare the resolved tier's rank against the donor's: at or below the donor the config passes through by reference; above it the donor's sun + atlas (+ local map size) rows replace the tier's own, exactly as before. "off" stays unconditional. Pinned by renderer/__tests__/lighting-quality-shadow-floor.test.ts, the tier-override suite (bench low / medium / ultra on an Intel desktop; bench medium on a discrete desktop unchanged), and the lume quality suite.
  • A cross-writer intent whose value fails the per-intent 64 KiB / depth-8 wall is now answered on the relay tier instead of dropped in silence. translateRailIntent (relay-peer-apply) returned [] on the parse refusal ahead of its refuse() path — the one silent path under its own "EVERY PATH ANSWERS" header — so the sender learned nothing until the 150-tick verdict-silence sweep synthesized timeout and its optimistic preview reverted ~5 s later. The parser (parseClientAuthIntentWireVerdict) now reports which wall fell (value_too_large / value_too_deep, two new ClientAuthIntentDropCode words), what the value measured, the cap, and the target id it read; the target's simulator answers that code on the intent.verdict broadcast with measured / cap beside it (additive fields; the kernel server's door keeps bad_payload). The sender's translateIntentVerdict folds the pair into the cmd.err control's new optional bound, the pending buffer carries it on the drop verdict, and the EXISTING per-ref revert fires on the verdict's arrival — one RTT, not tick 150. The revert also hands the two wall codes to a new told-failure door (confessClientAuthIntentValueWall): one episode-bounded runtime-log row per (target, code) on the writer's ring — getLogs and run_script's returned logs — stating the fact and the move; every other drop code leaves the revert as the whole told-failure, as before. The adjudicator's console line names the sender, the target, the measured number and the cap. A payload whose target id does not read still returns [] (no seat can know it adjudicates). The wall itself is unchanged; the walk now finishes the payload (one linear pass over bytes the command lane already bounded) so the refusal can carry the number.
  • A look frame miss carries the asked client's ingest position (ledger 3052 follow-up). The view_live_scene client RPC threw Object "x" not found — no entity with this id exists in the rendered scene. as an error, and a thrown error crosses the client RPC as its message alone (spawn.ts posts { message }; kiln's client-rpc-handler rebuilds new Error(message) and forwards { message }), so the ingest stamp landed on results only and the chat tool ran a second identify probe on the same client just to learn whether the screen was behind. Now that one miss returns as a RESULT: { ok: false, reason: "not-in-scene", error, ingest? } — the sentence byte-identical, ingest the same RelayIngestPositionReport the success result carries, read from the same rail in the same breath; absent off the relay wire (container tier) and on mounts with no runtime-worker rail. The worker classes the miss (SceneViewWorkerResult failure arm gains reason?: "not-in-scene", set by resolveLumeSceneViewPose only when the renderer knows no entity by that id — still and burst paths alike); every other capture failure (entity exists but renders nothing, hidden tab, device lost, …) stays unclassed and throws as before. Pins: scene-view-frame-miss-ingest.test.ts (behind → ingest.behind: true; current → ingest present, behind: false; no position / no rail → no ingest; no digit of the position in the sentence; two positive controls that the other failures still throw), scene-view-2d / scene-view-rig (the worker miss carries reason; the entity-exists misses do not).
  • One acceptance gate per creator-number boundary (lume audit #13001, group numeric-gates; Jacob's fix wave, 2026-08-16). Three renderer boundaries where an untyped script value became geometry or uniform bytes each gain one gate, and the generators and uniform writers behind them trust their inputs. lume/primitives/accept.ts is now the one acceptance gate for draw/primitive values (supportedPrimitiveFrom moved there; geometry.ts re-exports it, so store.ts / scripted.ts / preview-booth.ts all enter through it). Its law: a NON-FINITE number reads as absent so the kind's own default applies; a FINITE out-of-domain number clamps to its domain edge — dimensions to MIN_PRIMITIVE_DIMENSION (1e-6, the floor normalize.ts already routes to authored geometry), collapsible radii to 0, counts into [1, ceiling]: MAX_PRIMITIVE_SEGMENTS 256 per axis, MAX_BOX_SEGMENTS 128, MAX_POLYHEDRON_DETAIL 32, MAX_BEVEL_SEGMENTS 16; point lists decimate to MAX_PRIMITIVE_POINTS 512 (first + last kept), tube paths cap at MAX_TUBE_POINTS 8192, non-finite tuples drop, a lathe with fewer than 2 profile points renders nothing, torusKnot p = 0 drops. Wall dims and holes are gated here too, and createWallGeometry's own floors and per-hole isFinite guard are deleted. Clean values return the same object (signature dedupe stays byte-identical). New warning-class diagnostic primitives-value-degraded (tome/engine-diagnostics.ts), once per (kind, field, action). On master before this: a NaN sphere radius built NaN positions with a -Infinity footOffset (the GPU cull dropped it — invisible, no signal), a one-point lathe and a NaN tube point threw TypeError inside the generator, and a 1e6-segment sphere was accepted whole. terrain/decorations-sanitize.ts gains sanitizeItemNumerics: height/width/scale must be finite non-negative [min, max] pairs bounded to DECORATION_MAX_SETTINGS_DISTANCE_METERS (2048 — finite inputs overflow the radius arithmetic, (1e308 + 1e308) * 0.5 is Infinity), sprite anchor and sink take the same bound, weight/alphaTest/maxDistance/terrainPatternStrength/maxWaterDepth must be finite; a bad field drops to the kind default with a warn naming the path and the item keeps rendering. Numerics run before the per-kind contract check; seed is never touched (it is the scripted derived-mesh key's identity). Every factor of the card/primitive/scripted bounding radius is now ≤ 2048 or f32 vertex data, so registerPacked's finite-radius contract cannot throw for a decoration entry — the six-buffer-per-frame leak behind that throw has no precondition. The four decoration item schemas in @spawn/tome-schemas take z.number().finite() tuples so assertMergedTerrainDecorationsValid rejects at authoring time. shade/material.ts: the static fields (color, emissive, roughness, metalness, emissiveIntensity, opacity, transmission, toonSteps, alphaTest) are coercing accessors — color/emissive accept a Color-like {r, g, b}, an sRGB hex number, "#rrggbb", or an [r, g, b] tuple (per-channel finite fallback); scalars Number()-coerce with the field default as fallback. A value the setter cannot read as authored (a ShadeNode on color, "abc" on opacity) reports once per (field, shape) on shader-vocabulary-unknown-symbol. On master m.color = new Color(0xff0000) in a material script reached writeStatic as an object and threw lume: static field 'color' takes 3 float(s), got undefined after the record's uniform buffer was minted — one orphaned buffer per attempt, no record ever built. compat/three.ts derives its supported-prop vocabulary from the prototype setters too. docs/lume-architecture.md states the gate law. Pins: primitives/__tests__/accept.test.ts (70), terrain/__tests__/decorations-sanitize.test.ts "numeric item fields" (5 cells red on master), materials/__tests__/static-field-coercion.test.ts (the acquire ×5 → one record, one buffer), tome-schemas/src/__tests__/decoration-finite-tuples.test.ts. Verified in the running product: a spec carrying a 1e6-segment sphere, a one-point lathe, a NaN tube point (written by a behavior), a 1e308 grass height tuple, and two boxes wearing a m.color = new Color(...) material — every gate reported once, the orange boxes drew, the grass drew, no frame died.
  • A parked adjudicator's verdict silence now names itself on real sessions. The target_parked word (the verdict-silence sweep in relay-peer-apply.ts reading the adjudicator's folded visibility fact at the deadline) read that fact through the transport port relayMemberHidden, and the worker's transport wrapper MultiplayerDebugTransport never forwarded that port — so on every browser the sweep's adjudicatorParked read was undefined and every silence kept the timeout word, while the harness pins (which bypass the wrapper) said target_parked. Production over the seven days before this landing: 202 sessions logged synthesized a timeout verdict, none logged target_parked. The seam is now forwarded; the sweep, its 150-tick clock, the group abort and the confession row are unchanged — only the code and the confession's cause sentence change when the adjudicator's tab is hidden.
  • A parked see-through scripted material never occludes — and costs no draw (ledger 3040; Savi filing a5eba024, engine 5.2.39). The frame-budget guard parks a scripted material by having its build return null, and the wearer lands on the batched Std/PBR lane wearing only the intent's overrides. For an additive haze shell around a planet (a sphere just larger than the planet, no overrides) that fallback was an opaque, shadow-casting gray ball; the whole planet vanished inside it on the creator's phone until frames recovered. The runtime now records what each script declared on the material it returned (transparent, blending, static opacity, whether an opacityNode drives alpha), keyed by ref AND params (ctx.constants / structural ctx.params reads make one source declare differently per mode — a ref-only key was last-build-wins, and ghost-then-solid parked the ghost to the solid's opaque slab), at the current source hash, read at build time before the intent's overrides apply. The parked fallback (parkedScriptedMaterialFallback) reads it per intent: an opaque script keeps today's plain slab; a normal-blend static opacity rides the transparent lane at that opacity (no depth write, no shadow cast); a blend no slab can stand in for — additive/multiply/subtractive, or per-fragment opacityNode alpha — is HELD AND NOT DRAWN. That is a real representation, not an opacity-0 slab: the transparent lane's fragment shader runs the whole lit path and multiplies alpha last, back faces then front faces, so an opacity-0 shell cost about what the live haze cost and the park delivered no relief. Primitive lanes and oversized pools gain a per-slot draw bit (SlotRecord.drawn, PrimitiveLane.writeDrawn) independent of the entity's visibility bit: a slot with it off enters no cull bounds, no draw-set membership and no shadow list, while picks, world bounds and the outline mask still answer for it (pickability tracks geometry, never the material binding — ledger 1201). Primitives, oversized pools and bespoke parts all write it from one verdict on every representation sync, so the un-park sweep and a re-park land the right bit; the un-park hands the body back to the scripted lane as before. primitiveDrawSuppression gains scripted-material-parked (script names the ref), checked before the draw-set read so a parked body never wears ledger 3012's "renderer state, nothing the creator built is at fault" verdict; the frame caption stays silent for it (the sentence is owed, held with #14211). Red-first pins: scripted-material.test.ts (the fallback verdict per declaration; the two-order per-params pin — solid→ghost and ghost→solid both take their own fallback; an edit drops every mode's declaration) and store.test.ts (the haze shell is held with drawn false, out of the draw set after the membership settles, bounds radius −1, no shadow position, still ray-pickable with bounds, verdict scripted-material-parked; the opaque sibling keeps its drawn opaque slab; a 0.4 normal-blend glass draws a transparent slab at 0.4; the two-mode script parks each instance to its own fallback in either build order; a bespoke shell parks every part undrawn). Never-built refs and edited scripts keep the plain slab until a build runs. The model lanes' parked fallback (the model's own baked materials) is unchanged.
  • A peer's delete of an entity this seat once published never echoes back as this seat's own delete (ledger 2992 — the class beside #13986's ledger and #14022's reap-lane retire). The uploader's include filter (engine/runtime/client/runtime-client.ts getClientAuthUploadView) ships a dead row's delete through two memos: the simulated-despawn ledger ("did I kill it") and the published memo clientAuthPublishedEntityIds ("did I publish it"). #13986 guards the ledger by construction — a despawn that lands inside an ingestRoomDelta pass (room-delta-ingest.ts isIngestingRoomDelta) never enters it — but the published memo had no such guard. The memo is cleared only when this seat CLAIMS a place, never when it loses one, so an id a seat published as host and then stopped simulating stays memo'd until a live row for it drains, and a static entity has none. When the next host deleted it, the delete ingested here, the despawn landed inside the ingest (so the ledger refused it), and the include filter read !hasEntity && published.has(id) and shipped a delete row of its own: one redundant journal row and one fan-out frame per peer delete of a formerly-hosted entity, idempotent at the relay, authored by a seat that neither simulated nor killed it. Measured on the relay multi-client harness: B's delete journals at seq N, A's echo at seq N+1, both peers receive two delete frames. The kernel tier had the same shape one door over — a server kill of a host-simulated entity echoed upstream as the host's own delete, rejected by the server drain every time (client-auth-upload.test.ts pinned it as "redundant but bounded"). The cure is #14022's retire applied at the despawn instead of the drain: the uploader's despawn hook now retires an id from the published memo and both scope memos (clientAuthOwnEnvelopeIds, clientAuthRemainderPlaceByEntityId) when its despawn lands inside an ingest pass, so the change-log walk finds no memo to ride on. The peer's row is the journal's truth; this seat owes nothing. Untouched, and pinned as controls: a memo'd id that dies OUTSIDE an ingest (a script destroy, the interpreter's reconcile, on the host or on an ex-host) still ships its delete through the memo branch exactly as before; the seated host's own kill ships one delete through the ledger; a reap-lane tomb (api.destroy on a truth relay) keeps #14022's one-row shape; reset-sweep despawns retire ids the reset clears moments later anyway. Red-first on the production-parity relay harness (__tests__/relay-peer-delete-memo-echo.e2e.test.ts: A publishes as host, the seat moves to B, B deletes → exactly one delete row for the id at the hub, B's, and A puts no delete on the wire) and on the kernel-tier uploader pin (a server kill of a hosted entity → the host uploads no delete). Wire effect: one fewer journal row and one fewer fan-out frame per peer delete of a formerly-hosted entity on the relay tier; one fewer rejected upstream delete per server kill of a host-simulated entity on the kernel tier.
  • The perf-capsule zip runs in a dedicated worker, never on the iframe main thread (ledger 3077, God of Souls 09-04). Every bug-report press also captures a perf capsule in the background (the debug-dump rider). The capture fetched every session asset and then ran fflate's zipSync over the whole set on the iframe main thread (engine/client/capsule/capture-capsule.ts). On a 378 MB capsule (590 assets) on an Intel 12th-gen low-power CPU already at 79 % sim load that call held the main thread for ~90 s: no frame-loop post, no telemetry, no socket heartbeat. The parent page's tombstone sentinel (kiln tombstone-sentinel.ts, 60 s of silence) read it as a killed frame and raised "The game crashed. Reload to jump back in.", the relay closed the socket for missed heartbeats (4410), the chat side's eye ladder convicted the stale telemetry stamp and filed a second dump whose capture stalled the thread again, and the tester reloaded a game that had never crashed. Now capsule-zip-worker.ts (shipped as worker-capsule-zip.mjs in the split client build, spawned against the iframe document <base>) runs the same zipSync off-thread: capsule-zip-host.ts transfers every file buffer to a fresh worker (the main thread keeps no copy), takes the zipped bytes back by transfer, and owns the one lever that works from outside a thread — a wall-clock deadline (CAPSULE_ZIP_DEADLINE_MS, 5 min, inside the rider's 10 min listen) that terminate()s the worker and fails the capture with the deadline named; a worker that fails to load, errors, or whose zipSync throws (an allocation past the machine) fails the capture with that message. Failures stay console-only, as ruled ("if it finishes, it finishes; if not, it doesn't"); whether a press captures is unchanged. fflate leaves the main-thread capture chunk entirely. The existing one-background-capture-at-a-time guard in worker-browser-host.ts now does its job for a second press during a capture: the main thread is free to read the request while the first capture is in flight, so it is refused instead of queued behind a stall. Pins: a fake-worker suite for the host (transfer list, deadline terminate, late answer ignored, worker error, spawn failure) and a red-first capture pin in which fflate's zipSync throws when called in the capture realm — the previous version failed it with "zipSync ran on the capture thread". The capsule replay harness serves the new worker (WORKER_BUNDLES).
  • The perf rollup names the session's lighting tier, what set it, and the clustered-lighting row it landed on. Every 1 Hz renderer perf sample now carries a lighting block (tier, detected, source, clusteredTier, lightsPerCluster, shadowFloor), the sim worker's 15 s rollup forwards it (last sample wins), and the kiln route logs each field on the kiln.perf_rollup line beside gpu_vendor/gpu_class and the new governor_ladder/governor_rung/governor_bottom_rung fields. Before this, a plain identity-guess session logged no tier line anywhere (renderer init logs only the override, pin, player-perf, and bench cases), the tier lines that did exist lived in the browser-console lane where the rollup's GPU vendor could not join them, and ladder engagement on a per-app cut had to be inferred from render_scale. source is one of identity / bench / override / pin / player-perf, following the boot log lines' precedence (lightingTierSource). Structured values only, about 100 bytes per sample; no new log family and no monitor change.
  • Every place runtime steps exactly where this world's behaviour scheduler runs scripts, and the physics/step budget report names what the step actually simulated (ledger 2531). Three code-confirmed faces, class bound 5.2.13→5.2.31 across four apps. (3) features/PhysicsEngineFeature.ts: the occupancy gate that only the DEFAULT place read is now one predicate for every runtime (shouldStepPlace), tier by tier the scheduler's own scope (tome/simulation-authority.ts shouldSimulatePlaceHere, tome/systems/behavior-update.ts) — server-as-place-host reads the demand rule (tome/place-demand.ts: occupied ∨ builder window) for every held seat, so Savi building in an empty non-default place keeps it simulating exactly as the empty default place did; a relay-tier client steps a place when a session stands in it (SessionOwner replicates owner-only, so this is the local player's place), when it HOSTS the seat (the standing builder shell hosts every place no human holds; a tab client hosts the place it stands in), or when its locally controlled body is in it; a headless client harness (no local player, no session) steps every place unless it is a relay world before Ready, which steps nothing (the scheduler's pre-Ready guard, ledger 2557). Singleplayer steps EVERY place, the default place included: the local client runs hooks on every entity in every place (places never unload; the default-place pause reads a parity resource nothing writes), so a step gate that parks a place whose scripts still tick re-enters the inconsistency the March 2026 lazy-place revert (#5819, "behaviors and physics now run consistently across all places") removed — a kinematic mover driven by update() in a place the player is not in walked its replicated transform while its rapier body was never created, so anything riding it or colliding with it was missed until the player arrived and the bodies snapped; a spawner in an away place minted crates that froze mid-air and flung on entry. The unoccupied-place cost in singleplayer stays until scripts and physics learn to pause together (ledger 2990 option (a), pending a human word). A parked place still runs its removal cleanup, the path the parked default place always took; runtime creation, place materialization, and teardown are untouched. Duskfall's relay client stepped 12 unoccupied places. engine/features/terrain/terrain-systems-shared.ts: the chunk rescue judges only entities whose place stepped THIS tick (PlacePhysicsSteppedTickResource, stamped by the step in the same phase directly before it) — a parked place cannot have lost a body, and its terrain never streams while unoccupied, so the 2121+-fire rescue/remediation loop on four crypt NPCs from a relay client standing in main is unrepresentable. (1) tome/behavior-watchdog.ts PhysicsBodyCensus grows from dynamic/awake to static, kinematic (non-controller), character controllers, vehicles, places stepped this tick, live runtimes, substeps, and the sim dt; countSimulatedBodies fills it across both backends. The message now reads "on N dynamic, N static, N kinematic, N capsules; P places x S substeps" and the dynamic teach (~250/~400, despawn/pool) rides only a DOMINANT dynamic population (isDynamicDominantCensus: ≥ 100 and no smaller than the capsule and kinematic counts); otherwise the report says the cost is not a dynamic-body cost and names the populations that bill (kinematics re-sync every tick, capsules cast every substep). Both variants fit the 500-char rail with the consent rule intact at worst-case digits (pinned). (2) engine/physics/rapier/runtime.ts exports physicsSubstepCount(dt) — the one body the step and the census share. Code fact the row's face-2 arithmetic missed: both fixed-step loops (runtime-client.ts runOneStep, server-runtime.ts) hand physics dt = 1 / tickRate, so substeps are a constant per tick rate (2 at 30Hz, 1 at 60Hz), never the render frame's dt; the report carries substeps and dtMs so the multiplier is on the record instead of inferred. Red-first pins: engine/physics/__tests__/place-step-occupancy-gate.test.ts (singleplayer client steps every place — a dynamic prop in an away place falls, the default place keeps stepping after the player leaves it, a script-driven kinematic mover in an away place moves its rapier body; relay-tier client steps occupied ∨ hosted and parks the rest; a pre-Ready relay harness steps nothing; server-held non-default seat steps only while demanded), tome/__tests__/physics-step-watchdog.test.ts (a 747-static + 43-capsule + 0-dynamic census never gets the dynamic teach or "0 dynamic bodies"; the dominance rule). Existing pins that stepped a non-default place with no session now seat one (mantle-place integration, collider-gating, chunk-rescue's runRescue stamps the place as the step does).
  • placeStructure(template, pos) normalizes the creator's template object uncached (ledger 2808, follow-up to the #14403 identity memo). The identity memo on normalizeSerializedVoxelTemplate (features/terrain/voxel/template.ts) is keyed on the input object under the rule "spec objects are data, never mutated in place". That rule holds for the interpreter's callers (the marks and structures normalize and the bounds signature read spec.terrain.* objects, and patchTerrain clones every structure it adds), but not for the creator door: normalizeVoxelTemplateCandidate keyed on the creator's live script object, so placeStructure(wall, a); wall.palette = ["stone"]; wall.voxels.push(…); placeStructure(wall, b) stamped the first shape at b, and a rejected object the creator fixed in place stayed rejected. Savi's move is correct in standard JS, so the primitive is what moved: the creator door now calls the uncached normalize; the interpreter keeps the memoized export and its per-apply win (40 templates × 2,000 voxels re-apply, this box: 38.7 ms before, 39.7–42.7 ms after — one band). Pin in voxel-region-api.test.ts: place, edit palette and voxels in place, place again → the new shape; a rejected-then-fixed object is accepted on the next call. Red on the memo's bytes (expected 'glass' to be 'stone').
  • Pond bounds contain the pond's bank at every angle (ledger 3064). engine/features/terrain/marks.ts resolveMarkBounds expanded a pond by resolvePondLiquidEdge(1.15·R) + resolvePondShoreWidths(R).outer, while the apply (applyTerrainMarksToHeightInternal) reads the radius at the point — noise-widened up to POND_RADIUS_MAX_RATIO = 1.15·R — and sizes the shore from that same radius, so the bank reaches liquidEdge(1.15·R) + shoreWidths(1.15·R).outer. For R=10 the AABB was ±22 while the bank reaches 23.575 at the angles where the rim noise peaks near an axis: every gate that reads entry.bounds (the water-overlap count, the height apply, the material blend, the liquid sample) cut the bank there, leaving a thin flat sliver at its outer edge and, on the downhill side of a pond on a slope, a square-cornered end to the wall that holds the bank up to the water level. A later pond whose rim sample landed in that sliver resolved its level from the full bank while the gated query put no bank under its rim, so its water sat 11.5 cm off the ground it rests on (pond A R=10 at the origin, pond B R=6 at (28, 3.5), slope 0.55; the case ledger 3058's exactness claim missed). Bounds now use resolvePondShoreWidths(maxRadius). This is the one height change in the version that carries it, and it is confined to the sliver between the old AABB and the bank's true reach — measured against 5.2.40's bytes: on the A/B pair, 119 of 95,277 heights on a 0.25 m grid differ (max 7.1 cm), all in A's bank sliver, and A's and B's levels are identical (B: 22.730185580733725 on both; a sweep of 825 B positions changes it at 0) — the ground under B's rim rises to meet the level, the level does not move; Frontier Isles at spec versions 399 and 411 (10 ponds, R 45–70) moves 15 of 293,180 and 16 of 290,178 heights on a 6 m grid (max 14.3 cm), every one inside the old-to-new-bounds sliver of one of three ponds, with all water profiles, pond levels and 46,206 river-hugging samples unchanged; a single R=10 pond on a 0.55 slope moves 583 of 231,361 samples on a 0.125 m grid (max 12.9 cm, none outside the sliver, level unchanged); every mark kind overlapping on a hillside with two ponds moves 18 of 132,108 samples (max 2.3 cm); the same set without ponds is byte-identical (0 of 132,108), as are both non-pond golden fixtures on rolling ground (0 of 176,418). Where the sliver crosses the downhill wall, the wall's edge moves from the AABB to the bank curve and the delta is the wall's height (2.17 m at one sample on the overlapping-rivers fixture's field at 0.25 m, off-chunk). The golden chunk __tests__/fixtures/heightmap-build/marks-overlapping-rivers-lod0.json is recaptured: 4 of 16,641 heightfield samples (and 4 of 17,161 padded) move, max 5.6 mm, all at the tarn's bank edge 11.5 m from its center (chunk-local x=15.5, z=5.0–5.75); no other fixture moves. Pins in __tests__/marks-resolve-bounds.test.ts: on 720 rays with the gate removed, the farthest point a pond still moves lies inside its bounds (161 rays outside on the old bounds); gated and ungated apply agree on a 0.25 m grid around a pond on a slope (132 differed); a pond that follows a pond within its bank reach applies the earlier pond identically gated and ungated at every rim sample.
  • The preview booth's deadline verdict states the fact and the next move, and names no cause (ledger 2949, follow-up to the terminable-worker landing). The skip reason Savi reads for a generator the 5 s deadline stopped (scriptedGeometryDeadlineReason, _entry/client/object-preview.ts) used to say the generator "has a loop that never ends or work far past what a piece of geometry should cost" and told her to "fix the script". The host cannot make that diagnosis: it knows one fact — the call had not returned when the window closed — and a healthy generator on a starved device produces the same fact as a runaway one, so Savi relayed a cause the instrument never had. The sentence is now scripted geometry (<script>): geometry() did not finish within 5000 ms in the preview and was stopped — nothing rendered for this piece. Make geometry() finish well inside 5000 ms, then look again. Every clause holds on both branches of the world, the number is read from SCRIPTED_GEOMETRY_REALIZE_DEADLINE_MS (never hard-coded in the text), and "the preview" names her own call, not a component. A test pins the composed sentence and the absence of "loop", "never ends", and "fix the script". Nothing else moves: the worker, the deadline, the termination, and the per-look dedupe are unchanged.
  • The isolated preview booth draws a sign's board and names the text face as the half it does not draw (ledger 2693). resolvePreviewContent skipped every sign node as "text", so a sign-only object answered "Nothing in this object is previewable (every piece is text)" — which Savi read as "the board primitive from buildSignPrimitive never lands" and filed as a render bug (savi groups 0653dca8 + 48eac303, app a00242b7, 5.2.34). The sign vocabulary was never broken: the minimal { sign: { text: { content: "TEST" } } } derives DrawPrimitive + DrawText + TomeSignSpec on both realms at the 5.2.34 bytes and on master, replicates over the relay to a shell seat and an AOI browser seat, and renders in a real browser (board + "TEST"; identify_object finds it by point and by name). The creator's tab in the filing was 33k relay rows behind the room ([relay-ws] ingest meter … queueDepth=33021, the 2967/2774 ingest-backlog class), so a host-side spawn was not in that renderer yet when Savi looked. The booth now resolves a sign node through the engine's own derive (buildSignBoardPrimitive: normalizeSignSpec then the same box builder writeDrawSign runs — metrics, the authored board material, else the dark default panel) and counts the text face as a skipped piece: "rendered 1 of 2 pieces (1 skipped: sign text (shows in the scene, not in this preview))". A sign with no text skips as "sign without text"; a bare text node still skips as "text". Pins: the booth board (object-preview.test.ts), the minimal derive on both realms (sign-minimal-derive.test.ts), and the relay round trip on the filing's networking shape (relay-sign-minimal-reaches-every-seat.e2e.test.ts).
  • The preview booth realizes creator geometry generators in a terminable worker under a 5 s deadline, never on the iframe main thread (ledger 2949, Miscast dig dba2d751). look (target object → the preview_object client RPC) used to run realizeScriptedPrimitiveGeometry — and with it the creator's generator module, module-scope code included — synchronously on the iframe main thread (_entry/client/object-preview.ts). A generator that never returns cannot be stopped by anything in its own thread: the try/catch never runs, and the 2^28-iteration script loop budget (ledger 1328) never trips when the loop allocates per step, because the heap fills first — so each look at Miscast's dm-kirk-yard-geo.js (a for loop stepping the wrong way, allocating each step, called at module scope) froze the creator's tab until Chrome killed the frame; three of that evening's four tab deaths were looks. Now _entry/client/scripted-geometry-realize-worker.ts (shipped as worker-geometry-realize.mjs in the split client build, spawned against the iframe document <base>) runs the same one realization off-thread, and scripted-geometry-realize-host.ts owns the lever that works from outside: the deadline (SCRIPTED_GEOMETRY_REALIZE_DEADLINE_MS = 5000) is armed when a request reaches a READY worker (startup and queue time never count), an overrun terminate()s the worker, fails ONLY that request as deadline, and re-rides the queue on a fresh worker; a worker that does not start or errors fails what is waiting as retryable unavailable, never as the script's fault. The booth pre-realizes every scripted node of the hierarchy through the host (realizeScriptedPreviewNodes — deduped by script+params+seed, and a script ref the deadline already stopped is not run again for its other copies in the same look), then the synchronous piece walk looks the results up. The verdict Savi reads is a skip reason on the piece — scripted geometry (<script>: geometry() did not finish within 5000 ms and was stopped — nothing rendered for this piece; the generator has a loop that never ends or work far past what a piece of geometry should cost. Fix the script and look again) — carried in the perf line for a mixed hierarchy and in the error for an all-scripted one, so look returns instead of hanging. In-process tests and the derive-parity pins keep the in-thread realizer (realizeScriptedGeometryInThread); the live booth never uses it. The capsule harness serves the new worker (WORKER_BUNDLES) so the replay lane does not 404 it. Verified on a real stack in a real browser: with the Miscast loop shape as an inline object, the parent page's 50 ms heartbeat kept ticking through the 5 s, the look returned at 5001 ms with the verdict, a hierarchy carrying one healthy tower and two copies of the wedged script rendered the tower and named both copies in 5.6 s total, and the next healthy look after the termination rendered in under a second on the fresh worker. Not changed: the live derive (deriveScriptedPrimitiveGeometry on applySpec in the runtime worker) and run_script's require still evaluate creator code on the sim thread with only the loop budget between them and an allocating loop — the fourth Miscast death rode that path; and interpreter.ts's residency=null on clients (the singleplayer-mode whole-doc derive) stands as its own question.
  • The relay close registry mirror carries RELAY_CLOSE.joinFailed: 4414 (ledger 2622 — the relay half of the "frozen realm"). The relay now treats a join as atomic: a throw anywhere between admitting a socket to its subscriber table and finishing the join (a storage read in the catchup drain, a deflate, the attachment write) closes the socket 4414 "join did not complete; redial" and emits relay.join_failed, instead of escaping the handler — which left the socket open, subscribed and live:false for its whole life (heartbeats echoed, own writes acked, every fanned STATE/SPEC row parked server-side, so the session kept applying spec heads off the heartbeat pointer while no entity row ever arrived, and never redialed because acks and echoes are the two liveness signals it watches). No client handler changes: 4414 rides the default reconnect row of room-runtime's relay close table (which excludes only 1000 / room-full / 4431 / room-unpublished / 4412), so the fielded redial with backoff runs a fresh join. This row exists because the mirror's KEEP-IN-SYNC rule is "matching the relay's registry, not inventing one" — relay-wire-types.ts RELAY_CLOSE names every code the relay mints.
  • The renderer's bespoke-geometry cache survives a render-stream reset for the bodies the recovery snapshot re-points (ledger 3037 review, finding 2 on the pointer-hold re-land). With record-scoped retention, the STREAMRESET despawn-all (render-channel.ts finalizeDecodedFrame) retired every bespoke record and with it every cache entry. The recovery snapshot that follows carries a settled body's draw/mesh pointer but no geometry row once the sim's settled-geometry eviction has run (scripted-primitive-ingest.ts attemptDueEviction removes BespokeGeometry from the world), so on the previous version each evicted body missed, waited the two-second warn window, re-requested, and the sim re-derived and re-shipped its full bytes — every settled scripted body blinked for at least two seconds right after a channel collapse, and a world like TERRA's (256 chunks × ~500 KB) re-derived and re-shipped ~128 MB when the reader was already under pressure. Before the pointer-hold landing the insert-only cache survived a reset, so evicted bodies redrew at once; this restores that shape under retention. lume/primitives/store.ts: the reader's decoded STREAMRESET delta carries streamReset: true (render-op.ts), renderer.ts drainOps opens a reset grace on it (openBespokeGeometryResetGrace) before the handlers apply the despawn-all, and a record despawning under an open grace PARKS its three holds on the store (signature → owed release count) instead of releasing them. The snapshot's rows retain through the ordinary paths — a re-pointed evicted body hits the still-resident entry and draws with no wait — and the mesh handler's per-frame sweep (sweepBespokeGeometryResetGrace) closes the grace 30 s after the last reset (BESPOKE_GEOMETRY_RESET_GRACE_MS), releasing every parked hold exactly once so an entry no live record re-stated hits zero and is freed; nothing parked outlives the sweep, and one info line names how many entries went. A second reset inside the window keeps what is parked and restarts the clock. The census on the 1 Hz dump sample gains bespokeResetParked. The reader also gains poisonStreamForProbe(), installed on the worker global as __spawnPoisonRenderStreamForProbe only when the session is armed with the resetprobe render feature flag (?resetprobe=1, whitelisted in kiln; renderer/render-stream-probe.ts), so a real-browser probe can force the poison → reset → fresh-snapshot recovery; a production realm never carries the hook (scripted materials run inside the renderer worker, so an unconditional global would be a lever a material script could pull), and nothing in the product calls it. Parking is scoped to the reset frame's own collect (closeBespokeGeometryResetParking, the mesh handler after its ops): exactly the despawn-all parks, and a body destroyed on a later frame inside the window frees at once while the 30 s sweep runs on. Red-first pins on the store (reset → snapshot re-points → 0 waits and the entry held by the new record after the sweep; reset → snapshot omits → freed at the sweep; a double reset releases every parked hold exactly once; the census field) and on the reader (only the STREAMRESET delta carries the flag). Not changed: the writer's hold mirror still clears on a reset, so the recovery snapshot ships full bytes for the rows it carries (the reader dedups them against the resident entry by signature).
  • The sampled terrain-mark resolve gates prior marks by their bounds, so a cold resolve is linear in total river length instead of quadratic in the river count (ledger 3058). engine/features/terrain/marks.ts resolveTerrainMarkEntries resolves each river's water profile and each pond's level by applying every prior mark at three points per centerline sample (32 per pond rim) through applyTerrainMarksToHeightUpTo, which skips a mark whose bounds exclude the point — but entry.bounds was assigned only after that pass, so every prior river was projected onto (projectOntoPolyline → nearestSegmentOnGrid, which walks the whole polyline for a query far outside its grid) at every sample of every later river. Frontier Isles (5.2.38) measured in a headless build with the game's own generator: 63 rivers / 15.6 km → 9.6–10.8 s cold resolve; 23 rivers / 15.2 km → 4.6–5.2 s; 29 / 8.9 km → 3.2–3.8 s; 4 / 1.7 km → 0.16–0.2 s; 0 rivers → 84 ms; the CPU profile put 88% of the time in nearestSegmentOnGrid under the resolve. Every client chunk build ran past CLIENT_CHUNK_JOB_STUCK_TICKS and the creator's world rendered flat. Bounds are pure geometry (authored shape plus the centerline the geometry pass already resolved), so they now resolve before the sampled pass; the bounds themselves are the same. After: 63 rivers → 253 ms, 23 → 246 ms, 29 → 207 ms, 4 → 117 ms (≈84 ms + 11 ms per km, independent of the mark count). Heights: the gate is exact wherever a mark's bounds contain its full apply reach, and with this version's pond bounds (pond-bounds-contain-the-bank.md, ledger 3064) that holds for every kind, so the gated resolve reads the same ground the ungated resolve read. Against 5.2.40's bytes every river's water profile and every pond's level is unchanged: pond A R=10 at the origin with pond B R=6 at (28, 3.5) on a 0.55 slope — B's rim inside A's bank sliver, the adversarial case — resolves B's level to 22.730185580733725 on both versions and on the gated and the ungated resolve alike, and a sweep of 825 B positions changes it at 0; Frontier Isles at spec versions 399 and 411 (63 and 23 rivers, 10 ponds each) keeps all 86 water profiles, all 20 pond levels and all 46,206 river-hugging samples byte for byte. The reorder alone moves no height anywhere: with the bounds held at 5.2.40's, every mark kind overlapping on a hillside (132,108 grid samples), the three marks golden fixtures on rolling ground (222,594 samples) and the four Frontier Isles spec versions (1.08 M grid samples, 62 k river-bank samples, 119 water profiles, 40 pond levels) are byte-identical. The only height change in this version is the pond changeset's — the outer ring of a pond's bank near the axes, where the old bounds cut the bank — and it is described there. An intermediate state, the gate on with the old bounds, let a later pond's rim sample read the cut bank and moved B's level to 22.844735015515454 (+11.5 cm; 7 of 825 swept positions; 6,057 of 95,277 heights on a 0.25 m grid, max 2.05 m); that state sat between two landings of the same version and never minted. Pins: __tests__/fixtures/heightmap-build/marks-overlapping-rivers-lod0.json, a golden chunk build over crossing rivers, bank-hugging ponds and flattens captured on the pre-fix code (shrinking river bounds by 1.5 m fails it); __tests__/marks-resolve-bounds.test.ts — gated and ungated applyTerrainMarksToHeightUpTo agree at every point the resolve reads on that fixture, a pond that follows a pond within its bank reach resolves its level to the lowest gated height under its rim (on 5.2.40's bytes the resolve and the gated query disagree there by 11.5 cm), the resolve makes zero centerline projections onto rivers whose bounds exclude the sample, and a 32-river chain stays under three projections per sample (26,640 and 6,216 projections on the pre-fix code).
  • Frame-cadence phases read the frame clock; a camera view carries where inside the tick it was produced (ledger 3025; bran's Recast intro, dump af8e880b, engine 5.2.36). Two mechanisms, one specimen. (1) runFrame handed the frame-cadence phases (interpolation, renderPrep, renderSync) 1 / tickRate on a frame that stepped the sim and the frame's wall dt on the presentation frames between steps; the two windows overlap, so Σdt ran at (2 − tickRate / frameRate)× wall time — 1.75× at the worker's 120 Hz frame loop over a 30 Hz sim. Every clock integrating dt at frame cadence ran fast: juice timers (screenShake, punch, zoomTo, hitstop), sprite animation time, camera-script easing, and a scripted camera sweep that re-seated itself to a 12 Hz story clock every 0.3 s of drift — the periodic ~0.08 rad snap-back the player felt as constant stutter. The frame-cadence phases now receive the frame's wall dt on every frame (a catch-up burst hands the whole window once); the simulation phase keeps its fixed step. (2) Camera scripts run on every worker frame, and every view written between two sim steps was stamped with the integer tick alone, so they all folded into one ring slot that kept moving while the renderer blended toward it — the presented pose advanced as the square of the phase inside each tick, a 30 Hz velocity sawtooth on a smooth authored sweep. The client runtime now publishes PresentationTickPhaseResource (the ticker's leftover as a fraction of one tick), ecs-sync stamps it on the camera view as tickPhase (one f32 slot on the camera record; absent on old bundles), and the smoother ring places each view at tick + tickPhase (32 slots; a sub-tick step back folds instead of restarting the timeline). The playout clock still observes the integer tick, so entity presentation and its delay are unchanged. Red-first pins: render-prep-dt-wall-clock.test.ts (Σdt = wall at 120 Hz and 60 Hz over 30 Hz; the burst window; the simulation phase fixed) and camera-scripted-sweep-interp.test.ts (constant per-frame delta with the phase; the sawtooth named as the negative control). The render trace now records the presented camera rotation (camQx..camQw) so a per-frame angular receipt exists. Second-stack receipt, bran's camera.js verbatim under Xvfb Chrome, per-frame angular velocity of the presented camera over the same 3.5 s of his wake sweep: master cv 2.58 with 16 reversals → wall-clock dt cv 0.31 with 0 reversals → plus tickPhase cv 0.22, per-frame Δyaw spread 3× instead of 20×.
  • Durable writes made by game scripts while Savi's builder holds the room are reported as one fact-plus-next-move line, with the no-lane code (ledger 3047; wording follow-up from review 72acc7e0). Relay rooms persist spec writes through the elected host's page: the worker's save scheduler (engine/runtime/relay/relay-spec-save.ts) posts spawn:kernel:spec-save and the page hands it to kiln under the creator's own session. The headless room-host shell's room_host token carries no permission level by construction (kiln's ai-player token route never stamps one), so when a withPersistence write by a game script dirties the spec on that seat the scheduler refuses before it posts and drops the pending rows — behaviour unchanged from 5.2.40. What changed across the two 3047 landings and this one is the sentence in the runtime log Savi reads (client-sight read_client_logs, api.reportEngineBug dumps). It used to read spec-dirty but this session's relay identity carries no editor permission (level=null), which on the shell describes broken plumbing that is not broken, and Savi chased it. The first replacement named the shell and its missing spec-save lane — a component and a cause, with a next move ("when a creator's tab holds the host seat") that neither Savi nor the creator can act on, against the planned-events law every other Savi-read line in runtime-logs.ts follows. The line now reads, in ravi's words, [relay-spec-save] N durable write(s) by game scripts did not save from this room and will not. What the game changes while it is open in the creator's tab does save; until then the running world keeps these only until it restarts or is reset from the saved game. — three facts, each verified against the mechanism: the dropped writes never save (the branch empties the pending set and no path re-posts them when a creator's tab later hosts — only writes made while the tab hosts save); writes made while the creator's tab is open do save; and the live copy is not durable — it dies with the running world, or at the next reset from the saved game (a rejected mutation batch, a resync, a revert — the reset re-asserts the whole saved document, and the dropped rows have nothing left to overlay it). An earlier form of this line promised "they save when the game is open in the creator's tab" — a promise the mechanism does not keep — and a reviewer's hypothesis that the creator's next save would snap the live values back was checked on the relay harness: an ordinary save does not — a behavior's write never moves the seat's local doc mirror, so an unrelated save folds and leaves the live value standing — while a replace-class fold does snap it back (relay-shell-durable-write-snapback.e2e.test.ts pins both). The no-lane code (host_has_no_save_lane) rides the warn's data field rather than the prose, so the logs keep their handle while the sentence Savi reads names no shell, seat, lane or host. Once per session, like the viewer line; a creator's tab (a session-class token with a permission level) never enters the branch. The scheduler test pins the sentence whole, the data field, and the absence of the internal words from the sentence as read. If a batch ever does reach the shell's link, _entry/headless-room-host/runtime-worker-link.ts answers the same typed terminal instead of sinking it. Whether the shell may ever hold the spec pen is a write-authority question that stays with Jacob; nothing here decides it.
  • replaceSpecWithStarter tears the old world down on the seat that ran it (ledger 2796 — the client-side reset choreography deferred when 2314 landed). On the relay tier the room's authority is a CLIENT world: Savi's run_script executes the swap on the elected host tab or the standing shell, whose applyStarterSpecTail moves the spec head and mints TomeResetRequestResource — the same rail the kernel server drains through tome/reset-dispatch. Multiplayer clients never mount the server system set, so on the minting seat the request stood undrained: the old world's entities kept standing under the new document, and when kiln's fold of the swap arrived the mirror already equalled it, so the reconcile diff was empty and the completed-apply binding was restored over a world that was never rebuilt (Kamon's tape, 5.2.35: a 3d world standing under a 2d-top document until a reload; the swap was what provoked the restart-rooms). The tome feature now registers a CLIENT leg of tome/reset-dispatch — same name, same fn, the roomStateResumeClientMeta shape, one instance in the singleplayer glue by name-dedup — so every world that can mint the request drains it: despawn sweep, resource reset, reset apply of the new doc, the replace: true bump that arms this realm's own replace-apply. Kernel-tier multiplayer clients never mint one (the swap's authority guard) and pay one resource read per tick. Client-auth inside the drain: a non-server world's reset rebuilds only the envelope it owns (getLocalSessionClientId); remote players are their owners' replicas, and re-running their template and onSpawn here would mint a second copy of every rig the owner builds. Server worlds reset every player as before. Red-first pin starter-swap-client-teardown.test.ts (parent: the mint-without-drain face and the fold that restores the binding over the standing rock; fixed: the rock dies, the request clears, the bump is a whole-doc replace, kiln's fold is a no-op adopt, the remote replica keeps its owner's state while the local body re-mints, a spectator's drain is inert, the feature mounts the client leg). Second-stack receipt (container tier, two headed Chromium tabs on WebGPU): a 3d→2d-top swap through the exec lane paints the tilemap world on both clients within 2s, before and after this change — the container tier's server-side rail was already whole; the relay-tier seat is what this lands. Not run here: a relay-tier browser session (the box has no local relay); that tier's receipt is the unit pin plus the next relay room that swaps.
  • Client terrain chunk and horizon builds are judged "stuck" by executed sim ticks, never by a tick clock that a projection reset can move (ledger 3054). engine/features/terrain/client-terrain-system.ts and horizon.ts read their lost-job deadline (CLIENT_CHUNK_JOB_STUCK_TICKS, 300) as ctx.tick - submittedAtTick. The sim tick adopts the room's clock at every projection reset (runtime-client.ts rebaseToAuthoritativeTick, driven by netcode.ts applyProjectionResetAdoption), so a client that stalled and then ingested a reset saw its tick leap by however far the room ran ahead, and every queued build in the place read as past the window in one sweep — cancelled, re-marked dirty, restarted from zero, on the machine least able to redo it. Hot Drop 08-28 (5.2.15, container tier, a 4-thread laptop): two whole-place stuck: no completion within the deadline window sweeps at exactly the adopted reset ticks 1621 and 3903, minutes after the builds were submitted at ticks under 300. The deadline now counts the build system's own runs (state.runs, one per executed sim tick; submittedAtRun on every pending batch, single, and horizon job) — the window keeps its meaning ("300 ticks this client actually ran") and no adoption moves it. The warn line, the retry backoff, the liveness classification, and the server-side deadline (server-terrain-system.ts, a clock that never leaps) are unchanged. Red-first pins: __tests__/client-chunk-build-failure.test.ts and __tests__/horizon.test.ts — a build submitted at tick 1 survives a leap to tick 2000 untouched and is judged stuck on the 301st executed run.
  • A texture-script sprite's auto collider is re-derived on every realm, so a journaled pre-5.2.40 collider does not outlive the engine that wrote it (ledger 3048 — gfta's "1, 2, MANY GOBLINS", Savi filing 50316841, on 5.2.40 bytes). The 2986 cure (5.2.40) made the sprite auto collider a sprite-plane rectangle, but the physics body config it produces is REPLICATED state (PhysicsBodyConfig, replicate: "aoi"), and a relay room's world journal persists across an engine switch: the pin drain releases the room's recorded engine identity so every tab and the builder shell reboot on the new bytes (ledger 2933), and it deliberately does NOT reset the journal (ledger 2074 — a reload is a rejoin, not a world restart). So a 5.2.40 joiner built the rectangle from the spec at join and then, in the same catchup drain, adopted the old host's journaled row for the same entity — the world-space box [w/2, h/2, 0.25] whose 2d-top footprint is the w × 0.5 m sliver on the feet line — and nothing re-derived it afterwards. gfta's twelve texture-script walls (scripts/tex-wall.js?p=run&v=N, size [8, 7.25]) kept the sliver on the headless builder shell that had provably booted 5.2.40 (its boot line names the 5.2.40 engine hash); the filing's api.raycast hit at feet − 0.25 = 23.80 reproduces to the digit through the real seams (ObjectAPI.spawn → physics/step → ingestRoomDelta of the journaled row → api.raycast). The sprite/metadata-upgrade pass (features/sprite-metadata-hydration.ts) is the realm-local convergence lane for exactly this component — every realm re-derives an autoCollider: {kind:"sprite"} body's collider from replicated facts, write-when-different — and it already healed a PNG sprite (any current sprite2d entry, hull or null, enforces the derived shape), but it returned early for texture-script refs, which have no metadata lane, so a drawn wall kept whatever the journal said. The pass now converges a texture-script sprite's marked body too; the size is never touched, and a second pass writes nothing (the ledger 3041 guard). And the marker on a journaled row is the OLD engine's word, not the outline's: on 5.2.38/.39 a physics re-set on a sprite with an authored collider2d rebuilt the body as the auto collider (ledger 2993 — box + sprite marker), and that row rides the journal into the new engine the same way, so a marked body that carries an authored outline (TomeCollider2d, world state since 2993) converges to the AUTHORED hull through the one sprite derivation every spawn lane runs (spriteColliderPrimitive) and its marker corrects to primitive — the body spawn would have landed — on both the texture-script and the PNG lane; only a marked body with no authored outline takes the hydrated hull or the rectangle. Three lanes (boot apply, api.spawn, the pass) onto one derivation; the sprite primitive → collider mapping has one home (spritePrimitiveCollider), read by buildPrimitiveCollider and the pass alike. Pinned red-first in engine/physics/__tests__/2d-top-sprite-collider-journal-adoption.test.ts (gfta's wall spec verbatim: the journaled box is adopted → the sliver on new bytes → the pass restores the band; the PNG control was already green; an authored hull spawn landed is untouched; a journaled 2993-dropped body on a wall with an authored foot band — texture-script and PNG — converges to the authored band with the marker corrected, red on 99c52da705 where it became the full rectangle marked sprite). NOT changed here, named as the residual: a PNG sprite whose texture never gains a metadata entry (no metadata authority for its URL shape) keeps a journaled stale collider until the room's world is rebuilt from the spec — Savi's manage_engine_version restart-rooms (the relay journal reset) is the lever today, on 5.2.40 and every version; and the class itself — an engine switch on a warm relay room carries the OLD engine's derived state into the new engine for every replicated derived component — is a product question (should the pin drain reset a dev room's journal?) left for a human, not decided here.
  • A texture on a primitive reads upright — image top at the face top — on every draw lane (ledger 2414, 3032; 1968's workaround is no longer needed). A plain primitive's map draws on the shared texture-array lane when the map seats in a texture page, and on an oversized direct pool when the page fleet refuses it (over-profile — every texture over 512² on desktop, tailAdmission: false — an unsupported format, or the page budget spent). Lume uploads texels top-left (texture-upload.ts orientation contract); box UVs put v = 1 at the face top. The direct pool has always baked a V flip into its slot (scaleV = -|repeat.y|, offsetV pre-advanced by a whole repeat), so a pooled map read upright — the convention of a three.js material with a flipY texture, the prior every creator and Savi write against. The arrays lane sampled abs(scale) * uv + offset with no flip, so the same map read upside down the moment it seated in a page: a texture-script canvas with a red bar along its top edge baked with the bar at the bottom of a standard-material box (2414), a 1024² image was upright on desktop and inverted on a phone, and one URL read upright at fresh load and inverted after a mid-session material swap put it on the other lane (3032). The arrays lane now negates V in the shader on every tap: the repeat tap (in.uv * abs(scale) * (1, -1) + offset — a repeat sampler keeps frac(V), so the sign alone is the flip, and it lands on the same frac the pool's -|repeat.y| * v + ceil(|repeat.y|) + offset does), the clamp tap (1 - v inside the parametric 0..1 window), the workspace projection, and the displaced lane's height tap. The normal map samples and derives its tangent frame from the same flipped coordinate, as the pool already did, so the whole texture stack flips as one unit. The bespoke direct pool (resolveBespokeSlotOversizedBinding) carries the same signed flip the primitive pool does, so a scripted mesh's texture reads the same way up whichever lane residency put it on — without that this landing would have created the 3032 class for bespoke meshes. Not changed: the primitive direct pool's binding (byte-identical), primitiveTextureState/bespokeTextureState (the sign of scaleV on the arrays lane is still the clamp-array select — a negative authored repeat.y is still absorbed by Math.abs; honoring it is ledger 1968's separate landing and would invert any texture whose creator wrote a negative repeat to compensate), the pool-vs-lane clamp UV source, unauthored mapRepeat, and the ornament/tilemap/text/sky lanes (they already flip V in their taps). Red-first pins: material.test.ts (every arrays tap negates V; the direct variant is verbatim), store.test.ts (through the production routes with pageBudget: 1, the lane's and the pool's shader rules sample the same frac(V) at every face position and 0 — the image top — at the face top; the bespoke pool binding is -3 / 3.2 for repeat 3 offset 0.2). Real-product receipt on a second stack: the same test card (black bar + "TOP" along the canvas top) on a ≤512² box (lane) and a 1024² box (pool on desktop; page on the phone tier), 2414's red-bar canvas at 256 and 1024, a plain textured cube, and a textured sphere (workspace tap) — every one reads upright at 1600×900 desktop and at 390×844 with ?tierOverride=phone. Population: two populations turn from inverted to upright when a game takes this version. (1) Plain primitives: every texture that seats in a page — every textured primitive on phones, every ≤512² texture on desktop. (2) Custom-geometry meshes (kind: "custom" / kind: "scripted", textured through ctx.albedo / textureRuns): every textured scripted mesh on every device and every size — the arrays lane sampled bespoke UVs unflipped and the bespoke direct pool carried a positive V scale, so a scripted mesh's texture was inverted on BOTH lanes before this landing, desktop 1024² included; both lanes flip together now. Creators who flipped an image, drew a canvas upside down, or wrote a UV-flipping helper to compensate on either population (Herrmanns Radiowerkstatt's ausrichten(), the 1968 specimen's pre-flipped paintings) will see those compensations double-flip; the creator line names both populations.
  • The value-wall row's third sentence speaks for the refused write, not for the entity (ledger 3100 landed-look). Once a basis leaf over the wall is thinned sender-side, the same invocation's small writes land while the oversized one is refused — so the writer's ring row Nothing changed on "<entity>" was false in that exact case (the fix-forward's own e2e pins hp: 1 on the entity three lines above the row that said nothing changed on it). The row now reads That write changed nothing on "<entity>". (Those writes … on a folded episode), and the adjudicator's console line says the same. The relay.intent_value_wall meter's comment no longer claims the sender's uplink bounds its rate: that holds for value_too_large (64 KiB+ per refusal) and not for value_too_deep (a nine-deep array is ~20 bytes).
  • The truth-echo warn line says what the receiving client does next, and only that. [relay-truth-echo] … (me) — re-stating presence so its fold converges claimed a repair that never ran: the worker's transport wrapper does not forward the repair port (relayRequestPresenceRestate, still held), so every real session logged the claim and re-stated nothing — about 700 such lines a week in production. The line now reads (me) — this transport has no presence-restate port, so nothing is re-stated when the port is absent, and names the once-per-window restate only when it will run. The echo itself, its rate limit, and the drop it reports are unchanged.
  • A viewport look on a hidden tab answers the hidden-tab verdict, never "the renderer has not produced a frame yet" (ledger 3045; Savi filing 77e74705, engine 5.2.39). A hidden tab parks the swapchain on purpose (suspendPresentation unconfigures the canvas context — the IOSurface give-back), and on a browser whose worker rAF keeps ticking while hidden the frame loop stays alive: frameLoopPausedReason's stall clock never named the hidden tab, composeAndRenderFrame skipped every frame, and the frame-tail still serviced the player's-frame capture against the unconfigured canvas — getCurrentTexture() threw, frameCaptureSource read null, and captureSceneViewImage called it "the renderer has not produced a frame yet". Camera-form looks in the same room render off-swapchain and kept working, which is what made the sentence read as a renderer fault. The renderer now reads the LIVE device state (lume.presentationSuspended) for every capture that needs the swapchain — the no-argument scene view, its degraded no-camera form, the viewport burst at start and per tile — at admission and again at service time, and answers HIDDEN_TAB_CAPTURE_ERROR (the existing canonical line the chat side already classes as the hidden-tab eye). Camera/frame captures are untouched. Red-first pin scene-view-hidden-swapchain.test.ts (parent: the exact field sentence; fixed: the hidden-tab line from admission with the swapchain untouched, at service time when the tab hides between admission and the frame, for a viewport burst, a camera look still admitted hidden, the visible edge re-arming the grab). Second-stack receipt in headed Chromium on WebGPU: hidden → verdict in 1 ms, camera look served, visible again → the player's frame, odd-width resize → the player's frame.
  • The voxel terrain change-signature carries the part of the marks map's order that is ground (ledger 2808, third half — the voxel twin of #14391's marksOrder). buildVoxelMarksSignature has sorted the marks map by key since the first half (b8bd7d5b6a), so two spellings of one map read as one terrain — but resolveVoxelTerrainMarks (features/terrain/voxel/marks.ts) sorts by priority then insertion order and feeds each stage the stage before it, so two OVERLAPPING same-priority marks resolve differently in each order: a flatten carves air at y ≥ localGroundY and fills its material in the band below (the later pad wins), pond and river share one priority (the later liquid's air/liquid/bed overwrites the earlier one's, cross pairs included), a path's later band overwrites, a structure's later template — empty cells included — wins in the shared box; only clear is a union. A kiln fold spells the map in Postgres jsonb order (key length, then bytes), so a fold that reordered two overlapping voxel pads changed the resolved voxels with no reinstall: the connected room kept the authored ground, a fresh joiner built the folded one — silent peer divergence until recycle. The voxel signature now carries marksOrder: every ordered [earlier, later] pair of same-group marks whose reaches intersect, built by the same buildMarkOrderSignature the heightmap term uses (groupOf maps voxel pond and river to one group). resolveVoxelMarkReach reads the conservative XZ envelope each apply gates on — shapeBounds for flatten/pond, polylineBounds over every control point for river/path (dropped points only shrink the resolve's hull), the structure box from the template bounds unioned with the bounds box (the resolve takes whichever compiles; flattenBelow fills the same XZ box) — and anything it cannot bound reaches everywhere. The term reads the marks through normalizeVoxelMarks, the one door into the definition, because a generator-driven structure's box comes from the template that door compiles (memoized by content). TERRAIN_MARKS_SIGNATURE_VERSION 7 → 8; HeightmapMarkReach/heightmapMarkReachesIntersect become TerrainMarkReach/terrainMarkReachesIntersect in marks-types.ts, shared by both resolves. The winner rules are untouched.
  • The heightmap spline-road reach mirrors the resolve's third fallback arm (the #14395 landed-look finding). sampleCentripetalSpline3D drops consecutive knots within 1e-6 and returns fewer than two samples for a spline that collapses to one knot; the resolve then bounds the road on points, while the reach stayed at the collapsed knot — so a second road on the points corridor read as disjoint and a reorder changed paint order with no reinstall. readRoadSpline now applies the same dedupe and falls back to points when fewer than two distinct knots remain.
  • Pins: voxel-marks-reach.test.ts — reach ⊇ the resolve's bounds for every voxel kind across 200 random maps (both structure forms, fractional and rejected templates); the order term over 1,100 random dense maps reordered within their groups (556 kept the pair set and 0 of those moved a voxel on a 25×25×14 grid; 544 changed it and 356 of those moved ground — the term is not vacuous); an explicit overlapping-flatten pair, a disjoint pair, a clear pair, and a pond/river cross pair. voxel-fold-identity.test.ts (red-first on b1c964b269: the three reorder pins fail there with the signature unchanged) — two overlapping pads reordered by a jsonb fold → new signature, the room's ground at the overlap moves 8 → 4 and matches a fresh join; a pond and a river that share ground reordered → new signature; two overlapping structures reordered → new signature; disjoint pads reordered → nothing; a template respelled in jsonb key order → nothing; overlapping clears reordered → nothing. marks-reach.test.ts — the reader's exact reproducer (spline: [[10,0,10],[10,0,10]], points: [[500,500],[560,560]]): red on the landed bytes (reach {6…14} against bounds {497.5…562.5}), green now.
  • A voxel world cut open by the client's mesh window now says so in getLogs, once per player per place (ledger 2884, the silent half of ledger 2883 — CRATERCRAFT / MERIDIAN). A client meshes a voxel world inside a window: a horizontal spiral of chunk columns and, per column, a vertical band of chunks around the player (streaming.ts computeVoxelMeshDesiredChunks, ±2 chunks within 15 columns, ±1 beyond). A chunk outside the window is not desired and never drawn; solid ground there is intact in the generator and on the server, and nothing named the drop — a radius-26 planet drew as a cap with an open bottom and Savi spent an incident gather proving 130 solid samples against a fault no instrument named. New engine/features/terrain/voxel-mesh-window-verdict.ts: a paced client system (every 4 s until the place has its verdict; a headless client controls no entity and scans nothing) reads the field's own shell rows at the band's cut planes — a resident LOD0 chunk whose vertical neighbour is inside the world's vertical range, not resident, and not in the streamer's desired set (new getClientDesiredTerrainChunkKeys, so a pending build is never a cut). The mesher emits a face only from an occluding interior cell toward a non-occluding neighbour, so a solid cell in the undrawn row has a face nobody draws wherever it meets air; an undrawn face is a fault a player can see only when that air is outside air, so the scan seeds outside air at cell columns that are air from the cut plane to the far side of the window, floods the two rows at the plane, and counts solid undrawn cells that touch flooded air. A flat world (solid under solid, air over air) and a cave under the band earn nothing; a planet cut by the band, a planet under a floating player, and a canyon floor deeper than the band under open sky are named. The report rides engine.diagnostic as the new warning-class voxel-mesh-window-cut (log-only; #297 bucket: the engine acted on its own residency dial, never on content) with the drawn band, the cut plane, the undrawn chunk coords and the exposed cell count in its data. Nothing about what meshes changed — the spherical residency design stays ledger 2883. Pins: __tests__/voxel-mesh-window-verdict.test.ts (the sphere's named chunks equal an oracle over the generator's own border row; flat and cave worlds return null; pending neighbours return null; both planes; the exact Savi-read sentence and the absence of component words; the code allowlisted and landing in the runtime log through the real handler).
  • The voxel mesh-window scan latches a clean window and runs in slices (ledger 2884 fix-first, on the same version as the verdict). The verdict's client system latched only on a positive finding, so on every uncut voxel world — a flat world has a cut plane at both band edges whose rows never expose a cell — the whole scan re-ran every 4 s for the session: 14 ms in one simulation tick at the default window (845 resident grids), 36 ms at a 160 m window (2,205), 78 ms at 4,805. Now engine/features/terrain/voxel-mesh-window-verdict.ts (a) latches a clean verdict on the window it read — the streamer's desired set by identity (a new object per recompute) and the resident LOD0 grids by identity (a chunk arriving, leaving, or re-deriving swaps its grid) — and re-arms exactly one scan when either moves, so a stationary flat world scans once per session; and (b) runs the scan as a resumable job (createVoxelMeshWindowScan, paced by paceVoxelMeshWindowVerdict) in units of one boundary chunk's rows, one chunk's open-column seeds, a batch of flood nodes, a batch of counted cells, or a batch of resident coords, under a 1 ms budget per tick — a step does at least one unit and overshoots the budget by at most one unit; at 16-cell chunks every step measured at 1.0–1.3 ms across 845 / 2,205 / 4,805 grids, and at the product's default 32-cell chunk over a 31×31-chunk plane the largest unit is a lattice allocation that stays under about 1.7 ms cold and half a millisecond warm (Node numbers; the 1.3–2.5 ms figure was the cost before #14430's cut) (the flood arrays are allocated only for a plane that passes its dismissal gate, and exposed cells are counted per boundary-chunk index, so a dismissed plane allocates 6 bytes per lattice cell and a count unit mints no strings) — and a plane whose undrawn row holds no solid cell or whose drawn row holds no air cell is dismissed after its rows are read (a flat world's two planes both are). The one-piece detector findVoxelMeshWindowCut and its results are unchanged; the Savi-read sentence is unchanged. The code now also prints the server-console breadcrumb (SERVER_CONSOLE_BREADCRUMB_CODES) once per room, so the fleet can count worlds the band cuts open — the receipt the spherical residency design (ledger 2883) waits on. Pins in __tests__/voxel-mesh-window-verdict.test.ts: a flat world scans once across a minute of ticks and never again; a chunk arriving, a chunk leaving, and a window recompute each re-arm exactly one scan; the sphere-top, floating-planet and canyon shapes report once per session and neither time nor a moved window fires them again; the sliced scan reaches the one-piece finding; a step past its deadline still does one unit; the breadcrumb prints once per room across clients.
  • The world-sync ghost sweep's journal-truth bound and its reap-lane tombs now run on real sessions. The worker mounts netcode through MultiplayerDebugTransport, and that wrapper never forwarded relayWorldSyncLiveMember, so RelayWorldSyncDeps.isLiveMember was undefined on every browser and headless shell since the bound shipped: journalTruthProtectsFromSweep answered false for everything (a folded live member's body and a live member's authority scope were both sweepable on a peer statement) and enqueueRelayReapDeletes was skipped (swept ghosts kept their journal heads and re-materialized at the next fresh fold — the container-recycle resurrection loop). Only the harness pins, which bypass the wrapper, ran the bounded path. In production over the seven days before this landing the sweep fired 264 times and deleted 10,438 entities, zero lines said tombs journaled, and nine lines deleted a player/<uuid> body root — including a creator's own body after a redial, when the standing shell's statement omitted it. The seam is now forwarded in the wrapper's seam table; nothing in the sweep itself changes. With the dep wired: a body whose member is folded live in the requester's own election fold never sweeps; a candidate whose folded authority is a live member other than the statement's author never sweeps; every fired verdict rides the reap lane as an unstamped idempotent tomb, so the ghost's head retires at every fold and the warn line ends in , tombs journaled.