From 58bdfb32dee3fbbd69049689afa24623e2427986 Mon Sep 17 00:00:00 2001 From: Fr0zka Date: Fri, 11 Sep 2026 22:01:47 +0200 Subject: [PATCH] docs: WORK-NEXT.md -- the queue after Sol's read-only audit Ordered by importance then size. Sol (read-only, xhigh) audited experimental @ aa62971 against main and delivered the two-sentence diagnosis this queue is built on: "The operator abstraction leaked into the innermost loop, and streaming treats 'work submitted/applied' as 'safe to stand on.'" Two corrections it made to us, both recorded in the doc: - The fall-through is NOT a removed correctness barrier. main has no spawn gate either, marks tiles loaded before applying, and collides only LOD0. It was fast enough to hide the race. The owner's evidence was real; the inference was not. - The loop inversion did not recover the 8x because it traded PER-SAMPLE short-circuiting (~70% of deep-solid samples skipped the cave suite) for per-block pruning. The fix is lowering the operator graph into a fused evaluator, not more dispatch removal. It also found that RMC cooks collision ASYNCHRONOUSLY and we never record cook-complete -- apply_s ends at submission, so nothing we have ever measured says when physics could actually collide. Reading Plugins/RealtimeMeshComponent is now permitted for item 1, READ ONLY, by the owner's decision. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012aheo2crrZmHuYtPpdY2Cb --- WORK-NEXT.md | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 WORK-NEXT.md diff --git a/WORK-NEXT.md b/WORK-NEXT.md new file mode 100644 index 0000000..0b23493 --- /dev/null +++ b/WORK-NEXT.md @@ -0,0 +1,105 @@ +# WORK-NEXT — the queue after the read-only audit (2026-09-11) + +Ordered by importance, then by size. Everything here comes from Sol's read-only audit of +`experimental` @ `aa62971`, checked against `main`. + +The audit's two-sentence verdict: +> *The operator abstraction leaked into the innermost loop, and streaming treats +> "work submitted/applied" as "safe to stand on."* + +**Standing rules for every item**: determinism is absolute (same build + same seed = same world on +every machine); output may change between builds; nothing is deleted to go fast; capability before +speed (player-fit 20,830 / walk-reachable 10,909 — do not drop below); scope is +`Plugins\VoxelForge` only, no links, absolute `-out=` paths under the plugin's own `Saved\`. + +--- + +## 1. Collision-ready before player-ready · CORRECTNESS · medium + +The player falls through the world. There is **no invariant** that a tile you occupy has collision. +`main` has no such barrier either — it was simply fast enough to hide the race. + +- `apply_s` ends at mesh **submission**. RMC cooks collision **asynchronously** and we never record + cook-complete. We have never measured when physics can actually collide. +- A tile enters `LoadedTiles` before its apply path completes (`VoxelWorld.cpp:1532`). +- Only LOD0 carries collision (`VoxelWorld.cpp:3109`), so visible coarse terrain can exist while the + collidable tile is still queued. + +**Do**: record cook-complete; gate the pawn (spawn and movement) on the supporting tile being +collidable, not merely applied. + +📖 **Reading `Plugins/RealtimeMeshComponent` is permitted for this item — READ ONLY.** Find whether a +cook-complete delegate/flag exists. ⛔ No edits, no builds against it: the owner's copy carries custom +modifications and was destroyed once by an over-broad delete. + +## 2. Lower the operator graph into a fused evaluator · PERFORMANCE · large + +This is where the ~8× lives (pre-op-stack `34f06df` did 128³ in 0.130 s; we are at ~1.04 s). + +A LOD0 tile samples 42,875 positions. The old path short-circuited the whole cave suite per sample +when `bNearCaveSurface` was false — roughly **70% of deep-solid samples**. We now allocate a rich +`FVoxelOpSample` per position, run each active operator across the entire block, use scalar fallbacks +for most operators, copy scratch in and out, and still call scalar `GetDensityAt` per grid point. + +> *An operator whose interval intersects the surface anywhere in the block runs across the whole +> block; the old path could decide per sample that expensive detail work was irrelevant.* + +**Do**: keep the authored operator graph, but **compile/lower it** into a fused evaluator that restores +per-sample short-circuiting and stops spilling `FVoxelOpSample` through memory per operator. +⚠️ Byte-identical geometry is the acceptance test. Stage it so the tree never breaks. + +Note: the D-floors/terracing features are only ~17% of the penalty — not the 8×. + +## 3. Cancel obsolete work, and prioritise the floor · BOTH · medium + +Nothing aborts a tile when the player moves and it stops being desired. Work is distance-sorted from +an artificial chunk centre, not the pawn, with no collision-critical priority +(`VoxelWorld.cpp:1864`). Up to 14 workers can be busy with stale coarse tiles while the player's LOD0 +floor waits. + +**Do**: abort no-longer-desired tiles; sort from the true pawn position; give the occupied tile and the +next tile along the heading absolute priority. + +## 4. Collapse the duplicated field semantics · MAINTENANCE · medium-large + +The effective field now lives in three places: the operator stack, the classifier's parallel interval +logic, and a post-stack repair tail in `GetDensityAt` (origin floors, passage structure, passage +floors, room floors). `FRoomGraphSource` evaluates the room graph then traverses tunnels *again* for +metadata (`VoxelDensityOpStack.cpp:4234`). + +The audit calls this *"the clearest sign of overengineering"*: later fixes compensating for where an +operation sits in the pipeline. It also makes interval proofs harder to trust. + +**Do**: make the stack the single semantic source of truth. Likely overlaps heavily with item 2. + +## 5. Prove the verdict cache earns its place, or remove it · small + +Zero outer hits in **both** traces. Global lock, linear scan, 512 entries, keyed on sample step so it +barely reuses across LODs. It helped a deliberately repeated commandlet case, which is not how a +moving player streams. + +**Do**: measure nested/outer calls, hits and evictions on a real session. If it is neutral or negative, +take it out and reclaim the memory. + +## 6. Three small, sharp ones · tiny + +- **The zero-position guard.** Streaming only starts when `GetPlayerPosition()` is not exactly + `FVector::ZeroVector` (`VoxelWorld.cpp:1167`, `:1359`) — a pawn at the world origin is + indistinguishable from "no pawn", and **the owner spawns at (0,0)**. +- **`ApplyMeshToTile` has no success return** (`VoxelWorld.cpp:3064`). If runtime-mesh init fails the + tile stays recorded as loaded and never retries — a permanent hole. +- **Whole-tile uniform verdicts are trusted without exact validation.** Block verdicts get checked + against the full grid when meshing; an outer AllAir/AllSolid verdict has no equivalent safety net. + +## 7. Deferred, with reasons +- **Coarse-first LOD refinement** — blocked until coarse tiles can carry collision, or item 1 lands. +- **GPU evaluation** — right hardware, but bit-exactness across vendors/drivers is unproven and + determinism is absolute. Item 2 is the honest prerequisite either way. +- **The origin spawn room** — the owner considers it a design mistake that should not exist. Design + conversation, not a fix. + +--- + +### Open design questions for the owner +- All five strate slots resolve to `DA_Strate3`. Intended? +- Should a composer roll be allowed to overwrite an explicitly authored value?