Final edition · FPS edition (SCAR) · last updated 10 Oct 2026 10:59 · 32 breakages (7 critical · 10 high · 10 medium · 5 low)
Final edition: project paused 2026-10-10
Where Virtual Matter Breaks: destruction FPS
Engine release/iteration073 (384c388, built 2026-10-05), native client 73.0.1554, CLI 0.6.5. Found while building SCAR, a destruction FPS whose core loop is persistent terrain edits. Same 5W format as the Ashlight report (v33, https://ohge-games.github.io/virtual-matter-breakage-report/): Who / What / When / Where / Why, then impact, repro, mitigation and suggested fix. IDs are F1, F2... Where an entry extends an Ashlight card, the B-number is given. Final edition: project paused 2026-10-10. Every change is published to the play server; "Final state" (below) records the published build and how it was verified, and "Final autopsy" (at the end) is the builder's view of the CLI and MCP tooling.
Edit framing 18QYJ28E5mDi5I1uRKpoY
Engine iteration073 · 384c388
Client Native, Windows, 73.0.1554
Tooling virtualmatter CLI 0.6.5 + vm-agent-tools
Previous edition Ashlight v33
The 5Ws, per breakage
F1Static edits reach connected clients through a slow, capped stream
CriticalWhy: measured↑ index
- Who
- every player in a world whose terrain changes during play - the whole premise of a destruction FPS.
- What
- server-side static edits arrive on a connected client 1-4.5 s later when the stream is idle (6 single 0.8 m removes: 0.9, 4.5, 1.5, 2.5, 3.1, 1.3 s). Under load they queue: a fresh client that is still streaming the map received a single 0.8 m remove somewhere between 30 s and 3 minutes later. After bursts (40 removes at 5/s in one 8 m cell) the client was still wrong at 12-32% of sample points 75 s later, and an 18-crater burst (r 2.5 m) never arrived at all on a client that stayed connected for 15+ minutes (the client showed the cell flat; the server had craters to the pad floor). A client that connected later saw everything at once.
- When
- whenever edits are made while clients are connected; worst for bursts and large edits, and while a client is still loading detail (a fresh client was still pulling 68-107 KB/s eight minutes after joining a heavily edited 48 x 32 m pad).
- Where
- static voxel streaming (
_AmStreaming). Server:GetStreamingStats() shows each client in a STALLING lag state with stallingSendBPS = 500000; the client receives 24-110 KB/s. A paint over the stuck cell, an LOD bubble, moving the camera 600 m away and back, and AE:ReloadGeometry() did not resync it.
- Why
- edits are not pushed as small deltas with priority; they wait behind (or are coalesced into) bulk chunk streaming that is rate-capped per client. Under a burst, intermediate versions appear to be dropped and the final version is not always re-sent.
F2A connected client can stop receiving static edits entirely
CriticalWhy: observed↑ index
- Who
- any connected client after a burst of terrain edits.
- What
- native client #1 received none of 40 removes made at 5/s, nor any later edit (3 pillars of 4 m concrete, several holes) for 15+ minutes. Client #4 showed the same after an 18-op burst. The server-side screenshot client showed every edit.
- When
- after edit bursts while connected; seen 3 times in one session.
- Where
- static streaming to that client. Reconnecting fixed it every time.
- Why
- unknown; consistent with the flow controller (
senderRecvLagDeviation pinned at 16383, finalRatioPct = 0) never leaving its stalled state for that client.
F3Clients drop when the server stalls for ~15 s or more
HighWhy: measured↑ index
- Who
- anyone connected or connecting while the server saves its terrain.
- What
- a native client that connected just as SCAR's empty-server maintenance ran (reclaim, then a 17.3 s terrain save) was disconnected and did not reconnect. Its log shows "New max ui client message sending time: 11057 ms", then "Connection to server lost".
- When
- during any main-thread stall longer than roughly 10-15 s (terrain save B19).
- Where
- client/server TCP keepalive.
F4Native client loses its connection with no auto-reconnect
HighWhy: observed↑ index
- Who
- a native client in a long session.
- What
- two disconnects not caused by a server stall: 16:40:03 (after "New max ui client message sending time: 29600 ms") and 17:00:06 ("TcpClient::SendMsg: failed to send a message to server" with no preceding gap in the client log; the client was at 88 fps). The window stays open, showing a frozen scene; nothing reconnects.
- When
- 6 and 17 minutes into play. Update (8 occurrences; the 8th at 19:00 after a 51.8 s stall, with no screenshot involved): the client log shows "New max ui client message sending time" climbing to 29.6 s, 51.8 s, 58 s and 253.6 s before "Connection to server lost"; the server then reports the client gone. The client keeps rendering at 88-100 fps throughout, so it is not frozen; its upstream channel is blocked. Three of the seven followed a
screenshot --client capture within seconds to minutes; the others came while the client was streaming terrain heavily (150-216 KB/s downstream, footprint 346 MB and growing) during edit benches. A hidden (throttled) browser tab also fell behind and its divergence probes failed.
- Where
TcpClient.cpp:197/317; Client.cpp:2654 ("ui client message sending time").
F5Client ray and collision data is LOD-quantised a few metres from the camera
HighWhy: measured↑ index
- What
- over an untouched flat pad, server and client rays agree exactly; over dug ground 4-11 m from the client camera, client ray heights are higher than the server's in steps of 0.125 m (and some 0.25 m), even with an LOD priority bubble around the area.
F6The edit guard's budget is per frame, not per op
MediumWhy: measured↑ index
- What
- a pad reset issued 4 large ops in one Lua call (remove, add, remove, add; ~491 baseline-m2 each). The 4th threw "frame voxel budget exhausted (~697 already issued this frame...)", leaving half the pad removed and not re-added.
F7ForceStatic() throws on the client
MediumWhy: confirmed↑ index
Cast:Ray(...):ForceStatic() and Collide(...):ForceStatic() on a client raise "ForceStatic() only available on server". Client code must use plain rays and filter dynamic objects with Ignore. Suggested fix: allow it on clients (the client has static data) or document it.
F8CLI 0.6.5 files API requires a precondition on every PUT
Medium↑ index
Uploading a NEW file with no precondition returns HTTP 428. The vm-agent-tools push-only deploy (built against older behaviour) failed for all new files. Fix shipped in vm-agent-tools/cli-ext/vmpush.mjs: createOnly (If-None-Match: *) for new files, etag re-read on conflict.
F9Re-parenting keeps the world transform
Low↑ index
child.parent = obj keeps the child's world position, so a camera created at the origin and parented to an eye object ended up at the player's feet. Set localPos / localRot after parenting.
F10Streaming stats read as stalled for healthy clients
Low↑ index
Server:GetStreamingStats() reports senderRecvLagDeviationFlowState = STALLING and finalRatioPct = 0 for a freshly connected client that does receive data. The fields are undocumented, so they cannot be used to detect F2.
F11A zero-length ray throws
MediumWhy: measured↑ index
Cast:Ray(p, Vec3(0,0,0)):Run() raises "ray is zero length". Inside a util:schedule chain or an Update loop the error stops the chain silently (the B16 bench's sampler died this way when it picked the same player twice). Gameplay code hits it whenever two positions coincide: a grenade exploding exactly at a chest, a bot aiming at a target standing on it, a projectile at rest. SCAR guards every ray whose vector can be zero. Suggested fix: return nil (no hit) for a zero-length ray, as most engines do.
F12Every static edit costs one 30-50 ms server frame, whatever its size
CriticalWhy: measured↑ index
- Who
- every player of a world that edits terrain during play.
- What
- single gameplay edits through SCAR's scheduler on an idle server (17 ms frames): dig capsule r 0.7 -> worst frame 30-33 ms; frag sphere r 1.1 -> 30-34 ms; breach sphere r 1.8 -> 50-52 ms; Bloom (3 small adds) -> 25 ms. A sphere with 3.9x the volume of a dig costs the same frame, so the cost is mostly per op, not per voxel. Each op also adds ~40-110 ms of update work spread over the following frames.
- When
- every static
Vox op (Remove/Add/Paint).
- Where
- the commit of a static op (the voxel system flush, LOD rebuild and streaming of the touched chunks).
F13The server-side screenshot client goes stale after a map-scale rebuild
HighWhy: observed↑ index
After SCAR's clean rebuild (clear all static terrain, rebuild 112 x 112 m: 9.3k jobs, then a dressing pass) the CLI's default screenshot (rendered by the server-side client) showed only the southern half of the map, with a floating wireframe of edges over the north, unchanged across 4 captures over several minutes and two camera angles. Server rays (the verify script) found all terrain; a freshly connected native client rendered the whole map correctly. This is B3/B28 at map scale (remove then add everywhere while connected), and it means the agent's main visual check is wrong after any big rebuild. Mitigation: verify with server rays and a freshly connected native client. Suggested fix: resync the server-side client's stream after large edits, or reconnect it per screenshot.
F14A freshly joined client receives gameplay edits 12-45 s late
CriticalWhy: measured↑ index
- Who
- every player who joined a world within the last several minutes (in a 4-minute-round game: everyone).
- What
- bench/gameplay_edit_bench.py on the dressed Scarfield map, native client joined ~2 min earlier, standing 10 m from the edits: single digger (1 stroke/s, one cell) delivered 9/9, latency avg 14.5 s, p90 24 s, max 27 s; the global budget (2.5 ops/s over 6 cells) delivered 6/10 within 60 s (avg 12 s, max 23 s), 4 never arrived; frag craters (1 per 3 s) 8/8, avg 26 s, max 45 s. On the empty off-map pad earlier, a single edit took 1-4.5 s.
- When
- while the client is still streaming the map: 74 MB received after 8 minutes, 150-216 KB/s, client footprint 323-346 MB and still growing.
- Where
- static streaming: edits are not prioritised over bulk detail streaming (F1).
F15An object name set after creation never reaches clients
HighWhy: measured↑ index
The SCAR avatar scale bench cloned "Scar Rig 10" 40 times with Scene:CloneObject and renamed each clone ("Scar Bench Rig k") on the server. The server listed 40 bench rigs and one "Scar Rig 10"; the connected native client listed 41 objects named "Scar Rig 10" and none of the new names, minutes later. Client code that finds objects by name therefore never finds a clone. Workaround: pass Object.id (documented as unique across server and clients) and resolve with Scene:GetObjectById. Suggested fix: replicate name changes, or document that names are creation-time only.
F16Cloning a multi-part voxel rig stalls the server about 110 ms per rig
HighWhy: measured↑ index
- What
Scene:CloneObject of a 12-part rig, with each part bound to a baked .am asset, took 96-113 ms of server main thread per rig (about 9 ms per voxel part, max 144 ms). Ten clones in one Lua call stalled the server for about 1.1 s.
F17Clients draw terrain as grey placeholders while its collision is correct
CriticalWhy: observed repeatedly↑ index
- Who
- every player. The playtester reported it several times: "lots of world loading issues while moving; sometimes part of the map isn't generated while turning", then "large chunks of map aren't rendered".
- What
- whole regions of the 112 m map render as flat grey surfaces with wireframe chunk edges, with floating bushes and boulders. A screenshot pair 3 minutes apart from the same spot showed the east half missing, then the west half missing while the east rendered.
- Where
- the native client (73.0.1554), after 10-50 minutes of play on a field with ongoing digging. The client sat at 5.8 GB resident at launch and 7.4 GB after 50 minutes (65 GB host), so memory pressure is not the cause.
F18Lua resets silently orphan imagine() generations
HighWhy: observed ↑ index
- What
- generations started with
imagine(prompt, Object, opts) never finish if any .lua file is pushed while they run. The object keeps its Gen Progress script indefinitely (observed 25+ minutes) and no error is printed. Four weapon jobs were lost this way, then two more.
F19Small per-frame Lua garbage produces 10-14 ms client GC spikes
MediumWhy: measured↑ index
SCAR's procedural avatars allocated about 20 small tables per rig per pose (7 rigs at 60 fps, about 7k tables/s). The avatar script measured 87 of 1,015 frames over 2 ms with 14 ms peaks, although its own work averages 0.3 ms. Reusing the tables gave 2 of 1,744 frames over 2 ms with a 2.4 ms peak. The spikes are incremental GC steps charged to whichever script allocates. Rays (0.08-0.13 ms), localPos/localRot writes (0.0008 ms) and Vec3/Quat construction (0.0003 ms) are cheap. A controlled A/B of client fps against injected garbage was inconclusive (25-36 fps either way, with the window unfocused). Suggested fix: document the GC budget, and expose collectgarbage("step") control or a generational GC on clients.
F20A scoped zoom still renders distance LOD
LowWhy: observed↑ index
At FOV 14 (4.6x), the Marksman scope shows the same voxel LOD as the unzoomed view, so distant targets and terrain look coarse when magnified. The renderer picks LOD by distance, not projected size. Suggested fix: scale the LOD distance by FOV, or expose an LOD bias for the active camera.
F21Clients cannot see a streamed object's voxel data
MediumWhy: measured↑ index
On the native client, every rig part (rendered and visible) and every viewmodel part reported VoxelData.data == nil, VoxelData.asset == nil and isLoaded == false, while the server reported the bound asset and the volume. A client therefore cannot tell whether an object's voxels have arrived. SCAR's viewmodel waited for data.volume > 0 and never switched on. Workaround: trust the server's binding. Suggested fix: expose a client-side "streamed / LOD level" flag on VoxelData.
F22Dynamic objects stream only near their server position
HighWhy: measured↑ index
SCAR poses rigs and viewmodels on the client (receiveTransform = false).
F23Streaming to clients causes the server's frame spikes, and a long session makes them worse
CriticalWhy: measured↑ index
- Who
- every player once the world has been running a while.
- What
- a per-frame capture of all 149 engine timers over 25-30 s attributes the spikes. In spike frames (over 60 ms) these stages are far above normal frames:
• _AmStreaming - Sending: 17.7 ms (normally 0.8);
• VoxelServer Update: 31 ms (normally 0.12);
• AEVVRenderer - Load Phase: 15.6 ms (normally 2.1; the headless renderer, B43);
• VPO Update Part 7: 25.7 ms (normally 10.6).
- When
- continuously while any client is connected, worse the longer it stays connected.
- Where
- server-side voxel streaming (sending and VoxelServer update) and the headless renderer's load phase.
F24HUD root windows turn invisible on a fresh client with no script involved
MediumWhy: observed ↑ index
- Who
- any player whose HUD is built from script-created NewUI root windows (
ED.RootPanel).
- What
- after a fresh native client joined (9 Oct, ~05:30), the player reported "my UI is missing". On that client
UI:GetWindows() listed all of SCAR's HUD windows, but six (Top, Vitals, Weapon, Feed, Tags, Toasts) read visible = false. Nothing in SCAR's scripts sets those six invisible: they are created visible and never toggled. The windows the HUD re-sets every frame (crosshair, markers) were visible. Setting visible = true from a client run-lua brought the panels back at once (confirmed by a client screenshot).
- When
- on a freshly started native client, after the game had pushed several script updates (each push resets Lua and rebuilds the HUD). The exact trigger is not known.
- Where
- NewUI root window visibility on the client.
F25Client-posed objects render one frame behind the camera
LowWhy: observed↑ index
- Who
- first-person viewmodels and anything else posed on the client against the camera.
- What
- SCAR poses its first-person gun and arms (voxel objects,
receiveTransform = false) in LateUpdate from the camera object's world transform, after movement and the camera update. When strafing at 30-40 fps the gun visibly trailed the view, by about a frame of movement (10-17 cm, which is large at 0.4 m from the eye), and "hiccuped" with frame-time variation. Turning showed the same lag, hidden by the deliberate sway.
- Where
- transform propagation from Lua to the renderer for dynamic voxel objects, compared with the camera's own transform.
F26Play clients get pooled parts unparented, and never get empty parent objects
CriticalWhy: measured↑ index
- Who
- every player of a published world that builds object pools (rigs, held items, prop groups) under empty parent objects.
- What
- after publishing, players saw invisible bots, guns floating around the map and the placeholder first-person gun. A one-line diagnostic each client reports to the server showed, on the play client,
Avatars rigs=0 and VM set=nil (the editor client: 10 rigs, set 1). The server had all 10 "Scar Rig i" roots with their 14 parts, assets bound, and identical object counts to the editor. The play client never received the empty roots ("Scar Rig i", "Scar VM i", "Scar Lobby Props": no component, nothing synced), so Scene:GetObjectByName found nothing, and the parts arrived unparented, drawn at their raw local offsets near the world origin (the "floating guns").
- When
- on play servers only. In the editor, the client receives the full hierarchy, so the same code works.
- Where
- object replication to non-editor clients.
F27Published scenes don't carry script attachments made in the editor's live scene
HighWhy: measured↑ index
- What
- scripts attached at runtime in the editor (
AddScript from an installer, followed by Server:SaveSceneHierarchy()) were present in the editor but absent on the play server after publishing: FindScript("Scar Viewmodel") and FindScript("Scar Replay") returned nil there, while every script file had the new version. The first-person weapon and the round replay simply did not exist in the published game, with no error.
- Where
- the publish pipeline boots
Scenes/InitScene.aeScene; the live editor scene, and whatever SaveSceneHierarchy saved, is not what gets published.
F28No tool reaches a play client, and the CLI can't publish
HighWhy: observed↑ index
- What
run-lua, errors and screenshot work only on the editor framing. A read-only Lua probe can reach the play SERVER, but nothing reaches a play CLIENT: no client Lua, no client errors, no screenshot. Publishing is only a button on the project page (the promised publish CLI command is not in 0.6.5), so each fix needs the maker to click it.
F29virtualmatter open self-update fails from Git Bash
LowWhy: observed↑ index
When a new native client build was available, virtualmatter open run from Git Bash printed tar failed (128): tar: Cannot connect to C: resolve failed and did not start: GNU tar reads C: as a remote host. Running the same command from PowerShell (Windows tar) updated and launched the client. Suggested fix: pass --force-local, or extract with a bundled unzipper.
F30Client screenshots away from the player show unstreamed terrain
MediumWhy: observed↑ index
screenshot --client <id> --at x,y,z --rot ... moves only the camera. Streaming and LOD follow the player, so a shot 30 m from the player shows holes, wireframe chunk edges and coarse placeholder ground; the server-side screenshot client was stale at the same time (F13). A lighting A/B (sun angle) could not be judged at all. Suggested fix: move the streaming focus with a screenshot camera, or wait for streaming to settle before capturing.
F31A focused UI window swallowed the keys meant to close it (browser play build)
MediumWhy: observed↑ index
SCAR's Armory opened with UI:OpenWindow(window, true, false) (focus) and closed on Esc or U read through Input:KeyDown. A player on the published browser build was stuck in it: neither key closed it, and in a browser Esc only releases pointer lock. The editor testing never caught it because the menu was always closed by script. Workaround: open without focus, and give every modal a clickable close button. Verified on the play server (10 Oct, fifth publish) as a guest player in a browser: U, Esc, the X button and the CLOSE button each closed the Armory, and it reopened every time. One quirk remains: right after a mouse click into the game, the first key press was ignored, and a second U was needed. That happened all 3 times it was tried (synthetic input from an automated browser, so treat it as a lead, not a measurement). Suggested fix: document that focused windows consume keyboard input, and keep a guaranteed escape key that reaches scripts (or closes the focused window) in browser builds.
F32The guide documents CLI and MCP commands the published CLI doesn't have
MediumWhy: confirmed↑ index
- Who
- any coding agent that follows the AGENTS.md the CLI writes into every mirrored folder.
- What
- that guide lists
npx virtualmatter push [files] ("one-shot deploy, per-file result"), fetch [files], and the MCP tools patch_file, push_local_files and fetch_files. VM's 8 Oct reply also promised logs [--restarts], publish and status. On 10 Oct, npm's latest virtualmatter was still 0.6.5 (published 2 Oct). virtualmatter push fails with error: unknown command 'push' (exit 1), logs and fetch do the same, and the MCP server lists none of the three file tools.
- When
- the whole SCAR build (8-10 Oct). The folder's guide was written on 8 Oct, and the platform refreshed the world's AGENTS.md and Skills files again on 10 Oct.
- Where
- the guide the CLI writes on
pull, and the canonical copy at make.virtualmatter.ai/AGENTS.md, compared with the npm release.
Final autopsy: building SCAR through the CLI and MCP
Written by the coding agent (Claude) that built SCAR, when the project was paused (2026-10-10). Ashlight's autopsy (https://ohge-games.github.io/virtual-matter-breakage-report/#autopsy) covered the tooling basics: deploy, publish, crash logs and resets. This one covers what a second, harder project changed, and what an FPS exposed that a survival game didn't.
Scale of the work
- Three days, 8-10 Oct, with one agent deploying.
- 10 game scripts, about 575 KB (11,900 lines) of Lua: server authority, a terrain edit scheduler, bots, HUD, effects, procedural avatars, a first-person viewmodel, round replay, player control and movement.
- Generated content:
- two soldier models, cut into 14-part rigs;
- four guns and a spade, each baked twice (rig scale, and 4x density for first person);
- four lobby props;
- 14 sounds.
- Benches: terrain edit delivery, gameplay edit delivery, a 40-rig scale test, per-frame engine timers, and a 20 s worst-case stress test. A 14-check smoke test and a preflight ran before every publish.
- Playtests: two by the maker in the editor, then a friends' playtest across four publishes.
What changed since Ashlight
- Nothing in the tooling. VM's 8 Oct reply listed fixes and new commands, but the CLI stayed at 0.6.5 and the engine at iteration073 for the whole project. Every promised command was unavailable (F32), so every deploy still went through the hand-made push-only wrapper (patched for F8).
- The problems moved from plumbing to the client. On Ashlight, the slow parts were deploy, publish and crash logs. On SCAR, the slow part was learning what a player's client actually has: terrain edits (F1, F2, F14), streamed objects (F21, F22), object hierarchy (F26), UI state (F24, F31). All of these differ per client and per framing, and no tool shows them.
What was genuinely helpful
run-lua on both sides. Client-side Lua found F21 and F24 and fixed a player's missing HUD live. It also let the agent force the play-client code path inside the editor to verify the F26 fix before publishing.
- Engine timers through
run-lua (AE:GetLogTimers). One 25 s per-frame capture attributed the server stutter to streaming (F23) and cleared the game's Lua. Without it, the stutter would have been blamed on game code.
screenshot --client. Still the only trustworthy image of UI, scope and viewmodel, within F30's limits.
imagine() plus Vox:Copy. A generated soldier became an animatable rig in under a second of engine time. Generated audio covered every gun, dig and UI sound.
open, the native client. A real client for benches and A/B tests, once run from PowerShell (F29).
- Hot reload. Still seconds per iteration, with the cost below.
What got in the way
- The editor is not the play server (F26, F27, F31).
- SCAR was developed and tested in the editor all day, and three of the bugs the friends hit could not appear there. A fourth (F31) was hidden by how it was tested.
- Diagnosing them took three publishes, each needing the maker to click a button, because no tool reaches a play client (F28).
- The game had to grow its own telemetry (
svDiag) to see play clients at all.
- A push still resets all Lua, and silently kills
imagine() jobs (F18). Six generated models were lost before "no pushes while generating" became a rule, so content and code work cannot overlap.
- Visual checks mislead in new ways.
- The server-side screenshot client went stale after a map rebuild (F13).
- Client shots away from the player show unstreamed ground (F30).
- A client cannot tell whether an object's voxels have arrived (F21).
Several "missing object" alarms were tool artefacts, and one real bug (F22) first looked like one.
- Edit delivery is invisible.
- There is no per-client acknowledgement or pending-edit count.
- The streaming stats read STALLING for healthy clients (F10).
Measuring F1, F2 and F14 needed a two-sided bench that polls client rays.
- Native client disconnects (F4) ended long benches silently, so bots had to carry the long tests.
- The guide is ahead of the release (F32).
What's missing (ranked by how much time it would have saved on SCAR)
- Play-client visibility:
- a "preview as play client" mode in the editor;
run-lua --target client, errors and screenshot against a play framing.
That alone would have caught F26, F27 and F31 before any friend saw them.
virtualmatter publish with per-server status, so a fix reaches players without the maker clicking a button.
- Edit-delivery observability: per-client acknowledged chunk versions or a pending-edit count, and a "resync region" call (F1, F2, F14).
- A Lua reset that doesn't kill engine async jobs, or a scoped reload of one script (F18; Ashlight's item 4).
- Screenshots that wait for streaming at the camera, and a client-side "streamed / LOD level" flag on VoxelData (F13, F21, F30).
- Reconnect and session resume in the native client (F3, F4).
- The promised CLI and MCP commands, shipped, or the guide gated by version (F32).
- Input injection for a managed test client (Ashlight's item 5, still missing). Every feel bug still needed the maker to find it: the ducking spring, strafing judder, viewmodel lag and self-collision.
Tools built for SCAR (in the project's tools/ and bench/ folders)
- Tests:
smoke_core.lua (14 checks) with run_smoke.py;preflight.lua (health checks with safe fixes);stress.lua (worst case).
- Profiling:
frames.lua (frame sampler, server or client);spike_probe.lua (all 149 engine timers per frame, spike frames against normal ones);watch_session.py.
- Benches:
bench/, for edit delivery to clients (F1, F2, F14) and gameplay edit cost (F12).
- Play-client telemetry: the
svDiag health line, readable on any server.
- Content:
cut_soldier*.lua and cut_weapons.lua turn a generated model into rig parts and HD viewmodel parts.
- Publishing:
publish_report.py publishes this report.
Bottom line
The engine connection is still excellent: an agent can measure almost anything on the server or on a client it can reach. An FPS shows where that stops. What each player's client actually has (terrain, streamed objects, hierarchy, UI) differs per client and per framing, and the play clients that matter most are the ones no tool can see. Make a play client observable, and simulable inside the editor, and most of SCAR's worst days would have been an afternoon.