61b1c9c32927721afdda5a0bb582bfa782f53c67
100
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
61b1c9c329 |
research(intervals): one-day spike -- whole near region in 241 ms (6 workers), exact signs, far proxy 8.6 ms
Standalone C++20 (MSVC /O2 /arch:AVX2), no Unreal. A 372-shape corpus (rooms at the hardest profile's scale, winding tunnels, pillars, stalactites, shelves, floating masses, thin strata, rotated shapes, crowded junctions, craters), built two ways: point-by-point reference vs column intervals on 3 axes + 64-bit sign words + bit-scanned active cells + meshing from analytic crossings. 64 m near region at 25 cm (17.4 M nodes), 5 seeds, fresh processes: workers near CPU total (median/p95/worst) interval stage mesh stage (single-threaded) 1 349 / 358 / 358 ms 154 ms 188 ms 6 241 / 280 / 288 ms 48 ms 191 ms 8 240 / 271 / 277 ms 43 ms 193 ms Near mesh ~563k triangles, 13.5 MB; total output 19.9 MB; busiest line 58 candidates (< 64). Correctness: 0 sign mismatches vs reference at every node, 0 missing crossings/open contours, thin strata with no lattice node inside get explicit triangles (dropping them is caught), same hash on 1/6/8 workers and a repeated run. Far field: 47k nodes / 92k patches in ~8.6 ms, but fixed-grid ellipsoid sheets, not a validated cave hierarchy: unproven. No noise detail in this corpus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
413983f2d3 |
docs(research): Astra round 3 -- interval columns, packed sign words, surface-emitting hierarchy, 900 ms budget
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
8b87749771 |
docs(research): Astra round 2 -- shared shoreline curves, flowing stone, material-space deformation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
35e3d149d2 |
docs(research): Astra free-thinking round -- coarse structure + real surface relief, boundary-aware generator
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
bc0f9ee791 |
wip(step3): 12.5 cm voxels, fall-through fixed, brick evaluator in game, organic tunnels -- speed gate FAILS
Stopped by the owner's decision (in-game lit captures were eating the round); he judges the look in game instead. 1. Fall-through with the research field: fixed. Deep drop, gate on: 2 holds (0.50 s), min foot clearance +43 cm; gate off: penetrates (-278 cm). Stress fixture offsets converted to metres. 2. VOXEL_SIZE 25 -> 12.5 cm. Physical sizes kept in metres (player, steps, gate, insets, research field sizes, dig radii, test thresholds); class defaults that count chunks/voxels doubled (ClipRadius 6, RenderDistanceChunks 1536, ViewDistance*, StrateViewMargin 6, PawnCollisionRadius 2, SkirtCells 4, EdgeSealThickness 128, decoration spacings, density volume res 256). Asset values override these defaults: the owner must double his own. Ring scale, six workers, idle, step-2f field before the look changes: 64 m cube (519^3) 4.55 s; 32 m cube (259^3) 0.95 s. 3. In game: tiles go through the brick evaluator (proved by a log marker); profile switch rebuilds the loaded world (~5,800 tiles); full-detail fill 12.4 s after spawn in the visible-window test. 4. Look: round winding tunnels, per-column ellipsoid/lattice caches. All step-2f geometry gates pass at 12.5 cm (0 crumbs, 1 solid component per profile, solid share 69-87%). 259^3 ring, six workers: 1.08-2.02 s (worst HyperComplex) -- the 600 ms gate FAILS. Lit captures failed (hidden/off-screen window, then blank frames); not pursued. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
ca78352e43 |
research(step2f): coherent caves pass every gate, worst 572 ms idle -- look still to be judged in game
Editor-only, default off (voxel.ResearchParameterizedCave 1; the live skip proofs now decline automatically). Jittered elliptical chambers of varied size and height with rock between them, narrow tunnels, capped shafts, occasional pillars/ledges/stalactites/stalagmites/hanging masses; detail bands at 48/24/12 samples (shortest 3 m), bound 3.822. Gates, step 2e -> step 2f R29 (worst of 8 profiles), each rejecting 2e: crumbs < 1 m^3 2,290 -> 0; dihedral >45 deg 40.7% -> 2.2%; lattice detail energy 0.83 -> 0.007 (RMS floor kept: 0.484 >= 0.40); LOD1 distance p95 0.709 -> 0.377 samples; grid autocorrelation 0.667 -> 0.348; solid share 2.7% -> 79-82%; roof/floor openings 26,657 -> 0. Speed, 259^3 ring, six workers, idle machine (20 GB free): 527-572 ms, worst TerracedBasin 572.3 ms (R27 591 ms, R28 603 ms: run-to-run spread is ~5%). Proof audit 0 violations, undersized control caught; seams pass; 1 vs 6 worker hash 876069a813c83cee; TraversalSeeds pass. Captures are UNLIT (lit runs showed only sky; three D3D12 device-removed crashes): they show the material's tiling, not the cave forms, so the look is not yet judged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
d6555df5fa |
wip(step2f): coherent field -- flakes, speckle, grid, roof fixed; 3 crumbs + 636 ms left; last edits UNCOMPILED
Stopped by low memory (another app at 14 GB; processes failed with 0xC0000142). r6 (compiled and measured, owner playing during the run), step 2e -> step 2f r6: crumbs < 1 m^3 (max per profile) 2,898 -> 3 FAIL (0,0,0,0,2,1,3,2) flakes (shard share / p95 angle) 40.7% / 84.2 deg -> 2.1% / 33.1 deg pass lattice-scale detail energy 0.832 -> 0.016 pass grid signature (autocorrelation) 0.666 -> 0.349 pass min solid share / roof openings 2.7%, 26,657 -> 79.2%, 0 pass worst profile ring time 642.8 -> 636.3 ms FAIL (6 workers, 259^3) Step 2e measured 642.8 ms here vs 570 ms idle earlier: the game was costing ~12% during this run. Brick proofs + audit, seams + injected seam, 1 vs 6 worker determinism pass. After r6, feature probabilities were lowered to remove the last crumbs: NOT compiled, NOT measured. TraversalSeeds, in-game captures and the LOD-rejection figure for 2e are still to do. Reject screenshots included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
0a7492ffab |
research(step2e): 8 parameter profiles, worst 570 ms -- speed gate met, look NOT yet accepted
Editor-only, default off. Seeded chamber graph (jittered XY grid, spanning tree, optional loops, tunnels, shafts, pillars, ledges, spires, floating masses, basins), 8 profiles, four detail bands at every surface-affecting 25 cm sample, sound brick proofs. 259^3 ring, six workers, medians of 3: 404-570 ms (worst TerracedBasin 570.0 ms). Detail, seam, bound-audit (0 violations, undersized control caught), determinism (1 vs 6 workers) and TraversalSeeds all pass; live tests untouched. Not accepted yet: the profiles are 81-97% open air. In the slices a "TightNetwork" is a large void with scattered solid blobs (rooms of 0.5-0.76 x pitch overlap and merge), and the finest detail band shows as salt-and-pepper speckle with 22-109 separate 1 m components per ring: fast partly because air bricks skip, and the look needs the owner's judgement. Also missing vs live: maze, flat/plain, crystal-chamber, surface-world and underwater grammars; water geometry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
f8a46ecf8d |
wip(step2e): parameterised chamber-graph model -- compiles, traversal test PASS; benchmark not run
Stopped by low memory (another app held 12.5 GB; processes failed with 0xC0000142). Editor-only, default off: a seeded connected room graph (varied chambers on a spanning network, optional loops, shafts, rock features, ledges, basin floors), eight parameter profiles, the step-2d brick driver and detail bands, a new test VoxelForge.ParameterizedGeneration.TraversalSeeds (PASS in step2e_functional_01, which also proves the tree compiles). Existing live tests untouched. Not yet run: the eight-profile ring benchmark, variety metrics, slices, detail/artefact/determinism checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
78641da0bb |
research(step2d): a simpler field is fast (81 ns/sample) -- but it is not the owner's world; NOT a pass
Editor-only, default off (voxel.ResearchRedefinedDensityField). The redefined field is a seeded, periodic cross-corridor pattern per strate plus the authored passages, landings and a shaft tree, with four value-noise detail bands at every near-surface 25 cm sample and sound 8^3 brick proofs. 259^3 ring, six workers: 308 ms median (467 ms without skips) vs 8.9 s for the live field. Detail, boundary-artefact, determinism (1 vs 6 workers, two runs) and bound-audit checks pass. Why it is not a pass: the slices show a mostly-solid field with a few straight corridors, where the owner's world is mostly open space; rooms, the tunnel network, composer recipes and archetypes are gone. Much of the speed comes from 60% of bricks being proven solid in that simpler world. What it does show: detail at full resolution plus brick skipping costs ~80-130 ns/sample; the cost of the live field is how rooms/tunnels/passages are represented, not the detail or the lattice. The two walkability tests were redirected to the research field in the working tree; that change is NOT committed (saved as scratchpad step2d-test-redirect.patch) so they keep testing the live world. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
d6e021a80b |
docs(research): step 2 verdict -- exact per-sample density cannot reach 600 ms
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
43c11ccaa8 |
measure(step2c): setup once per chunk, still 1.6 us/sample -- exact per-sample density misses 600 ms
Editor-only, default off. 259^3 ring split into 1,000 aligned 32^3 chunks; cache/index builds bounded by chunks (948 room/SDF caches, 800 active-op lists, 8,532 index tables); 800 block setups + 201,243 scalar fallback points (1.16%); no per-point GetDensityAt on supported routes. Six workers: live 7.07 s wall / 1.678 us per sample; prepared 7.92 s / 1.595 us. Candidate visits 21.2 -> 15.8 per sample, evaluations 6.31 -> 5.75; room / tunnel / tunnel-core evaluations unchanged (48.1 M / 5.0 M / 38.4 M for 17.4 M samples). Passage evals 18.1 M -> 8.4 M. Exact: 0 Q16/sign disagreements, five seeds, same hash on 1 and 6 workers, reach shrink caught. Luna's verdict: 600 ms is not reachable while every lattice point evaluates the exact current density; 27.7 worker-CPU seconds need >= 7.7x less work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
fd9f809c1c |
measure(step2b): per-brick setup rebuilds the chunk caches -- 10x slower; live cost attributed
Editor-only brick API (<= 8^3 points per call, TunnelNetwork/Underwater op-stack routes, 1.16% scalar fallback). Exact: 0 Q16/sign disagreements on the full 259^3 ring and the five-seed probe set, same hash on 1 and 6 workers, reach shrink still caught (18,107 Q16 / 735 sign). Speed: 69.19 s wall, 17.6 us/sample vs live 7.04 s, 1.65 us/sample. Stack sampler (inclusive): BuildChunkCache 93.5%, PropagateSdfOverBox 92.5%, BuildActiveOpList 92.6% -- each brick rebuilds the cache windows and active-op lists; EvalBlock itself is 3.6%. Live path attribution (inclusive, 68,934 stacks): op-stack RoomGraph EvalBlock 54.4%, SDF and spatial candidate scans ~28%, tunnel core 18.4%, passage floor segment 15.0%, structural posts 14.6%, noise octaves 2.6%, disturbances 0.6%, diff layer 0.3%. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
41a9265ebd |
measure(step2a): candidate bins alone are slower -- the per-sample GetDensityAt call must go
Editor-only ablation (explore commandlet, -regioneval, default off): 8^3 bins for rooms, room-floor joins and tunnel chains, but every point still goes through GetDensityAt. 259^3 ring, seed 1337, six workers: live : 6.776 s wall, 29.16 s worker CPU, 1.679 us/sample, 21.2 candidate visits/sample binned: 19.54 s wall, 50.02 s worker CPU, 2.879 us/sample, 16.4 candidate visits/sample Correctness: zero Q16 (x16, ties away from zero) disagreements on the full ring and ~284k probes on 4 more seeds (composer recipes, warped rooms, passages, landings, strate edges, edits); shrinking room reach to 0.5 -> 18,107 Q16 / 735 sign differences (the check bites). Not the planned region program: the step-2 question is still open. Baseline for the next attempt: 1.68 us CPU per sample on the live path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
3b4d6855fe |
docs(research): record step 1 verdicts in the build plan
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
41b001b652 |
measure(step1): cook is 1.5-2.3 ms, RMC's route is 8-11 s; CMC cannot take a field floor; cap 16 uploads
Rebuild plan step 1 (RESEARCH-SPEED-2026-09.md), all behind default-off switches. A. Direct cook on a dedicated thread, 27-tile support cohort: core cook p50 1.50 ms, p95 2.28 ms; a 3,949-tri tile 1.67 ms extract+cook. PASSES the 10 ms gate. Through RMC's route the same support bodies became ready 8.46 s p50 / 10.80 s p95 after their meshes existed: FAILS 150 ms. Exact-target capsule sweep confirmed (0.75 ms after body update). B. 100 rapid underfoot digs on CMC with a field override: 883 false-support frames, 0 false-air, 0 invented velocity. CMC's floor comes from collision-scene traces -> step 4 = field-aware Mover. C. 341 prequeued tiles, render on: cap 4 = 238 applies/s, cap 8 = 476, cap 16 = 639 (drain p95 2.22 ms vs 2 ms gate); first visible 1 frame after release; no RT/RHI backlog. Tune drain, no grouping needed yet. D. Same 128^3 region, 64/64 tile hashes equal in export and game. The "263 ns/sample" was export WALL time with 15 workers sharing a lattice (~3.4 us CPU/sample); game tile time includes meshing and duplicated borders (+22%); contention cap 1 vs 14: 74 vs 112 ms per tile. Profiling is not the cause. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
97a1874498 |
wip(step1): collision/upload clocks behind default-off switches -- partial, stopped on low memory
Compiled and run (cap 14 / 12 / 8), then stopped: another app held 12.5 GB, free memory fell under the 6 GB launch floor and processes failed to start (STATUS_DLL_INIT_FAILED). Measured so far (owner world, 120 s windows): - 343 L0 tiles, request->collision-ready p50/p95: cap 14 = 262/440 ms, cap 8 = 196/238 ms; scheduler queue wait p95 141 ms -> 0.9 ms. Initial support tile at cap 14: RMC submit->body 7.47 s, first check->ready 9.73 s; at cap 12: 0.33 s / 2.54 s; at cap 8 a 3,949-tri tile reached body update 2.8 ms after RMC submission. Waiting, not cooking, dominates. - NOT confirmed: a capsule sweep hitting the exact target body (the 0.75 ms hit was another component); the 10 ms core-cook and 150 ms/27-tile thresholds are unscored. - CMC cannot take a same-frame density floor: FindFloor/ComputeFloorDist trace the collision scene. Underfoot digs (100-dig test), upload throughput (render-enabled caps 4/8/16) and the 8x per-sample question are not run. Per-sample profiling was fully disabled in these runs, so it does not explain the 8x. Switches (all default off): voxel.Step1GenerationCap, Step1PauseGenerationAfterSeconds, Step1MaxMeshApplies, Step1PrequeueVisibleLOD0, Step1UploadDisableCollision, Step1CollisionProbe, Step1CoreCookBenchmark; harness -EnableRender. Also: plan step 3b, AVX2 need not match scalar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
6d2a068308 |
docs(research): step 3b -- AVX2 check against the new evaluator (owner's request)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
153798f436 |
docs(research): consolidated decision -- float region programs, quantized lattice, gated build plan
Round three (Sol fork): keep precise float procedural math, restructure evaluation (region programs, feature binning, brick certificates, shared lattice), a versioned 16-bit lattice as the common mesh/edit/collision cache, integer edit composition on GPU for craters. Seven ordered steps, each with a numeric pass/fail gate; day one instruments collision and upload clocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
3de7ce1420 |
docs(research): round two -- wider search, AVX2 integer probe, crater transaction design
Fork of the Sol research session with the owner's answers (player-only 1 s collision; bounded digging but fast crater spells). AVX2 integer kernel 4.25-5.86x over its scalar reference with exact parity; radius-10 m crater = 714 bricks, cached-field edit < 1 ms (render not measured). Cost estimate revised to 6-12 engineer-months; kill test gate <= 0.35 s worker wall on real plans. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
1568f76ca2 |
docs(research): speed research -- sparse compiled bricks, field collision, edit transactions
Sol 6 (high, web search) research round: recommendation, three architectures, determinism contract, migration with a 5-day standalone kill test. Standalone probe in Saved/Research/brick_kernel.cpp (not VoxelForge code): 16.8M integer samples in ~0.36-0.48 s, brick-classified ~0.1 s, 0 sign mismatches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
bf22f0ffe0 |
perf(collision): cook stages measured, no standing on dug-out ground; review F/H/E measured
1. Collision cook breakdown (request -> ready), critical support tile: spawn (0,0,-1): generate 107 ms, apply < 1 ms, RMC submit->body 479 ms, total 587 ms; deep floor (0,0,-7): generate 82 ms, RMC 1,441 ms, total 1,548 ms. Almost all of the wait is inside RMC (end-of-frame update + async pool + Chaos cook + body install, not separable from our side). Critical priority does not shorten it. Collision is async, complex-as-simple, fast-cook off; skirts are ~16-18% of collision triangles. No cook change made. Startup outlier: first support tile waited 2.09 s for its game-thread apply. Underfoot dig: a carving brush that intersects the pawn's capsule and support tile now disables the old body and withdraws readiness on the carve frame: 0 frames standing on removed ground (replacement 91.8 ms later). 8 neighbouring digs: 0 gate frames. Gap audit 0. 2. Stack sampler, 49.4 s game path: top resolved leaf was the profiler's own VoxelDensityProfile::BucketFromName (4.86%). Linear label scan -> CRC-keyed lookup with exact compare: 59.26 -> 57.87 ms/tile (-2.35%), 980/980 tile hashes identical. 3. Measured only: F (classifier mode 1, no exact check) +48% worker CPU, 0/980 tiles differ -> not worth it. H (handoff component scans) p95 0.07 ms/frame -> not worth it. E (FullResClipLevels=1): worker CPU 56.7 -> 35.7 s, settle 9.6 -> 7.0 s, crossing samples -30%; changes the look, owner's decision. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
ce6812dbeb |
fix(streaming): no false gate on digs, no see-through at tile handoffs; density volume off
- Dig near the pawn: a same-tile collision recook withdrew readiness although the old body was still installed, so the gate held a standing pawn (957 of 1,931 frames over 8 near digs). A tile now stays ready during a recook while collision is still wanted and its existing body is valid. After: 0 gate frames, 0 falling frames over 2,604 frames. Dig directly under the pawn still falls (~127 cm, max ~502 cm/s). The reported "accelerating toward the ground" was not reproduced; the false hold is the measured part. - See-through: the retire logic only waited for replacements that overlapped the old tile in volume and missed desired neighbours touching at a face/edge/corner. Handoff now includes contact. New surface-witness gap audit (24 surface points per tile, skirts excluded, catches an injected early hide). 6000 cm/s walk, 75 s: 3 gaps / 51 frames / longest 603 ms -> 0. Dig session: 0 -> 0. Overlap audit and edit ghost stay at 0. - bEnableDensityVolume defaults to false; when off: no volume, no fill thread, uploads or tick work, no volume-dependent proof bypass; terrain MIDs get VolP5.z = 0 (enable off), other VolP* black, VolTex* null, so M_Test1's volume nodes return their neutral result. Gate: deep gate-on passes (79.9 m, 3 holds, -0.101 cm), gate-off penetrates (-5.1 cm). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
0bcd67a016 |
perf(review): gate never deadlocks, collision radius, 20x faster digs
From the outside performance review (items 1-4; item 5 prototyped and reverted).
1. Collision gate: a support request outside the stamped desired set was cancelled by the rebuild
it forced, and the gate held the pawn with gravity 0. Baseline deep-drop (floor at (0,0,-7),
outside the aligned L0 ring): 1 hold of 30.0 s, never released. Fix: the target and 3 tiles
below are retained through rebuilds at CollisionCritical; hold only when the swept capsule is
about to enter pending support; release restores movement mode, gravity and downward speed.
After: 3 holds, 2.21 s total, 112.8 m horizontal progress; gate off still penetrates (-7.4 cm).
2. Suspected cleanup regression (out-of-layout stacks): not real. 44 paired boundary tiles,
30.9 ms vs 32.6 ms at
|
||
|
|
116b57f01e |
wip(gate): support column kept through rebuilds, hold only on swept contact -- NEVER COMPILED OR RUN
Stopped mid-round: the PC ran out of memory (another app held 11 GB), new processes failed to start (0xC0000142), and the round ended without verifying anything after the edit. Confirmed in code (performance review finding 1): a support request outside the stamped desired set forces a rebuild that cancels it, the gate asks for one unresolved tile at a time, and it holds before the pending tile is anywhere near the pawn's next step. Uncompiled edits: a short collision-only support column retained through desired rebuilds and prioritised; hold only when the swept capsule is about to enter a pending tile; downward speed restored on release; opt-in deep-drop fixture (carved shaft) in the stress harness. Evidence so far: shallow 10-voxel fall, gate on, before the edit: 1 hold of 1.51 s, clearance +120.6 cm. The 80/160-voxel attempts spawned OUTSIDE the strate layout (support unavailable, zero holds) and failed the penetration check at -11.1 cm: not the reviewed loop, but worth a look. Compile risks: GetGravityZ(), TSet pruning in the rebuild, the fixture's carve/log arguments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
0b8fbc5591 |
Merge pull request #14 from Fr0zka/cleanup/2026-09
Cleanup/2026 09 |
||
|
|
b4ac9969f5 |
fix(passages): skip proofs cover the new descent geometry -- soundness PASS; passage tiles +28% cost
- Passage proof bounds now enclose everything the passage code can write: separated switchback
legs, outward door approaches, native floor slabs with a derived relief supremum, and the final
body-envelope carve (segment XY extent + half-width, floor range + player height + step).
- ClassifyTile: the cave-only AllSolid shortcut could restore a solid verdict after a passage
carve candidate was found; it now keeps the tile mixed.
- Descent corridor test asserts no corridor stencil tile gets a uniform verdict.
Evidence: SealedSolidProofSoundness and ClassifyTileSoundness pass; 64 owner seeds, 0 body
blockers, 0 uniform stencil tiles, CRCs match. Negative control (passage reach shrunk to 4 voxels):
7 sealed-solid proofs among 620 corridor tiles, i.e. the check bites.
KNOWN COST, not fixed: tile profile, owner world, seed 0, 15 s window: passage-candidate tiles
83.6 ms (
|
||
|
|
fb052716c6 |
wip(passages): A->B descent corridor clear -- 60/64 seeds blocked -> 0/64; soundness + cost not yet checked
What the pillars were: at switchbacks the native-floor D-section clip in UVoxelStrateManager::EvaluateModifierSDF used ONE floor branch (the nearest by projection) for neighbouring capsule segments, so one leg's floor clipped the other leg's carve and left rock standing in the corridor (seed 0 witness: density -29.45, carve SDF +3.28; with voxel.TunnelAblateNativeFloor=1 the same point is air). Separately, the lower ramp was routed through the lower landing room (sign error in the lower "outward" score), where room ownership correctly erased the tunnel floor: up to 12.5-voxel drops. Fix: each segment clips with its own floor branch before the union; switchback legs separated and door approaches moved outward so ramps leave their landing rooms; a final carve clears the player body envelope (1.36 + 2x1 voxel wide, 1.8..8.8 voxels above the route floor) after all writers, with a room-SDF guard. No floor slab, no fill, no blockade on the through edge. Owner world, 64-seed sweep, stations every 0.5 voxel x 5 lateral x 14 heights: before 89,603 body blockers in 60/64 seeds; after 0 in 64/64, 0 floor/width gaps, worst step 0.958 voxels (limit 1.8). Seed 0 built twice: identical density CRC. Crossing at default speed still stops on capsule_overlaps_pending_floor (also before); 500 cm/s reaches B. NOT YET CHECKED: sealed-solid / classifier soundness against the moved passage geometry, and the generation cost of the per-segment projection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
de05e293aa |
docs(codemap): aligned clipmap rings, indexed reconcile, immediate gate support, two new tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
6ee433efa5 |
test(gate): stress repro judges terrain penetration -- gate on 10/10 clear, gate off 3/3 falls through
The old criteria (travel distance) could not tell a working gate from a broken one: every run,
gate on or off, ended at (455.7, 0, -58.1). That spot is measured air ~1.2 m above a real floor
(density zero-crossing at world Z ~ -275.7 cm), so it is a terrain trap, not a fall-through.
The stress test now drops the pawn fast onto an unready support tile (0,0,-1) and samples the
density at the capsule feet every frame, sweeping at <= half a voxel between positions. PASS =
no measured clearance below -5 cm.
Owner config (radius 3, max level 6, distance 768, sheets off):
- gate on: 10/10 PASS, min clearance +120.5..+120.9 cm, one hold of 0.43-0.47 s each,
support submitted in ~0.7 ms, collision ready in 0.43-0.47 s
- gate off: 3/3 FAIL terrain_penetration, clearance -5.7..-8.1 cm
Edit-ghost, clipmap no-overlap sweep: pass. Test-harness code only; no production path changed.
This validates
|
||
|
|
a49725d365 |
wip(gate): request the support tile at once; no gate timeout -- stress criteria NOT trusted yet
- RequestCollisionGateSupportTile submits the level-0 support tile immediately, even before the
first desired set; the desired rebuild adopts the same pending key (1 early request, 1 adoption,
1 ready callback in all 10 runs). First check -> submit went from ~2.2 s to ~1 us.
- The 2 s gate release timeout is removed: at the owner's startup the game thread applies nothing
for ~2.2 s, so the timeout always fired and dropped the pawn. The gate holds downward Z only;
horizontal movement stays free.
- Controls (previous round): legacy selector+reconcile failed the stress repro 0/5, aligned 1/5,
so
|
||
|
|
85a803b873 |
wip(streaming): LOD rings tile exactly once, cache race, reconcile 104x -- gate stress FAILS 3/4
- Clipmap: finer rings snap to child-pair boundaries, so no two desired tiles of different levels overlap. Owner config 635 overlapping pairs -> 0; LOD0 ring 343 -> 512 tiles. New test sweeps 6,174 cases; fails on |
||
|
|
7486c299d4 |
fix(streaming): no stale geometry over its replacement -- edit ghost 40s -> 0.17s
The owner reported a wall staying visible after he carved through it, and overlapping LODs when crossing slopes at speed. Two causes: an edit only re-meshed the level-0 tiles of the touched chunks, so coarser tiles kept pre-edit geometry until something else re-queued them; and superseded tiles stayed drawn until the budgeted teardown reached them. Now: edits fence late pre-edit async results and re-mesh every affected loaded/pending level; a replaced tile is hidden as soon as its replacement is fully covered, while destruction and collision removal stay budgeted (the anti-spike rule that made teardown budgeted in the first place). Load-before-unload is unchanged, so no holes. Measured: edit ghost 40.095 s (unresolved at test exit) -> 0.172 s; 6000 cm/s slope overlap 19.952 s with 153 overlapping pairs -> 0.000 s with zero events. Gate stress PASS (113.68 m, 2 holds, 0 full stops). Apply-frame cost peaked at 0.979 ms against a 2 ms budget. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
f36bc1f9b2 |
wip(streaming): priority by class and level -- near ring 53.6s -> 1.2s, but crossing test fails
Scheduling rule: CollisionCritical -> Edited -> LOD0 -> Horizon, with coarse work capped so 4 task slots stay reserved for near work; result queues follow the same order; epoch and cancellation handling unchanged.
Measured at MaxClipLevel=5 / RenderDistanceChunks=768: spawn ring request-to-ready 53.632 s -> 1.171 s; spawn ring from trace start 68.252 -> 62.549 s; moving first complete ring 66.808 -> 63.917 s, warm ring p50 0.267 s, per-tile moving LOD0 p50 69.4 -> 62.0 ms; full settle of 10,841 tiles 110.7 -> 106.9 s. Gate stress PASS (139.99 m, 0 full stops); static perf PASS.
⚠️ NOT SAFE TO MERGE YET: the strate-crossing test fails in both patched runs with capsule_overlaps_pending_floor -- the exact guarantee the gate exists for. Codex suspects the owner's current DA_Settings (seal 50, clip level 5) rather than this change, since older passing captures used different settings. Control needed: same test, same assets, on
|
||
|
|
370c39e473 |
feat(streaming): horizon distance with real tiles only -- sheets off by default
The sheet system models terrain as one ground and one cap height per column, which cannot express this world's overhangs, floating islands and open sky; three attempts to fix the MC/sheet seam produced holes, then caps over the void, then both. Measured alternative: cover the render distance with real marching-cubes tiles and switch the far-sheet ring off. Benchmarks at RenderDistanceChunks=768, all tiles loaded at steady state: L4 57,473 tiles / 30.1M tris / 837 MiB / 2,514 s worker / 296 s to settle; L5 10,841 / 8.1M / 226 MiB / 375 s / 108 s; L6 3,281 / 2.9M / 82 MiB / 127 s / 77 s. Defaults now MaxClipLevel=5, bFarSheetRing=false. Invariants: strate crossing PASS, gate stress PASS (140.06 m, 0 full stops), determinism PASS with 10,841 tile hashes identical vs -voxel.CrtFma3=0. Peak memory ~4.2 GiB in all three. Owner action required: his DA_Settings still serializes MaxClipLevel=3 (asset edits are out of scope for Codex), so his world needs that value raised to 5 to use the new far field. At twice the distance the estimate is ~39.5k tiles / 29-30M tris / ~0.8 GiB / ~1,500 worker-seconds, which would want L6 rather than L5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
ea3f0d9a52 |
fix(classifier): exact lattice check before a uniform verdict; ceiling cause is NOT false certificates
ParameterRoll's 5 false box verdicts are fixed: fine room-graph intervals are now checked against exact lattice samples before a uniform verdict is accepted, while the SDF bound keeps its conservative lower bound. Lattice sweep 600 tiles / 0 violations; ParameterRoll passes with 9,577 exact lattice leaves and 774 interval disagreements caught. The owner's ceiling holes are NOT explained by this: in his recorded session outer_classifier_mode=0, solid-proof skips were 0, and air-proof skips were outside the strate. The trace points at the far-field sheet system instead: sheet tile L5 (0,1,0) is deliberately empty inside the sheet hole while its bridge tile L4 (0,1,-1) meshed 662 ceiling triangles. Continuous ceiling is NOT verified: every render launch failed (D3D12 driver error, stalls before map load, the 6 GB cap), so the round produced no matched after-render. Cost note: this round used 3.46M tokens on Luna 6 at max, most of it burned on failed render launches. Verification by render is unreliable in this harness; verify ceiling continuity from tile/geometry data instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
30253f0e89 |
fix(streaming): vertical reach follows the strate, and the level below the sheet ring is filled
The owner marked missing tiles around him in a 64-chunk surface strate with RenderDistanceChunks=768. Cause: the desired-set vertical clamp used the player's small window (bClampViewToStrate on, ViewDistanceUp/Down=5, margin 3), so at chunk Z=0 only [-5..3] was ever requested; the rest of his strate was never asked for. Second cause: with MaxClipLevel=3 and a two-level sheet span the outer ring is level 5, while the marching-cubes loop stopped at 3, leaving level 4 empty. The band now follows the player's whole strate plus margin ([-66..3] in the pinned case) and keeps the small window only when there are no strate bounds (inter-strate gap), so the hidden-rock column the clamp exists to avoid does not return. Bridge shells are emitted up to the level below the sheet ring, filling level 4. Pinned case desired tiles per level, before -> after: l0 343->343, l1 218->218, l2 129->178, l3 80->178, l4 0->178, l5 4801->9586; total 5,571 -> 10,681 (+91.7%). New focused fixture VoxelForgeVerticalStrateReachTest fails before and passes after. Stress repro passes (140.089 m, 4 holds, 0 full stops); strate crossing passes (0 holds, 0 floor overlap). ⚠️ Cost not established: the post-fix perf sample was incomplete and showed a 55.7 s p50 queue wait, which may be the fixture's extreme settings (768 render distance -> 9,586 sheet tiles) or a real backlog. Measure in the owner's world before merging. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
d7af2cab97 |
fix(collision gate): hold the fall, not the player; add voxel.CollisionGate switch
The owner could not do speed runs: the gate stopped the whole pawn whenever streaming fell behind. Measured at 6000 cm/s on
|
||
|
|
88f3e44402 |
wip(collision gate): stop the fall instead of the player -- UNVALIDATED, after-change run never happened
The round was stopped when Windows began refusing to start processes for it (0xC0000142) under memory pressure, before any after-change test run. Treat as a draft: the baseline run happened, the verification did not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
0dd45ca410 |
fix(collision gate): stop freezing the player on a stale prediction
The owner fell through a surface-only world and hovered in mid-air: log showed 'ready=1 predicted_wait=1' for 50 s. Two causes, both fixed: (1) engaging the gate zeroes velocity, so the predicted-support probe never re-ran and the gate kept waiting on the tile remembered from when the pawn was still moving -- the prediction is now re-derived every tick from the pawn's current pose; (2) a tile the streamer never requests (out of layout, or outside the desired set) could never become ready, so the wait was unbounded -- such tiles are now logged and treated as nonblocking, and any wait is bounded to 2 s with a warning. Repro added to the harness (surface-fall scenario): before, the pawn stops at Z=1315.9 with collision_gate_prediction_deadlock; after, it reaches the ground in 2.25 s at Z=-45.6. Strate crossing still protected: 145.49 s route, max gate wait 0.109 s (limit 10 s). Perf S/M/S/M 24.265/54.262 and 23.947/53.057 s, within repeat noise. Owner and canonical geometry unchanged (44E7C813 / 94B47A1C). Known red, pre-existing and unrelated: VoxelForge.Composer.ParameterRoll still reports false box verdicts in the owner's current single-strate surface layout (5 violations, identical in the baseline). Next round. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
7af8d0e870 |
fix(correctness): false AllAir certificates and a stale shaft cache key; 44/44 tests green
The harness's first full suite run showed 16 of 44 tests failing. Two were real defects in the owner's world: 1. ParameterRoll: the tile classifier could certify a box AllAir while the final field is solid there (3 false proofs found, e.g. density -2.092319 at (-192,16,-224)). Cause: the box diagnostic narrowed 'tail reach' to 'air reach', so the swept tunnel FLOOR -- which writes solid -- did not count as reaching the box. A false AllAir skips meshing, i.e. missing floor in game. The classifier now uses the same reach predicate as the final writer (swept chain, floor band, relief, room-mouth envelope) and propagates it through Mixed refinement nodes. Re-run: 1,288,143 lattice samples, 0 violations. 2. VerticalShaftEquivalence: LedgeSpacing and LedgeDepth were missing from the production TLS cache key, so a shaft could reuse stale ledge parameters. Both are now in the key. The other 14: broken fixtures (missing staged corpus assets, a sampler leaking the shaft TLS marker between queries, stale candidate IDs, a window entirely inside the common tail) or stale expectations after this week's owner decisions (no authored tunnel floor, slope in degrees, rooms owning their interior). No test was deleted or weakened into vacuity; retired legacy comparisons stay as telemetry and the current stack is asserted instead. PassageLandsInOpenSpace now requires a real player-capsule fit in the final density at each authored landing (14/14, worst gradient 0.115723). Suite: 42 tests green in one run, the two long op-stack sweeps green in serialized filtered runs (the 1800 s launch guard); a harness timeout-recording bug was fixed. Bounded probe exports unchanged (canonical 94B47A1C, owner 44E7C813). ⚠️ Harness perf scenario moved 50.74 s -> 53.58 s worker (+5.6%): the wider reach predicate skips fewer boxes. Measure on the game path and decide before merging. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
cc04c0bd4e |
chore(tools): untrack a stray __pycache__ artifact
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
a7b8d10de6 |
tooling(test): one command to test VoxelForge, with a commandlet-vs-game parity check
Tools/VoxelForgeTest.ps1 runs scenarios (canonical, owner, probe, perf, tests, parity) with the known-good flag sets, isolated user/config dirs, serialized launches, an owner-process guard, and a compact result.json + summary.txt instead of 300 MB logs that Codex has to stream. Answers the owner's question 'can the commandlet reflect in-game behaviour': -gameconfig=1 makes the commandlet use the authored settings, and the parity scenario compares per-tile geometry hashes between the commandlet export and the game's streaming path. Parity PASS: 64 commandlet tiles vs 810 game records, no differing tile. First run of the tests scenario: 44 tests, 28 pass, 16 fail (8 composer, 6 op-stack equivalence, PassageLandsInOpenSpace, StrateParamBlendCoverage). Triage is the next round: stale expectations from the floor removal and the degrees change, versus real defects, especially the legacy-vs-op-stack equivalence ones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
1c642fd182 |
perf(tunnels): memoise the room mouth -- room ownership now cheaper than before the change
The room-wins rule cost +55% static / +36% moving worker CPU because every sample re-answered the room-mouth question. A bounded exact memo around BuildRoomMouth (4096 sets x 4 ways, 7.49 MiB, keyed on every geometry-affecting room/tunnel input) removes that: hit rate 99.91% static / 99.89% moving, and VF_FindRoomFloorCrossingWorld (19.5%/17.1% inclusive), VF_FindRoomMouthBoundary (16.0%/14.0%) and VF_EvaluateRoomLandingDensity leave the sampler's top 30 entirely.
vs the tip DLL (
|
||
|
|
76bc8bce97 |
docs(work-next): room-wins result, checks passed, and the perf regression it introduced
Crossing PASS (248 m, 26.6 s), TilePostReachProof PASS, DetSinCos PASS, canonical export identical with -voxel.CrtFma3=0 (86A99075), walk Connected 42,870 / 17,413. FAILED: one S/M/S/M pair on the owner's staged map shows worker generation 47.7 s vs 30.7 s static (+55%) and 83.1 s vs 60.9 s moving (+36%), request p95 +19-28%. The room-ownership containment test now runs per sample in the generic tunnel SDF, the core evaluator and both native fallbacks. Next round: same geometry (export hash must stay 86A99075), cost back to the tip's level. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
d01af4606d |
wip(tunnels): room wins over tunnels -- no shelf, smooth mouths; stopped before final checks
Stopped by the owner (he wanted his PC back to play) after most acceptance was in. Measured with the owner's assets: the shelf across rooms came from the tunnel core reasserting solid below its floor inside room volumes, plus the landing-floor post. Room ownership now suppresses the tunnel bottom in the generic tunnel SDF, the core evaluator and both native fallbacks: tunnel-attributed solid inside rooms 469 -> 0, and a matched-camera re-render shows the slab gone. Trimmed mouth endpoints now take their height from the room's own vertical zero crossing (join offsets -2.08/+0.40 -> -1.13/-0.71 voxels). Mouth surface periodic amplitude 1.49 cm floor / 0 cm wall (degree-six trend removal; raw local-median audit 6.19 cm kept). Canonical walk Connected, 42,870 fit / 17,413 walk-reachable (was 41,184 / 13,879); export 141,054 triangles, geometry hash 86A99075. Launches use an isolated engine saved/config directory so the owner's editor settings are not rewritten. NOT DONE: the -voxel.CrtFma3=0 export comparison, TilePostReachProof / DetSinCos / strate crossing, the perf pair vs the experimental tip, the EditorSettings.ini diff. Unvalidated in game. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
01cb9d47f1 |
docs(work-next): tunnel playtest night -- rib cause, removed floor, what's queued
Records the owner-playtest findings (stale editor build, owner assets vs harness defaults, the 0.1 slope freeze, ribs with every terrace setting at 0), the proven rib cause and its fix on fix/tunnel-shape, the reverted Catmull-Rom attempt and why its evidence was wrong, the in-editor ablation procedure (cvar read once at first Play), current canonical numbers, and the queue awaiting the owner. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
4fa3931176 |
fix(tunnels): ribs removed at the cause; authored tunnel floor removed; slope acts on the route
The owner proved in game that the tunnel core caused the ribs (voxel.TunnelAblateTunnelCore=1 removes them). Root cause: the core's final reassertion replaced any sufficiently interior sample with a fixed +16 air density, destroying the distance gradient, so marching cubes snapped the surface to the voxel grid (all 385 centre samples saturated). The core now reasserts the continuous -Core.SDF, with bottom polarity from the swept shape. The Catmull-Rom sweep from |
||
|
|
0231072cc4 |
wip(tunnels): continuous world-core sweep, slope in degrees, bounded winding -- NOT MERGED: +18-30% worker CPU, visuals unconfirmed
Tunnel round from the owner's playtest. Luna's ablations traced the ribs to the world-space tunnel-core stage: disabling it removes them, while terracing, detail ops, roughness, the support floor, lateral warp, radius jitter, winding and LOD do not. The per-span capsule union is replaced by a deterministic Catmull-Rom sweep. Winding and graph expansion are now gated on bTunnelFloorEnabled (they ran even with the floor off). TunnelFloorGentleSlopeThreshold is authored in degrees (0-90, min 1 deg, DetSinCos conversion, legacy tangent values migrated: 0.3 -> 16.7 deg). The route length is capped at 6 waves x 640 = 3840 voxels, so 0.1 deg loads instead of freezing (2048 collapsed canonical reach; 24576 used ~2 GB). Room-wall trimming is behind voxel.TunnelMouthTrim (default OFF): with it on, a 36 m gap disconnects the walk. Canonical walk: 20,907 / 10,981, connected (was 20,830 / 10,909); exports identical with -voxel.CrtFma3=0; TilePostReachProof, DetSinCos and strate crossing pass. NOT merged because: one S/M pair vs the tip DLL shows worker CPU +17.8% static / +30.3% moving and worse p95; and the orchestrator's look at the before/after renders is inconclusive (camera not matched; regular grooves still visible in the after interior). Next: owner checks the look in game; if smooth, make the sweep cheap before merging; if not, drop the sweep and keep the degrees/bound/wind-gate parts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ |
||
|
|
bf9384a1d5 |
docs(work-next): bet A killed, bet B cleared rung 1, rung 2 interrupted by the usage limit
Bet A: the per-sample lookup it would remove is 5.1-6.1% exclusive, and feature-major visiting would touch 5.2-6.6x more lattice points than the current code evaluates; the swept kernel is branch-divergent. Killed on its own numbers. Bet B: 20.04% of static LOD0 density calls are exact duplicates with 80.6% donors already finished (~2.96 s of 18.3 s), moving 20.70% / 63.3%; re-derived independently from the raw trace. Its rung-2 prototype is committed unvalidated on sol/tile-sample-reuse after the Codex usage limit ended the round mid-rebuild; resume brief in the scratchpad. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
8722293f6b |
docs: deterministic maths recorded (new canonical hashes); stale landing-connector paragraph corrected
- WORK-NEXT: state after 2026-09-16 -- Sol's review, the sol/deterministic-math result, new
canonical export/worms/field hashes, and the next branches in order.
- CODEMAP 3.2: VoxelMath::DetSinCos / IsFiniteFast rows.
- ARCHITECTURE: passage landings have had no connector to the (0,0) room since the owner's
|
||
|
|
10fd0b6e77 |
fix(determinism): own sin/cos on the world path -- same world on every CPU, 3.5% faster
On Win64, FMath::Sin/Cos resolve to CRT sinf/cosf (GenericPlatformMath.h:521/530; no platform override), and the UCRT picks FMA3 or non-FMA3 implementations at startup by CPU. /fp:precise closed only the compiler half, so the same build and seed could build a slightly different world on two Windows PCs, and on Linux. - VoxelMath::DetSin/DetCos/DetSinCos (VoxelTypes.h): fixed double-precision period reduction to a quarter period, then fixed float minimax polynomials; no CRT, FMath or CPU-dependent intrinsic. Measured max error vs sinf 5.96e-8 over the used range (|arg| <= 6.19). - Every world-deciding FMath::Sin/Cos replaced (generator, op stacks, cave morphology, strate manager, content placement, strate measure); none remain in runtime code. - Pinned test VoxelForge.Determinism.DetSinCos (golden bit patterns + error bound). - Diagnostic start-up switch -voxel.CrtFma3=0 (Windows) forces the CRT's non-FMA3 path. - Parse-once console switches now initialise in StartupModule on the game thread; workers only read them (was an unsynchronised first parse inside GetDensityAt). - Corrected the CRC comment that claimed a CRC32 cannot give a false positive. Proof (Codex round; orchestrator re-checked): - Before the fix, FMA3 on vs off was identical on this Ryzen 7 5800X3D: the hole exists but was not observed in this world. After the fix, the canonical exports are byte-identical with FMA3 on and off. - The world changed once, as expected. New canonical export SHA-256 CBB8AE18...906F (geometry B9EF84AC; was B3E5F4C3...377); worms region 9242C093 (was 311CA42C), walk OBJ 20CCF7BD.... Triangle counts unchanged in every tile. Order-independent nearest-vertex distance, worms region: max 8.7 micrometres (the reported "11.4 m" was a line-order artefact of a line-by-line OBJ diff); export region max 3e-5 m. - Capability exact: player-fit 20,830, walk-reachable 10,909, connected. TilePostReachProof, sealed-proof, cross-platform and strate-crossing tests pass. - Performance, headless game path, S/M/S/M vs the committed-tip DLL: static worker 27.41 s vs 28.44 s (-3.6%), moving 59.59 s vs 61.74 s (-3.5%); LOD0 p50/p95 not worse. From Sol's code review (DESIGN-SOL-2026-09-15-CODE.md, section 4.1), branch sol/deterministic-math. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
cda082fa10 |
docs(design): Sol reads the code -- three changes worth testing, one determinism hole
Round two of the owner's "build it every better way" question: Sol's round-one session was forked read-only and given the repository, to say what could reasonably change and how each change would prove its worth. Advice only; nothing was changed, built or run. Sol's verdict: don't rebuild. The representation, mesher, clipmap and operator stack are already close to its clean-slate design. Three things are worth testing, each with a cheap instrumentation-only first step and explicit kill criteria: - tile-wide, feature-major tunnel evaluation (inferred 8-18% of worker CPU); - exact density reuse across adjacent gameplay tiles (theoretical ceiling ~23%); - a canonical numeric contract for world-deciding maths (correctness, ~neutral on speed). The orchestrator verified against the code and the UE 5.7 engine source: - FMath::Sin/Cos resolve to the CRT sinf/cosf on Win64 (FMA3 variant chosen at runtime); - per-sample lookup is ~5% exclusive, so round one's "the loop direction is the largest gap" overstated it; - worker-thread parse-once flags, raw-memory CRC cache keys and a docs-vs-code contradiction on landing connectors are real. Round one's note gets a pointer to the corrections. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
cf9904e8b1 |
docs(design): Sol's clean-slate architecture answer, with a determinism risk it surfaced
The owner's reframing idea: after local "find and fix the hot spot" rounds hit diminishing returns, we asked Sol High, with no code and no file access, how it would build this project in every better way. It recommends feature-rasterised sparse bricks (each feature stamps into the bricks it touches instead of every sample searching for features), noise only in surface bands, coarse LOD from finer data, a fixed-point determinism contract and deadline-driven collision-first streaming. The orchestrator's check against our code: 34 FMath::Sin/Cos calls sit on the generation path (per-sample strata line/rib detail and passage/tunnel shape building). The MSVC C runtime switches those to FMA3 implementations at runtime, so cross-machine bit-identity is not guaranteed. Not changed yet; recorded for a deterministic replacement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
410788f7dd |
perf(generation): per-chunk routing cache -- ~4% less worker CPU, exact
GetDensityAt asked the strate manager on every sample whether the chunk is a gap chunk, which generator type it uses, and whether it uses the operator stack. All three are constant per chunk. voxel.ChunkRoutingCache (default 1) memoises them per worker thread (Codex; reviewed by me): - thread_local storage only, so no cross-thread sharing; - key = generator owner id + manager pointer + manager lifetime id + layout version + full chunk coord, the same identity pattern as the existing CP_* refetch; - the editor composer override is still queried in the CP_* refetch, not cached here. Attribution for the re-rank's ~28% shared cost (offline-symbolised sampler, exclusive): GetDensityWithParams 16.4%, GetDensityAt 6.2%, unknown 5.8%, FChunkSDFSpatialIndex::GetRange 3.8%, FScopedTimer::End 1.3%, VF_ForEachSpatialCandidate 1.2%, UsesOperatorStackForChunk 1.0%. The tunnel-cache lookup was already near-perfect (48 misses in 2,248,091 samples). A thread-local timer cache was tried and rejected as slower (+0.4% static, +1.2% moving). Spatial-iteration and mesher-loop changes found no isolated exact win. Routing A/B: static worker 28.50 -> 27.78 s (-2.5%), moving 63.01 -> 59.81 s (-5.1%). Final DEFAULT build vs the committed-tip DLL (two interleaved runs each, same command line): static worker 28.79 -> 27.58 s (-4.2%) LOD0 p50/p95 52.3/94.8 -> 50.1/92.6 ms moving worker 62.25 -> 59.97 s (-3.7%) LOD0 p50/p95 51.4/95.8 -> 48.8/92.3 ms Field exact: OBJ SHA-256 b3e5f4c3..9b377 on both builds, 0 per-tile differences, capability 20,830 / 10,909; TilePostReachProof, sealed-proof and strate-crossing tests pass. Ledger: every launch was serialized with 0 editors before it. Two attribution attempts were rejected on harness bookkeeping/output-path bugs before a clean run; one crossing run was invalid (profiling left on, exit -1) and its retry passed. No crash folders. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
c7b832db4c |
docs(work-next): the tunnel SDF/core merge is closed -- the world core is load-bearing
Records why the merge must not be re-proposed without a new idea. WorldControlPoints keep the
authored room-floor anchors and walkable routes before cave warp; replacing them lost 1,146 fit /
975 walk-reachable cells, and the exact shared-segment variant was slower. The remaining large
costs are the geometry itself, so the exact-skip perf push has reached diminishing returns; the
reach proofs are now guarded by an automation test (
|
||
|
|
8ef1a3b579 |
test(reach): automation test guarding the per-tile reach proofs; merge closed as load-bearing
VoxelForge.Correctness.TilePostReachProof (VoxelForgeTilePostReachTest.cpp) runs the real mesher twice in one process: at full reach it compares the skipped posts' FINAL field (356,946 comparisons, 0 differences), and at a deliberately shrunk reach it must find differences (774 found). Native/fused sample counts are identical (137,180). So a future tunnel or passage geometry change that breaks a reach proof ( |
||
|
|
cfd81b5ce9 |
docs(work-next): state after 2026-09-15 -- gameplay fixes, correctness, perf, current cost map
Records the playtest-driven fixes (strate crossing, sealed-rock proof, option B floors, gap D-floors), the cold-audit correctness round (including the tile-cache determinism bug), the perf gains measured against committed-tip DLLs (static worker ~184 s -> ~28 s over the whole push, same world), the current remove-one cost map, and the parked exact-cull branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
a668833ef5 |
perf(generation): exact reach gating for the tunnel core (per tile) and passage carving (per 8^3 block)
Applies ce4d878's decide-once-then-prove pattern to the two largest exact targets from the re-rank
(tunnel core 20.8%, passage carving 9.1%). Codex; reviewed by me.
Measured first, where the time is:
core world: far 223,860 vs near 35,515,979 cycles -> tile gate only; the core is
near-dominated (~99%)
core tail: far 363,440 vs near 20,110,219
passage, tile: far 7,315,426 vs near 30,168,796 -> refined to an 8^3 block gate
passage, 8^3: far 11,233,384 vs near 26,250,838
The core already uses the tunnel spatial index. An exact skip cannot remove its cost: that cost is
in tiles near tunnels. The remaining lever there is the field-changing SDF/core merge (next).
- Core reach per tile, from lattice plus halo: swept capsule reach, floor band, floor-profile
deviation, relief bound, room-mouth ownership. The GetDensityAt tail is identity unless
bSupportFloor, bRoomFloor or CoreSDF < -inset.
- Passage carving per 8^3 block: capsule-chain and landing-room domains, the carve threshold and
the SmoothMin K/6 margin. Malformed descriptors stay candidates (conservative).
- voxel.TileReachCostDiagnostics (default 0) for the far/near cost split.
Soundness: the final-field debug comparison ran 130,285,889 comparisons with 0 differences; shrunk
reach (0.5) produced 140,035 differences (60,098 in the final field) and failed as required.
Field exact: canonical 07C14005 / b3e5f4c3..9b377, 64/64 per-tile ledger identical, capability
20,830 / 10,909, strate-crossing and sealed-proof tests pass.
Final DEFAULT build vs the committed-tip DLL (same command line, two interleaved runs each):
static worker 28.84 -> 28.10 s (-2.6%) LOD0 p50 53.3 -> 51.5 ms p95 94.4 -> 93.1 ms
moving worker 61.39 -> 60.61 s (-1.3%) LOD0 p50 50.9 -> 49.7 ms p95 92.21 -> 92.27 ms (flat,
+0.06%, within noise)
Maintenance note: these reach proofs must track tunnel/passage geometry. The next round adds an
automation test for the final-field comparison so a geometry change cannot silently break them.
Ledger: 15 builds (one C2065 fixed, one access-denied path retry); rejected TileOnly/BlockLookup
variants were slower; one hung diagnostic (a non-owner PID) was stopped; wrapper quoting failures
launched no editor. No crash folders.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
|
||
|
|
0208e93606 |
measure(perf): re-rank component costs on the current build -- the tunnel core is now the largest
Measurement only (Codex): the same remove-one ablation method and command line as |
||
|
|
1d824aaab2 |
perf(noise): batch the three cave-warp channels through the SIMD evaluator -- exact, ~4% faster
The remove-one ablation, re-confirmed on the current build, puts the cave warp at 11.0% static / 11.8% moving of worker time: three independent Perlin3D calls per sample. VoxelNoise::Perlin3D_x3 evaluates the three warp channels together through the existing SIMD evaluator (Codex; reviewed by me). It is wired into the generator, op-stack, classifier and room/player-fit unwarp paths. Exact: the field is byte-identical. 0/841 tiles changed, 0 triangle delta, 0 voxels of maximum surface displacement; canonical export 07C14005 / b3e5f4c3..9b377; capability 20,830 / 10,909; strate-crossing and sealed-proof tests pass. The seam test (VoxelForgeMazeSeamTest, extended) has 48 neighbouring-tile and 24 cross-LOD comparisons, 0 mismatches. Before/after renders from a camera aimed at the real arrival tunnel are byte-identical. Cross-machine determinism: Perlin3D_x3 adds no new intrinsics, no AVX, no FMA and no runtime CPU dispatch. It reuses the evaluator behind the compile-time gate `#if PLATFORM_ENABLE_VECTORINTRINSICS && PLATFORM_CPU_X86_FAMILY`, so every x64 machine runs the same instruction path; its output matches the scalar path bit for bit. Final DEFAULT build vs the committed-tip DLL (two interleaved runs each): static worker 30.83 -> 29.47 s (-4.4%) LOD0 generation p50/p95 56.3/99.3 -> 53.3/95.3 ms moving worker 67.28 -> 64.56 s (-4.0%) LOD0 generation p50/p95 55.9/99.0 -> 53.4/96.4 ms Ledger: every launch passed; two harness false negatives (the seam test on the game-only validator, and a trace ended by intentional forced termination) were rerun. No crash folders. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
ce4d8783e9 |
perf(generation): per-tile reach test skips landing and structural posts -- ~12% less worker CPU
The remove-one ablation put landing posts at ~10% and passage structural posts at ~6% of worker time, though landings exist only near passage ends and the origin. The parked exact-cull round's per-SAMPLE post bounds had been a net loss. This round decides reach once per TILE (Codex; reviewed by me). - VoxelTilePostReach.h: one per-tile reach mask (thread-local byte), set when the tile is set up. The origin landing, passage landing SDF/floors, native floors, tunnel air and passage structural posts return their input unchanged on tiles no instance can reach. Per sample this costs an inline flag read. - Reach proofs come from each post's geometry (origin rooms, landing SDF and floors, native floor band, structural support spheres), not from comments. - voxel.TilePostReachDebug=1 evaluates the skipped posts anyway and compares the FINAL field; voxel.TilePostReachScale=0.5 deliberately shrinks the reach and must fail. Default build: 694 tiles, landing reachable on 4 (skipped on 690), structural posts skipped on 169. Soundness: 123,958,673 comparisons, 0 differences; shrunk reach: 13,929 differences, FAIL as required. Final DEFAULT build vs the committed-tip DLL (same command line, two interleaved runs each): static worker 34.80 -> 30.52 s (-12%) LOD0 generation p50/p95 67.0/107.6 -> 55.8/95.8 ms moving worker 75.96 -> 66.66 s (-12%) LOD0 generation p50/p95 66.3/106.0 -> 56.0/95.8 ms Field exact: 841/841 keyed tiles vs a fresh committed-tip trace (669,902 triangles, which includes 9260775's gap floors), export b3e5f4c3..9b377, capability 20,830 / 10,909; strate-crossing and sealed-proof tests pass. Ledger: all launches passed or failed where designed to; early raw-SDF debug attempts failed until the comparator was corrected to compare the final field. No crash folders. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
92607751b1 |
fix(passages): D-floors now exist inside the inter-strate gap; two stale tests corrected
Investigation of the two tests that had been failing for days (Codex; the fix reviewed and its field claims re-run by me). Real bug, introduced by |
||
|
|
cf2b2add20 |
feat(tunnels): option B floors -- no staircases; steep tunnels wind or drop
Owner's playtest showed a staircase (dozens of <= 45 cm risers) on a steep tunnel into a room. He chose option B: "smooth passage and 'dramatic ledge' on tunnels that crossed the slope limit, so we both have serpenting tunnels and sometimes dramatic drops that needs to be escalated". Implementation (Codex; the edge rule reviewed by me): - VF_TunnelFloorNeedsTerrace and all tunnel-floor NumSteps quantisation are removed; new profiles always have NumSteps = 0. Gentle floors remain continuous ramps with bounded relief. - The room graph's bridges and a deterministic reserved walk spanning forest decide each steep edge. bGraphLedgeEligible = leaf || (redundant && !walk-forest edge). Eligible edges may receive a few large drops at control-point boundaries, never repeated small risers. Every other steep edge WINDS (a sinusoidal wander lengthens the WorldControlPoints route until its floor is walkable). Several drops chosen together cannot disconnect walking, because the forest stays walkable. - The collect margin includes the longer wound-route envelope (window invariance). Classifier interval bounds include both endpoint floor levels, covering a ledge riser. Verified: - default acceptance (slot 1, threshold 0.9657): player-fit 20,830, walk 10,909, arrival -> departure connected, TunnelFloorMultiStepEdges 0, mesh 311CA42C unchanged. NOTE: this config has 0 steep edges, so it does not exercise option B at all. - stress (threshold 0.2): arrival -> departure connected; player-fit 21,305 (winding adds volume), walk-only 10,787. Fewer walk-only cells are expected behind climbable ledges. Ledges 4-8 voxels: 52,826 observations; 8+: 215,880; below 4: 0. - determinism: two runs identical (164,126 triangles, 70F987AA, 0 per-tile differences). - performance vs baseline DLL: moving worker 93.6 -> 85.2 s; LOD0 request p95 static 196 -> 181 ms, moving 188 -> 164 ms. - the two already-failing tests fail identically before and after (ClassifyTileSoundness: 2 expected-uniform holes; PassageLandsInOpenSpace: upper landing endpoint mismatch). NOT verified visually: every render reused one fixed camera, never aimed at a changed tunnel. The arrival case was rendered at the default threshold (8/8 views identical); in the steep/wind cases the changed views did not show a tunnel clearly. The owner's in-game check is the real acceptance. Ledger: several intermediate capability gates failed before the final configuration passed; two malformed launches were aborted; no crash folders. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
8879045627 |
fix(correctness): cold-audit fixes -- tile-cache determinism bug, cache identities, lifetimes
Correctness round on AUDIT-COLD-2026-09-14.md (Codex; key fixes reviewed by me). #7 (determinism, introduced by the tile-cache work): the refetch guard in GetDensityAt now rebuilds on `bTileCacheContext != CP_UsesTileCacheWindow` or when the worker-local stack/core were moved into a cache entry (`CP_ActiveTunnelDensityCache != nullptr`). A cache miss can no longer evaluate a moved-from, empty operator stack. Test (VoxelForgeCorrectnessRoundTest): the pre-fix binary CRASHED in the context-switch case (negative control); the fixed binary passes with 0/5 coarse and fine mismatches, and warm vs fresh origin-tile meshes are identical. Also fixed, each with a focused test that passes: - #3/#8: worker diff/surface/biome caches carry owner/layer identity (no cross-world reuse); #9: the shaft key gains LedgeSpacing/LedgeDepth and the island key BoundarySealThickness; #14: clearing passages bumps PassagesVersion; #21: HasAnyModInChunkRange is proportional to the queried range (the sealed-rock proof calls it per candidate). - #1: the density-volume fill thread is paused/drained with generation; #2: each content manager joins its own decoration tasks before destruction; #15: non-finite/invalid modification geometry is rejected; #20: zero-width transition blend is guarded at runtime. - Also #4-#6, #10-#13, #16-#18, #22. #19 is valid C++20 and unchanged. Verified: canonical export b3e5f4c3..9b377; capability 20,830 / 10,909; fresh trace 841/841 identical, 0 origin-column mismatches; static mesher calls 18,078,130. Performance: two pairs disagree in sign, and the means are final -2.5% static / -0.8% moving; no repeatable regression. Known and NOT caused by this round: ClassifyTileSoundness and PassageLandsInOpenSpace were already failing (15/17 in the grouped suite). Queued for investigation. Ledger: first determinism launch hit the DDC fatal (crash folder 57DB6ADC, 23:21); the retry exited 1 on the two known failures; one malformed multi-test launch was inconclusive; one malformed trace launch was stopped; one launch with an unquoted project path found no test and its retry passed. Everything else passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
39c306b524 |
perf(streaming): prove sealed rock solid instead of sampling it -- crossing fix's cost recovered
|
||
|
|
481e7bbaee |
docs(audit): cold read-only examination with verification notes -- one determinism bug confirmed
A read-only Codex examination (no project background in the brief; it did read the root docs) with 22 code-level findings, kept verbatim, plus the orchestrator's verification notes: - #7 CONFIRMED: after VoxelGenerator.cpp:2968 moves CP_OpStack into the tunnel cache, a miss under the other tile-cache context skips the refetch (:2723-2725) and evaluates an EMPTY stack. The hit path makes the spawn column X=Y=0 reach this after an ordinary hit. Introduced by the tile-cache work; queued first in the next correctness round. - #3/#8 are real but narrower (multiplayer peers share seed and layout by design). - #19 is not a defect under C++20. The rest are to be verified individually before fixing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
4c8d06fd8f |
fix(streaming): the player can walk from one strate into the next
Owner playtest: he could not walk from strate A into B. Forcing the pawn through in the editor showed the junction tunnel (and his edits to the lower strate) were there. Cause: UVoxelSettings::StrateContentCutMinLevel defaulted to 0, and DA_Settings does not override it, so the strate content band (the PAWN's strate) also cut LOD0, the collision tiles. While the player stood in A, the passage below A's seal, the gap and strate B had no LOD0 geometry, and the collision gate correctly refused to step onto missing collision. The band only moves once the pawn is inside B: a deadlock. bClampViewToStrate is a different setting, which is why toggling it did not help. Some historical fall-throughs were likely this, before the gate turned "fall" into "blocked". Fix (Codex; reviewed by me): - StrateContentCutMinLevel default 0 -> 1, ClampMin 1, and UVoxelSettings::GetEffectiveStrateContentCutMinLevel() clamps to [1,9] at every runtime consumer, so a legacy asset serialising 0 cannot bring the deadlock back. LOD1+ stay banded inside strates and go full in the gap. - A regression test, -voxel.TestStrateCrossing=1 (off unless passed): it walks the real manager passage control points with AddMovementInput and normal swept character movement, with limits of 10 s max gate, 120 s total and a 2-voxel floor tolerance. Old code: FAIL collision_gate_timeout at route 5/9 (10.0 s gated). Fixed: PASS reached_lower_strate, strate 0 -> 1, max gate 0.092 s. The trace shows band [-7..0] -> full in the gap -> [-17..-10]. Field unchanged: canonical export b3e5f4c3..9b377, capability 20,830 / 10,909. In game, the LOD0 change in the crossing scene is 11 transition-gap tiles going from 0 to 22,390 triangles; no LOD0 interior tile changed. COST, stated plainly (two interleaved runs, baseline vs fixed DLL): static generation CPU 34.1 -> 44.1 s (+29%), density calls +23%, LOD0 request p95 +8.9% moving generation CPU 78.8 -> 91.1 s (+16%), density calls +26%, LOD0 request p95 +3.1% applied triangles identical (669,834 / 1,331,482): the extra work is LOD0 tiles in sealed rock that the old cut skipped. The next round proves them solid instead of sampling them. Visual caveat: the old default of 0 was a deliberate July choice, because LOD0/1 tiles straddling a strate boundary mixed both strates' materials. With LOD0 never cut, that mixing may reappear near seals. The headless runs are -nullrhi, so this still needs checking in the editor. Launches: all serialized and waited by PID. Failures: one malformed first baseline attempt, one over-strict early harness assertion, and one run against stale staging (it logged CutMinLevel=0), all superseded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
7ece3ceafc |
docs(work-next): state after 2026-09-14 -- perf ledger, measured costs, what failed and why
Records in the repo what two days of perf rounds established: the in-game worker CPU trajectory (~184 s -> ~34 s static), the remove-one ablation costs, the three approaches that were tried and not kept (with where the parked work lives), the measurement lessons that each cost a round, and the next candidates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
7a972f513d |
fix(ablation): tunnel-core ablation no longer disables the fused evaluator
Salvaged from the parked exact-culling round (wip/exact-cull-20260914, 49369ac). This is the only
change ported. `if (!VoxelDensityAblation::IsTunnelCoreOff() && CP_UseOpStack)` becomes
`if (CP_UseOpStack)`: with the tunnel-core ablation on, the old condition also sent coarse tiles
to the scalar per-chunk cache path. That was the 2.9x "tunnel core off" anomaly in
|
||
|
|
6ccf3718ff |
measure(perf): per-component ablation of the TunnelNetwork path; exact worms restored
Round (Codex; reviewed by me against PERF-SAMPLED.md). Revert: voxel.WormNoiseMode / voxel.WormLatticeStep, their storage and their switches are REMOVED. VoxelWormField has one path again, exact Perlin with the N1 short circuit. Kept: bEnableWorms (asset), WormsForceOff (measurement only), the exact block skip (default 0). Ablation instrument: 14 development-only, world-changing force-off bits (voxel.TunnelAblate*), applied on the fused, op-stack/classifier, cached SDF/core and modifier/floor paths. They resolve once per process, are hashed into the generation fingerprint, and are compiled to zero in UE_BUILD_SHIPPING (VoxelDensityAblation.cpp). They are a measurement instrument, never a gameplay or multiplayer switch. Defaults exact: canonical export OBJ b3e5f4c3..9b377, worms-region 311CA42C / 75,482 triangles, capability 20,830 / 10,909, and 841/841 keyed tiles identical to NextHeadStaticTrace_20260913. Static worker seconds saved by removing ONE component (two off runs vs the interleaved all-on 33.06 s; baseline noise 0.27%): tunnel SDF 11.4%, cave warp 10.3%, passage carving 10.1%, landing posts 9.9%, passage structural posts 5.6%, worms 2.4%, native floor 2.2%, origin spine 1.6%, room SDF 1.6%, everything else <= 1.1% Moving (2+2 runs each) confirms the top five at 6.0-11.6%. Tunnel SDF off cuts LOD0 generation p95 104 -> 83 ms: it owns the slow tail. The positive savings sum to 58% of the static total; the other 42% is shared. The rows are not additive. Unexplained: tunnel-core OFF made the static total 2.9x SLOWER (95.5 s) while LOD0 generation got faster (p50 64.7 -> 60.6 ms) and triangles fell. The report blames the changed field, which does not fit; more likely a slow fallback path in coarse tiles. That row is not a cost measurement. Ledger: every Unreal process exited 0 and verified the loaded DLL; two PowerShell parser errors happened before any process started. No crashes or retries. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
c132243b30 |
feat(worms): asset-owned worm off switch; offline stack symboliser -- cheap-worm default to be reverted
Worms round (Codex; reviewed by me against its report and PERF-SAMPLED.md).
Part 1, a real off switch: UVoxelStrateDefinition::bEnableWorms (default true, so existing assets
are unchanged). It is deliberately not in FStrateGenerationParams, so the 83-field memo-key guard
is untouched. It resolves after composer candidates, season vectors and boundary blending, is
included in the generation fingerprint, and clamps composer overrides, so a roll cannot re-enable
it. With strength 0 the fused path skips the worm block, the op-stack builder omits the worm
source, and the interval/classifier paths do no worm work. Proof: disabled == hand-zeroed control
byte for byte (70D310A4, 74,672 triangles), capability 20,856 / 10,917, connected, zero worm rows
in the symbolised sampler. voxel.WormsForceOff is a dev-only, world-changing measurement
override, included in the fingerprint.
Part 0: the sampler writes a module map (733 modules, identity checked), and a post-exit
offline symboliser (VoxelStackOfflineSymbolizer, editor module) rebuilds the all-LOD / LOD0 /
LOD1+ exclusive / inclusive / source-line tables. A planted cost was found (5 named rows) and then
removed. DbgHelp still never runs in the measured process.
Part 2, "cheap worms": FAILED to deliver, and the default is wrong. No candidate was faster:
lattice-2/4 gave no gain, and value noise was within noise static and ~2.1% WORSE in moving worker
seconds. Yet this commit carries voxel.WormNoiseMode=1 (value noise) as the default, a field change
(29/64 test tiles) with no benefit, selected after value-noise variants were tried until one
passed capability (three were rejected at 20,821-20,828). The next round reverts the default to
exact Perlin (mode 0) and removes the no-gain world-changing experiment modes.
The finding that matters: disabling worms entirely (WormsForceOff A/B, two interleaved runs each)
saves only ~2.5% static and ~3.4% moving worker time. The sampler's "worm line
VoxelGenerator.cpp:3985 = 19.4% of LOD0" was a misattribution of inlined noise code to one PDB
line. Line-level attribution of inlined code must be confirmed by ablation before a round targets
it. That is why the worm block skip (
|
||
|
|
11f0c1335b |
fix(diagnostics): sampler can no longer crash the run it measures; worm skip default off
Harness round. Every launched run is in Saved/HarnessFixAcceptance_20260914.ledger.txt.
- FVoxelStackSampler: two sampler-on runs had died in EndPlay (logs stop after "workers drained",
before the latency summary). The lifecycle teardown is now serialised, registration TLS is
tagged by session, stale worker registrations are cleared safely, and in-process DbgHelp
initialisation/symbolisation is REMOVED. The measured process now writes raw PCs only; symbol
resolution is deferred to after process exit. (An offline symboliser is still needed for
readable tables; it is queued first in the next round.)
- voxel.WormBlockSkip default 1 -> 0: it measured neutral (
|
||
|
|
26b34765d5 |
perf(generation): exact worm block skip with a proven 3D Perlin bound -- measured NEUTRAL
The sampler put the worm carve's first noise call (VoxelGenerator.cpp:3985, FusedWorm) at 19.4% of LOD0. The worm only carves where N1 + N2 < T with N2 >= 0, so where N1 >= T it contributes nothing, bit for bit. A block proven to have N1 >= T everywhere can skip both noise calls exactly. - The Lipschitz bound for this Perlin3D implementation: L = (15/4) * sqrt(3) * 1.25 = 8.118988160, in scaled-N1 units, with a 1e-3 float-rounding margin. Adversarial sampling found a worst ratio of 3.187 (0.39 L). The existing 2D floor-relief bound (8.5) is a component bound of a different field and was confirmed not to transfer. - A soundness test that can fail (VoxelForgeWormBlockSkipTest): 6,476 proved blocks, 355,945 exact lattice samples, 0 violations. A deliberately halved L proves a bad block; the full L rejects it. - voxel.WormBlockSkip, default 1. Field exact: export OBJ byte-identical (b3e5f4c3..9b377), 841/841 keyed tiles identical to NextHeadStaticTrace_20260913, capability 20,830 / 10,909. RESULT, stated plainly: no measurable speed gain. The skip rate is 4.07% of worm-eligible LOD0 samples and 0% at LOD1-4, because the bound is ~2.5x looser than the worst observed ratio at the block size used. Paired on-vs-off, two interleaved runs each: static worker +2.15%, generation p50 +1.8%; moving worker -1.42%, request p50 -2.5%. Within noise. The next round turns the default OFF. The proven bound and its test are kept for a tighter skip later (smaller or hierarchical blocks, or a per-cell bound). Run ledger (from Codex's report): the first build failed on an ambiguous test overload and was fixed; two timing runs are void because the orchestrator stopped the session so the owner could use the PC; the eight valid timing runs, the sampler run and the diagnostics runs completed. No new crash folders. PERF-SAMPLED.md now lists all eight earlier-round UECC crash records. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
5489b5e311 |
perf(generation): inline exact IsFinite -- LOD0 ~11-12% faster, field-exact
The sampler's last "unknown" LOD0 bucket (~13.8%) was ucrtbase.dll!_finite: FMath::IsFinite is an
out-of-line CRT call on the MSVC game path, hit from the innermost tunnel, passage, density,
spatial-index and meshing loops.
- VoxelMath::IsFiniteFast(float/double) in VoxelTypes.h: memcpy to uint32/uint64,
(Bits & ExpMask) != ExpMask. It is the same predicate for every bit pattern, with no FP
comparison for fast-math to fold. The disassembly shows it inlined (movd/movq, mask, compare).
- VoxelMath::IsFinite routes through a plain global, voxel.FastIsFinite (default 1), for the A/B.
The CRT call remains only on the switch-off branch. Hot generation-path uses are replaced; no
_finite / std::isfinite remains in Source/VoxelForge. Tool/editor/test code keeps FMath.
- A test that can fail: VoxelForge.Math.IsFiniteExact compares against FMath::IsFinite over 22
explicit float/double patterns (+-0, denormals, min/max normal, +-Inf, quiet and signalling NaN
payloads) plus 2,000,000 hashed patterns each: 0 mismatches. The explicit NaNs make a NaN-wrong
helper fail.
Field exact: 841/841 keyed tiles identical to NextHeadStaticTrace_20260913 (verdict/empty/
triangles), export OBJ unchanged (b3e5f4c3..9b377), capability 20,830 / 10,909.
Within-round A/B, game path, two interleaved runs each, sampler off (off -> on):
static LOD0 request p50 95.5 -> 84.8 ms generation p50/p95 70.3/114.1 -> 62.3/100.6 ms
worker 35.4 -> 31.6 s (-10.5%)
moving LOD0 request p50/p95 70.8/144.2 -> 62.0/126.1 ms
generation p50/p95 62.6/113.4 -> 55.1/101.0 ms
worker 102.6 -> 91.3 s (-11.0%)
Sampler-on moving: the _finite/CRT cluster is gone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
|
||
|
|
22186473f9 |
perf(generation): spatial index default on; the 10 s question and the unknown bucket, answered
Measurement round (Codex; checked against its report):
- Per-tile identity for ab4bbe3's always-on LOD0 changes: a fresh 841-tile HEAD trace matches
traces recorded before them (MemoStaticOn/Off), keyed by (x,y,z,level) with
verdict/empty/triangles compared. 0 differences, 0 missing; LOD totals identical, 669,834 in all.
- The "missing 10 s" is not the spatial index: all six TileCacheWindow x SpatialIndex
combinations are within ~1% for a given window setting. TileCacheWindow=0 at HEAD is not
2990009's path. It still thrashes at L3/L4 (p95 ~250 ms). The default beats
|
||
|
|
ab4bbe3680 |
perf(generation): field-exact LOD0 overhead removal; the unknown bucket is Core.dll
Field-preserving floor round (Codex; reviewed by me against the code):
- exact per-(sample, passage) caching of native/generic floor projections and walkable-air
checks, behind voxel.FloorRound1PassageProjectionCache
- a zero-work disabled path for VoxelDensityProfile::FScopedTimer, unchanged when enabled
- pointer / range-for iteration in the proven-hot tunnel, passage, spatial and candidate loops
(TArray RangeCheck was ~6.5% of LOD0 samples on the Development binaries the owner plays on)
- FVector2D temporaries replaced with scalar doubles, same operations in the same order
- FSurfaceColumn made trivial, so thread-local construction does no work. Verified safe:
ComputeSurfaceColumn writes all five outputs unconditionally before any branch, and every read
of Box.Cols is gated by Box.Computed
Verified: export OBJ byte-identical (b3e5f4c3..9b377); capability 20,830 / 10,909; all 8
interleaved game runs gave identical totals (841 tiles / 669,834 triangles static, 2,348 /
1,985,216 moving, the same as previous rounds). Per-tile identity for the always-on changes still
needs a check against a stored trace; that is queued first in the next round.
Game path (sampler off, two interleaved runs each):
projection-cache switch alone: neutral (static worker +0.41%, moving -0.05%)
vs the previous round (
|
||
|
|
b839edd3a3 |
docs(work-next): correct cfad3d1's false "machine in daytime use" explanation
cfad3d1's message blamed cross-round drift on the owner using his PC. That was my unverified guess, and it is false: he had not used the PC all day. The gap is systematic. The switch-off baseline measured 58 s static worker CPU in two rounds hours apart, against 48 s at |
||
|
|
cfad3d1c18 |
perf(generation): gate the tile cache window by LOD; LOD0 back to switch-off speed
2de603c's tile-sized room cache cut worker CPU, but LOD0 generation was ~9% slower. The per-tile
split shows the loss was evaluation (more candidates per sample in a bigger window), not cache
building. Policy, measured per path and LOD:
- fused path: tile window at LOD >= voxel.TileCacheWindowMinLOD (default 3)
- op-stack path: tile window at LOD >= voxel.TileCacheWindowOpStackMinLOD (default 4)
- lower LODs keep the 4-chunk worker window
- voxel.SpatialIndex: -1 auto (off at fused LOD0, on elsewhere), 0 or 1
Proof caveat closed: VF_ComputeTerrainOpEnvelope adds authored terrain-op extents (pits, chimneys,
detail overrides, ...) to the invariance envelope. Ops beyond the proven 256-voxel extent, or
malformed/unloaded ones, force the legacy window, so window invariance holds for every asset.
Sampler fix: the leaf symbol kept pointers into a TMap that FindOrAdd can rehash while later
frames resolve; the leaf is now re-found by program counter after insertion.
Game path, two runs each, sampler off (Codex; checked against its report):
LOD0 request p50/p95 generation p50/p95 worker s
static optimized 106.3 / 175.9 ms 76.6 / 124.3 ms 39.2
static switch-off 106.3 / 173.0 75.9 / 124.1 58.5 (-33%)
moving optimized 79.4 / 158.5 72.4 / 123.7 113.7
moving switch-off 82.8 / 160.4 73.2 / 125.4 141.9 (-20%)
LOD0 is flat within noise static and slightly better moving; worker CPU keeps most of the gain.
Field exact: 841/841 per-tile triangle identity, export OBJ SHA-256 unchanged (b3e5f4c3..9b377),
capability 20,830 / 10,909.
Caution: compare these numbers only within this round. The machine is in daytime use, so
absolute figures drift between rounds.
Current LOD0 map (sampler, moving, inclusive): tunnel SDF 12.5% + tunnel core 12.3% (the same
tunnel in two coordinate spaces); passage carving 11.1%, structural posts 11.4%, native floor
4.1%, with floor projection at 8.9% inside them; cave warp ~8% exclusive. Development-build-only
overheads: TArray RangeCheck ~6.5%, per-sample FScopedTimer ~2.6%.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
|
||
|
|
2de603cd77 |
perf(generation): size the room cache to the tile; spatial index; memo-key guard
Coarse tiles thrashed the per-worker 4-chunk room-cache window: 633 BuildChunkCache calls per LOD3 tile and 1,062 per LOD4 tile. This round was started by one Codex session and finished by a second, after the orchestrating session died at 06:06 and corrupted the first session's record. The second session reviewed and built its predecessor's half-finished tree. - voxel.TileCacheWindow (default 1): the room cache covers the requesting tile's footprint plus a fixed collect margin. It is set with TGuardValue around GenerateMesh and classify, so it never leaks to other work on the thread. Tile windows are capped at 64 chunks per side; unsupported/non-finite params fall back to the legacy window. - Window invariance, argued by Codex: graph decisions depend on at most two bounded MaxTunnelLength hops, and primitives are culled only once their complete bounds are known. So the collect margin 2*MaxTunnelLength + max(room reach, pair/chain/tube reach) does not grow with the window. Caveat: oversized authored terrain-op radii are not yet in the envelope check. - PrepareTunnelCoreCache reuses the graph, rebuilding only the exact support-column table for a crossed chunk. - FChunkSDFSpatialIndex: ordered XY buckets over room/join/tunnel bounds; rejection stays exact and within-bucket order is preserved. Only 9-13% of candidates reach exact evaluation. - static_asserts in VoxelStrateTypes.h: VF_STRATE_PARAM_FIELDS lists 83 fields, and their byte sum + 8 B padding == sizeof(FStrateGenerationParams). This closes the memo key's known gap (it catches omissions and size changes, not same-size replacements or padding-hidden fields). Verified (game path, two runs each, sampler off): - field exact: 841/841 per-tile triangle identity, 669,834 triangles; export OBJ SHA-256 unchanged (b3e5f4c3..9b377); capability 20,830 / 10,909, connected - cache builds: fused 139,187 -> 1,019 (-99.3%), op-stack 60,598 -> 879 - worker CPU: static 58.4 -> 40.8 s (-30%), moving 138.4 -> 121.2 s (-12%) REGRESSION, stated plainly: with the switch on, LOD0 gets slower. Generation p50 is ~9% slower, static 75 -> 82 ms and moving 71 -> 77 ms; request-to-ready p50/p95 is ~5-6% slower. This is consistent across both runs of both cases. The thrash only lived at LOD2+ (LOD0 had 1.66 builds per tile), so the next round gates the tile window by LOD and must bring LOD0 back to switch-off speed while keeping the CPU gain. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y |
||
|
|
2990009f3b |
perf(generation): memoise room player-fit points -- 3.8x less worker CPU in game
The sampler (
|
||
|
|
8e40bdd92c |
measure(perf): in-process stack sampler; the game spends ~3/4 of worker CPU on room player-fit
A diagnostic stack-sampling profiler, off by default. A sampler thread captures the stacks of
registered generation workers with FPlatformStackWalk::CaptureThreadStackBackTrace every N us and
tags each sample with the tile's LOD. Symbolisation (inline frames included) happens after the
run, into a bounded CSV plus a summary. Registration is per tile task, never per sample; when the
sampler is off it costs one relaxed atomic load. Game: -voxel.SampleStacks=<us>. Commandlet:
-samplestacks[=us]. The streaming latency line now also prints applied tile, visible tile and
triangle counts.
Instrument checks (Codex, PERF-SAMPLED.md):
- a planted 20 ms busy loop was found at 10.5% inclusive, the expected share, then removed
- closure: 193k static / 251k moving samples, 0 capture failures, <0.75% wait frames,
leaf resolved for 82-84%
- static game output identical with the sampler on or off: 841 tiles, 447 visible, 669,834
triangles
- overhead at 1 ms: +4.7% static worker CPU; moving worker CPU within noise, moving timing +4-5%.
So trust large shares, not single-digit deltas.
The finding, on the game path (the owner's instruction: profile the game, not the export):
all-LOD inclusive static moving
BuildChunkCache 79.5% 80.5%
VF_FindPlayerFitPointForRoom 73.4% 74.0%
About three quarters of in-game worker CPU goes to player-fit searches for rooms. They are
recomputed on every per-worker room-cache rebuild, and coarse tiles span many cache windows. At
LOD0 the costs are the cave warp (3 Perlin per sample), the swept tunnel evaluated both in the
SDF and in EvaluateTunnelCoreWorld (~12% inclusive each, duplication confirmed), and the passage
structural tail (~11-14%). Candidate AABB rejection is cheap (1.5-2.2%). The 74-field params copy
does not show up as a separate cost.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZS94UH8bSsBeg5sZaxe2Y
|
||
|
|
c65b015f01 |
perf(streaming): outer tile classifier off by default; delete mode 2
Owner-approved, on the A/B measured in
|
||
|
|
83a0e4d85c |
measure(classifier): outer classifier is net-negative in game; nested 3.5x IS real
Three-mode outer-classifier A/B on the headless game path, nested refinement off in all
modes, clean and diagnostics off. Runs made by the forked Codex session; the table was
assembled and checked by me from its logs (Saved/OuterABMode*_20260912.log,
OuterABMove*Headless_20260912.log).
static ready p95 mode0 182.4-182.7 mode1 189.7-194.8 mode2 190.0-194.7 ms
gen p95 mode0 124.9-127.0 mode1 139.1-140.6 mode2 140.3-141.3 ms
worker CPU mode0 184.9-193.5 mode1 201.2-202.3 mode2 201.2-201.3 s
density mode0 18.05M mode1 21.89M mode2 21.89M
moving ready p95 mode0 198.9 mode1 208.0 mode2 210.7 ms
density mode0 57.7M mode1 69.6M mode2 69.6M
The outer classifier costs more than it saves: with it removed (mode 0), every latency
figure improves and density calls drop by about 18%. Mode 0 also cannot remove geometry,
because it skips nothing.
Mode 2 (reuse the validation samples as the mesher's core grid) recorded 0 reuse tiles in
every run. That is by design, not a bug: the grid is only reused when validation DISPROVES
a uniform verdict, and it disproved none. Mixed tiles, which are the ones that need a
grid, never run validation at all.
Recommendation recorded in WORK-NEXT.md, pending the owner: default the outer classifier
mode to 0. The code default is NOT changed in this commit.
CORRECTION to
|
||
|
|
667da8df14 |
docs(work-next): promote item 4 to performance architecture
Written by the classifier-fix Codex round before it was closed. The classifier is a second evaluator -- interval proofs, exact certificates and final-field validation -- beside the canonical lowered one, and the runtime can validate the same tile again before meshing. Any classifier kept long-term must consume the lowered representation and reusable density data. That round's other uncommitted edit was NOT kept: it flipped GVoxelForgeOuterClassifierMode 1 -> 0, turning the outer classifier off by default. That was A/B setup for an unfinished experiment, not a measured decision, so the committed default (1, classifier on) is restored. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X9DLqyXrJxG4TojzDrSmVw |
||
|
|
f2044135ea |
fix(mesher): stop forcing the nested block classifier on -- but I cannot reproduce the 3.5x
The code contradicted its own documentation. VoxelMarchingCubesMesher.h:150 says to leave
the optional 8^3-block refinement DISABLED in streaming, "repeating a proof on ..." --
and VoxelWorld.cpp forced `Mesher->bUseBlockEarlyOut = true` regardless.
It is now off by default, behind `voxel.UseBlockEarlyOut` (CVar + command line), so the
capability stays available for the focused diagnostics where it was measured to help.
⚠️ THE HEADLINE NUMBER DOES NOT REPRODUCE, AND I AM NOT CLAIMING IT
Sol's second pass read a 3.5x from the attribution table:
classifier disabled 587.991 ms
classifier enabled 2,056.596 ms
My own clean A/B on this flag, quiet machine, 3 runs each:
nested OFF 0.597 / 0.613 / 0.607 s mean 0.606
nested ON 0.637 / 0.599 / 0.605 s mean 0.614
Identical within noise.
So either the 2,056 ms control exercised more than this flag does, or the 3.5x lives on
a path the 128^3 export does not take. PERF-ATTRIBUTION.md describes that figure as "the
separate classifier control", which is not obviously the same lever. Until the game-path
A/B is run, treat the 3.5x as UNCONFIRMED.
What this commit is worth on its own: the code now does what its documentation says, the
behaviour is switchable rather than hardcoded, and geometry is unchanged --
SHA-256 b3e5f4c3..9b377 identical with the flag on, off, and against
|
||
|
|
bb8ec51939 |
measure(perf): the remaining 4.3x is ALL density evaluation -- and the classifier costs 3.5x in game
Measurement only; no density or meshing decision changed. Full table in
PERF-ATTRIBUTION.md. The profiler self-check finally passes honestly: profiled 606.128
vs unprofiled 602.341 ms, **+0.63%** (it used to inflate 11.5x).
THE ATTRIBUTION, and it is almost embarrassingly one-sided
mesh ledger, additive, sums to the clock exactly (sum_matches_mesh = true)
shared density-grid fill 590.923 ms 97.4913%
tile parallel wall 10.972 ms 1.8102% cells, interp, normals, streams
tile merge 4.232 ms 0.6982%
pre-tile setup / prep 0.002 ms ~0%
remainder 0.0001 ms ~0%
------------------------------------------------
total 606.128 ms
GetDensityAt parent: 580.184 ms worker-wall, nested inside that 590.923 ms.
⇒ **The mesher is exonerated. Marching cubes, vertex interpolation, normals and stream
building are 2.5% combined.** The whole 4.3x is density evaluation, which is where three
of us have been looking and none of us had proven it.
WHAT IS ACTUALLY BEING DONE, per 2,248,091 samples
rooms 11,099,891 candidates -> 1,730,920 evaluated
tunnels 28,951,420 candidates -> 3,462,565 evaluated
tunnel-core 28,951,420 candidates -> 1,881,812 evaluated
~31 candidates SCANNED per sample, ~3.1 evaluated
fused detail ran on 1,079,777 and skipped 1,168,314 samples (52.0%)
software tunnel cache: 2,248,043 hits / 48 misses -- not the problem
The post-stack structural tail, which I have suspected twice, is small: StructuralTail
20.9 ms CPU / 1.9 ms wall, DensityStructuralPosts 21.9 / 2.0, PassageStructuralPosts
10.5 / 1.0 -- all nested samples against a 590.9 ms wall.
⭐⭐ AND THE FINDING THAT MATTERS MOST FOR THE GAME
clean export, classifier absent 587.991 ms
same export with the classifier 2,056.596 ms
The classifier makes generation **3.5x slower**, it is ABSENT from the export path we
have benchmarked for five days, and the GAME PATH USES IT. Its control route runs
211,289 support-column builds, 2,171,763 candidates, 1,370,314 floor queries and
2,296,243 checks -- none of which the fused export route executes at all.
⇒ Every optimisation this week was measured on a path that skips the single largest
cost the player actually pays. That is a measurement-design failure and it is mine.
Also newly visible: the full export wall is 1,004.557 ms, of which mesh is 606.128 ms
(60.3%) and OBJ WRITING is 394.273 ms (39.2%). My "0.556 s" figures have always been
mesh_seconds alone.
One real hot-path improvement landed with the instrumentation: AreCountersEnabled()
returned an unconditional `true`, so counter hooks were live in shipping builds. It is
now a relaxed load gated on diagnostic mode.
VERIFIED BY ME: build 0 errors; export 0.552 / 0.555 / 0.566 s (
|
||
|
|
cf0319d480 |
perf(streaming): item 3 bought nothing, item 5 removed dead weight -- both worth knowing
Two WORK-NEXT items, one null result and one confirmed removal. Item 4 untouched.
ITEM 3 -- CANCEL OBSOLETE WORK AND PRIORITISE THE FLOOR: NULL RESULT
Clean -nullrhi, diagnostics off, 800 cm/s, 200 m of travel:
before after
request->ready p95 0.369117 s 0.367612 s
queue wait p95 0.066949 s 0.064483 s
generation p95 0.287926 s 0.283642 s
p95 travel distance 2.952938 m 2.940894 m
obsolete aborts 0 12
Flat. Aborting obsolete tiles, sorting from the true pawn position and prioritising the
occupied/next tile changed request-to-ready by 0.4%.
⭐ AND THE NULL RESULT IS ITSELF THE FINDING. Look at the split: queue wait is 65 ms of a
368 ms p95; generation is 284 ms. **The queue was never the problem, so reordering it
cannot help.** Only 12 tiles in a 200 m run were obsolete enough to abort. The floor is
late because generation is slow, not because work is badly ordered -- item 3 establishes
that by exclusion, which is worth more than the 0.4%.
The machinery is kept: it is correct, it costs nothing, and it will matter once
generation is fast enough for ordering to be the binding constraint.
ITEM 5 -- VERDICT CACHE REMOVED. It was pure overhead.
Clean moving-session audit:
outer calls/probes/hits 2,109 / 2,109 / 0
nested calls/probes/hits 19,904 / 19,904 / 0
enclosing hits 0
stores 15,877, evictions 15,365
⇒ It stored 15,877 proofs, evicted 15,365 of them, and hit ZERO times. A moving player
visits unique regions; the cache was filling and thrashing a 512-entry table under a
global lock for no benefit. Same-binary A/B: request p95 0.367645 vs 0.365978,
generation p95 0.285559 vs 0.285992 -- neutral within noise, so its cost was the lock and
the linear scans rather than time we can see.
Removed: the global cache, its lock, the entry table, the invalidation path, the
cache-only profiler fields and the synthetic probe. The proof classifier stays.
⚠️ I asked for this cache two days ago on the strength of a commandlet measurement that
re-visited the same region repeatedly. That access pattern is nothing like a moving
player, and I should have said so when specifying it.
VERIFIED BY ME: build 0 errors; export 0.563 / 0.565 / 0.566 s (
|
||
|
|
35de59bac5 |
perf(opstack): fused evaluator -- 1.05s to 0.56s, byte-identical, and the ~70% early-out is back
WORK-NEXT item 2. The authored operator graph is lowered at chunk-cache build time into a fused scalar evaluator for canonical TunnelNetwork/Underwater stacks. Operators are untouched; this is a lowering, not a de-composition. Custom recipes, composer/lateral stacks and other archetypes stay on the interpreted block path, selected by a build-time EVoxelOpFusedEvaluator marker with `-voxel.UseFusedEvaluator=0` to A/B it. ⭐ MY OWN A/B, same build, 3 runs each: fused 0.545 / 0.563 / 0.561 s mean 0.556 interpreted 1.066 / 1.036 / 1.033 s mean 1.045 -46.8%, 1.88x geometry SHA-256 b3e5f4c3..9b377 IDENTICAL across fused, interpreted, and |
||
|
|
0388c7dede |
docs: Sol's read-only audit, verbatim
The full 34 KB assessment that WORK-NEXT.md was built from, kept in the repo so any future session has the reasoning rather than my summary of it. Read-only audit by gpt-5.6-sol at xhigh; nothing was modified when it ran. Its two-sentence verdict: 'The operator abstraction leaked into the innermost loop, and streaming treats work submitted/applied as safe to stand on.' Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012aheo2crrZmHuYtPpdY2Cb |
||
|
|
081cc5e459 |
fix(streaming): collision-ready gate -- the pawn waits for a COOKED floor, not a submitted one
WORK-NEXT item 1, plus all three of item 6. Item 2 (the fused evaluator) untouched as
instructed.
⭐ RMC DOES EXPOSE WHAT WE NEEDED, so the gate rests on a real signal:
OnCollisionBodyUpdated (delegate -- diagnostic)
SetCollisionConfig() -> TFuture<ERealtimeMeshCollisionUpdateResult> (AUTHORITATIVE)
RealtimeMeshComponent was READ ONLY, per the owner's grant. Nothing there was modified.
THE INVARIANT
Until now nothing guaranteed a tile the player occupies has collision. apply_s ended at
mesh SUBMISSION; RMC cooks asynchronously and we recorded no completion, so no
measurement this project has ever taken said when physics could actually collide.
- per-tile CollisionReadyTiles state, with stale-callback protection
- HandleTileCollisionCookComplete driven by RMC's cook future
- pawn gated at BeginPlay and pre-physics on the FEET-SUPPORT tile -- deliberately not
the actor-centre tile, because the floor that catches a falling pawn is what must be
cooked -- plus the predicted movement path and solid/air traversal
- movement-component state saved/restored, so a temporary stream wait cannot
permanently change a character's movement mode
- new trace fields: mesh_submit_to_cook_s, collision_request_to_cook_s,
body_event_to_future_s -- three boundaries where we had one blurred number
ITEM 6, all three:
- LoadedTiles is now recorded only after SUCCESSFUL mesh submission, and a failed
mesh init retries. Previously a failed init left a tile marked loaded forever -- a
permanent hole.
- origin spawning fixed (the zero-position guard made a pawn at exactly
FVector::ZeroVector indistinguishable from "no pawn" -- and the owner spawns at 0,0)
- exact core-lattice validation for uniform whole-tile verdicts, which previously had
no safety net while block verdicts did
⚠️ I FIXED TWO COMPILE ERRORS MYSELF rather than spend another Codex round on them:
`GetMovementMode()` / `GetCustomMovementMode()` do not exist on
UCharacterMovementComponent -- MovementMode and CustomMovementMode are public fields.
Two lines. Codex did not build this round, so it could not have caught them.
VERIFIED BY ME: build 0 errors after the patch; export 1.022 / 1.055 s (
|
||
|
|
58bdfb32de |
docs: WORK-NEXT.md -- the queue after Sol's read-only audit
Ordered by importance then size. Sol (read-only, xhigh) audited experimental @
|
||
|
|
aa62971047 |
tools(trace): Play-to-steady-state timeline -- startup is 83ms, the other 8.2s is tiles
Measurement only, no optimisation, per the instruction. First time anyone has looked at
the path BEFORE LoadTile, and first time any measurement has used the owner's REAL
assets instead of the commandlet's synthetic strates.
Trace: Saved/StartupTraceRealFinalTrace.startup.jsonl -- 873 JSONL records, 268 KB,
841 tile records, bounded at 4096 with zero suppressed. Structured, own file,
stream-parseable; the 13 GB log pile taught that lesson twice.
TIMELINE
BeginPlay 45.585 ms
StrateManager.Initialize 29.018 ms
GeneratePassages 6.628 ms (5 passages)
first BuildDesiredTiles 2.710 ms
------------------------------------------
all startup stages ~83 ms
BeginPlay -> steady state 8.216 s
process launch -> stop 20.164 s
⚠️ My hypothesis was wrong: I expected layout resolution or GeneratePassages to be a
hidden one-off cost. They are 83 ms combined. **The 8.2 seconds is tiles, all of it.**
A further ~2.05 s sits between BeginPlay finishing and the first desired-set build, and
the trace attributes that to engine/map/player startup, not to us.
REAL ASSET RESOLUTION -- two things worth the owner's attention
settings /Game/VoxelForge/DA_Settings, seed 0
⭐ five slots, ALL resolving to /Game/VoxelForge/DA_Strate3
InterStrateGapChunks 2
MaxClipLevel 4, ClipRadius 3, RenderDistanceChunks 0
bFarSheetRing true, but NO sheet tiles exist because render distance is 0
⭐ bEnableDensityVolume FALSE -- already off, no volume object, no GPU upload
DA_Strate1 (the 10.7 KB surface strate) and DA_Strate2 (rooms + water) are not in play
at all. Every strate in the world is Strate3.
THE DESIRED SET -- 841 tiles, and the shape is the story
LOD0 343 tiles 8 m each 56 x 56 x 56 m
LOD1 218 16 m 112 x 112 x 80 m
LOD2 120 32 m 224 x 224 x 96 m
LOD3 80 64 m 448 x 448 x 128 m
LOD4 80 128 m 896 x 896 x 256 m
⭐ LOD4 covers 896 x 896 x 256 m -- about 205 MILLION cubic metres of cave -- and its
verdicts are 0 AllAir / 0 AllSolid / 80 Mixed. Not one LOD4 tile can be skipped, and
each costs 127.5 ms p50 / 291.6 ms max to generate. That is roughly 12 s of CPU spent on
geometry nobody can see from inside a cave.
TILE DISTRIBUTIONS (p50 / p95 / max ms)
LOD tiles verdicts A/S/M req->ready generation mesh
0 343 98/123/122 44.9/420.8/819.5 9.6/358.2/767.6 0/341.6/726.1
1 218 49/83/86 31.1/148.9/188.6 8.7/134.3/164.2 0/117.8/151.1
2 120 0/39/81 34.0/61.6/76.9 10.9/43.6/63.7 9.9/40.4/60.5
3 80 0/2/78 46.4/85.9/96.3 38.5/80.7/87.8 31.0/67.5/70.7
4 80 0/0/80 148.2/272.8/304.2 127.5/253.8/291.6 127.4/253.8/291.5
totals: 147 AllAir, 247 AllSolid, 447 Mixed, 669,834 triangles
apply never exceeds 0.43 ms at any level
zero classifier-cache and region-cache hits on a fresh process, as expected
⇒ The two costs are LOD0's 122 meshed tiles (~360 ms p95 each) and LOD4's 80
unskippable tiles (~150 ms each). Apply, queue and startup are all noise beside them.
VERIFIED BY ME: build 0 errors; export 1.034 / 1.089 s (
|
||
|
|
5ddd96664d |
perf(opstack): invert the loop + prune per block -- 1.45s to 1.02s, byte-identical
The architecture round. Loop inverted from per-sample-per-op to per-op-per-block, operators pruned per block by interval bounds, profiler moved out of the hot loop. my build, 3 runs: 1.013 / 1.036 / 1.075 s ( |
||
|
|
adb34dffa9 |
feat(passages): passages are D-tunnels now -- legacy support writer fires ZERO
The owner was right and said so plainly: "the tunnels should be a flat D with then a
bit of noise added, as it's most basic shape -- this alone should make all tunnels not
over X steepness to be walkable." Codex had reached the same conclusion from the other
direction ("the native fix is to author the inter-strate passage floor profile during
passage construction"); it had measured the current position while he described the
destination. This is that refactor.
Walkable inter-strate passages now bake their floor profile and bounded relief during
GeneratePassages. Evaluation composes a D-shaped SmoothMax floor, with final MC
ownership after the generic writers -- the same ordering fix that made the tunnel floor
native in
|
||
|
|
4f8b4a9a27 |
fix(gen): the phantom terracing is the PASSAGE support writer -- plus a region verdict cache
The owner played the build and reported four things. Three are answered with evidence, one is disproven, and my own leading hypothesis was wrong. ⭐ 1. THE PHANTOM TERRACING IS NOT MARCHING-CUBES ALIASING He reported stairs surviving with bTunnelFloorTerracingEnabled = false. I suspected MC lattice aliasing on a near-planar floor; I was wrong. An A/B over the same mesher, counted in pixels: graph-tunnel floor removed 2,813 / 147,456 px changed 1.91% passage support removed 25,695 / 147,456 px changed 17.43% ⇒ The bands are the INTER-STRATE PASSAGE SUPPORT WRITER, which is independent of the tunnel terracing flag. That is exactly why turning terracing off did nothing: he was disabling the wrong system. FCaveTerraceMod is inactive (TerraceStepHeight=0) and was never involved. ⚠️ It cannot simply be switched off. With it disabled: fit 20,804 -> 20,511, walk-reachable 10,884 -> 7,525, components 260 -> 272. Route still connected, but a third of reachable space gone. It stays as a correctness backstop. The native fix is the same pattern we just applied to tunnels: author the inter-strate passage floor profile during passage CONSTRUCTION. Codex judged that refactor too large to risk this round and said so rather than attempting it. MC aliasing remains theoretically possible at shallow angles (Lorensen & Cline 1987), but the same-mesher A/B proves our writer dominates. Dual Contouring (Ju et al.) was considered and rejected as a disproportionate mesher/topology change. 2. THE ROUGHNESS COST DEFECT DOES NOT EXIST -- my hypothesis, cleanly disproven FBM 2.91s / 66.92% skips · Ridged 2.85s / 66.53% · Mixed 2.92s / 66.82% Cellular 2.99s / 66.43% · FBM frequency 0.025-0.5: 2.88-2.99s, 66.80-67.04% I predicted a shared bound across noise types collapsing the classifier. The code already carries separate conservative bounds per type. No roughness code was changed. ⇒ Whatever the owner saw is not steady-state export cost. Most likely the in-editor regeneration a parameter change triggers, which is the full-rebuild cost, not the per-sample cost. Worth confirming with him. 3. ROOM MOUTH RISE -- his idea, implemented, off by default RoomMouthRiseBlendVoxels, default 8.0 blend 8 fit 20,804 reach 10,884 40,429 v / 75,416 t capability-NEUTRAL blend 24 fit 20,792 reach 10,874 40,337 v / 75,232 t REJECTED, loses capability Relief preserved at blend 8 (dihedral p50 2.5584, p90 33.7191). The chosen camera did not see a mouth bench, so no visual claim is made. 4. ⭐ VERDICT CACHE WITH REGION REUSE -- answers "why re-prove what we proved?" 130 classification calls -> 1 store, 129 hits, of which 128 ENCLOSING-REGION hits. The region level is the one that matters: deep rock is empty thousands of chunks at a time, and one proof over a large box now serves all of them. Soundness, which is the whole risk (a stale "empty" silently deletes geometry): 512-entry bounded LRU; stores ONLY AllAir/AllSolid, never Mixed; key includes seed, layout/lifetime id, params fingerprint, diff version, density/seal settings, support mode, lattice step, origin and extent; dynamic season/composer/terrain-op/biome configs FAIL CLOSED and bypass reuse. Deliberately session-resident, not on disk -- cross-process persistence cannot serialise all asset/layout/edit state safely yet. VERIFIED BY ME: build 0 errors; export 1.353 / 1.430 / 1.432 s ( |
||
|
|
2260c4d47a |
perf(gen): the floor is finally NATIVE -- clamp 29,634/29,634 -> 0, and the 551ms empty tile is dead
Two targets, both hit, and the second is the biggest in-game win since the interval work. 1. THE FLOOR IS NO LONGER PATCHED IN The audit proved the backstop was doing the work: TunnelAuthoredFloorProtectionClamps fired on EVERY authored floor sample while the named fallbacks fired zero. The cause, in its own words, was that the stack composed the floor before the common disturbance/passage writers, so every sample looked like a post-hoc clamp. The floor is now composed ONCE, after those writers, at the final MC boundary. The clamp inside the operator stack is deleted; the metadata stays on the sample for the hand-off and for diagnostics but may no longer modify density. clamp fires 29,634 / 29,634 -> 0 player-fit cells 20,804 (unchanged) walk reachable 10,884 (unchanged) connectivity arrival -> departure, Connected geometry SHA-256 b3e5f4c3..9b377 IDENTICAL to |
||
|
|
5156084cac |
audit(gen): which post-hoc ops are tunnel-floors in disguise -- and the X+2A budget is unsound
The owner's framing for the night: "if it sees performance opportunity by unifying
some process that should be, or like the tunnels, have it be native more than patching
it after generation". This is the audit. No generator behaviour changed; the only code
here is request/generation timing instrumentation in VoxelWorld.
STRUCTURAL-POST AUDIT -- verdict per operator
FBoundarySealOp 0.000011 us/sample KEEP. A boundary condition, not a workaround.
FXYEdgeSealOp 0.000054 us/sample KEEP. Domain constraint; identity today with
WorldRadiusVoxels=0.
FOriginSpineOp 0.000588 us/sample PARTLY family, but origin anchoring and
ordering are special.
FPassageCarveOp 0.019977 us/sample Could share the volume/floor representation,
but its boundary-crossing order and
current-density carve are load-bearing.
floor protection 0.061298 us/sample ⭐ THIS IS STILL THE REAL PATCH.
TunnelAuthoredFloorProtectionClamps fired 29,634 / 29,634 -- every authored floor
sample -- while the named support/room fallbacks fired ZERO. So the backstop is not
a rare safety net; it is doing the work, and the tunnel floor is not yet native.
⭐ AND IT NAMED THE PATH OUT, which I had not seen: the floor is authored at build time
but LATER WRITERS can still refill or erase the clearance, so a clamp re-asserts it.
Native means either composing the floor AFTER all writers, or making every later
writer floor-aware with a proof it cannot violate the invariant. Removing the clamp
today would be unsafe. It did not remove it.
PRIMITIVE FAMILY -- valid, but my proposal was too crude
Algebraically sound: solid + floor via SmoothMax + bounded relief + smooth union.
Rooms, swept tunnels, landing rooms and some passages can share a cached
walkable-volume DESCRIPTOR (shape/profile, baked floor, relief params, mouth/room
ownership, capability metadata).
⛔ But they should NOT become one undifferentiated operator: tunnels are swept
multi-segment chains, passages cross structural boundaries, origin landings have
special finite geometry, seals are domain conditions. Flattening those would WEAKEN
interval proofs and operation ordering -- the opposite of what I hoped unification
would buy. Renaming the passage carve would not help either; it Lerps against
incoming density, so its global bound stays unbounded regardless.
X + 2A CLEARANCE BUDGET -- SETTLED, AND IT IS UNSOUND AS SPECIFIED
A surface-displacement budget needs BOTH an upper bound on field perturbation AND a
lower bound on the gradient near the zero surface. The second fails at flat or
degenerate crossings, and the current-density Lerp/Min operators make a global bound
unavailable. Perlin derivative bounds alone do not fix it.
⇒ Usable only inside separately proven primitive regions; elsewhere the validator and
backstop must stay. The owner and I both assumed interval propagation already gave
us this. It does not, and now we know why rather than just that.
ITEM ZERO -- the suspected in-game regression: NARROWED, NOT CONFIRMED
Queue wait is real, but meshed latency is primarily GENERATION time, not queue. One
EMPTY LOD0 generation took 551.7 ms, so it is not pure queue saturation either.
RoomGraphSource measures 0.278939 us/sample, which cannot explain a 400-1000 ms mesh.
Codex declined to call it a confirmed code regression on this data. Still open, and
it now points at the known-unsolved LOD0 mixed-classifier fallback rather than at the
floor work.
REFERENCE ARCHETYPE -- costs, and a correction to my arithmetic
CorridorRadius 12.5 voxels is a 6.25 m DIAMETER (I said 3.1 m), and validation caps
it at 16 voxels. The 15-20 m reference hall needs a separate gallery archetype or a
larger cell-size budget; raising the value violates current lattice/wall assumptions.
FCaveTerraceMod is a true no-op disabled (0.000531 us/sample); enabled it adds two
cached SDF probes, estimated lower bound ~0.56 us for a qualifying sample -- estimated,
not measured. Columns belong to slab generation; TunnelNetwork needs a baked column
op. Water is presentation, not rock density, and null-RHI cannot price it.
Build 0 errors. No RMC files, links, historical checkouts or logs touched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aheo2crrZmHuYtPpdY2Cb
|
||
|
|
8e42d6d807 |
feat(tunnels): floor authored at BUILD time, room clips tunnel, climb tier added
The round the owner asked for, with three corrections from Codex that are worth more
than the features.
WHAT LANDED
- The complete tunnel floor profile is authored into FCachedTunnel during
BuildChunkCache, not derived per sample. This was his point: "it should be done at
creation time, since it knows its destination."
- Room floor ownership blends/clips the tunnel floor at mouths -- his A > B boolean.
- The traversal validator gained a climb tier, structured exactly as agreed:
bWalkOnlyCanReachDeparture / bClimbCanReachDeparture kept SEPARATE, with
WalkOnly / Climb / MineRequired cell counts reported alongside.
The comment in the header states the contract: "The primordial capability contract
is walk-only... climb is reported as a separate tier and never makes the hard
connectivity verdict pass." That is the distinction we wanted: reporting tiers, not
permission.
- Floor controls exposed under Cave Morphology|Tunnels|Floor.
⚠️ CORRECTION 1 -- LARGE LEDGES ARE NOT CAPABILITY-SAFE YET, so they stay opt-in.
default (preference 0) fit 20,804 walk reach 10,884 0 ledges
preference 2 fit 20,765 walk reach 10,712 360 ledges
Ledges cost 172 walk-reachable cells. Codex kept preference 0 (the old staircase) as
the default rather than shipping the owner's preferred look at the price of walkable
space, and led its report with that. Correct call.
⚠️ CORRECTION 2 -- THE BACKSTOP STILL CANNOT GO. Support/room fallback counters were
zero, but the structural protection clamp fired on 31,017 of 31,017 authored floor
samples -- 100%. So the shape is still not correct by construction; the clamp is
doing the work. Instrumenting it was the right move: we now have a number instead of
an argument.
⚠️ CORRECTION 3 -- THE "X + 2A" CLEARANCE BUDGET IS NOT IMPLEMENTABLE AS I SPECIFIED.
Interval propagation bounds FIELD VALUES, not SPATIAL DISPLACEMENT. Deriving A needs
a proven Lipschitz/influence bound for every post-operation, which we do not have.
Both the owner and I assumed the interval work already gave us this; it does not.
The idea is still right, the prerequisite is a displacement bound.
MEASURED BY ME: build 0 errors; export 1.365 / 1.357 / 1.420 s (checkpoint was
1.321 / 1.357), flat within noise; 153,346 triangles.
ALSO MEASURED THIS ROUND
- Edit cost: 8 affected chunks, 195.5 ms total -- generation 195.471 ms, apply 0.059,
diff 0.020, queue 0.001. It is full level-0 regeneration; a dirty-mesh path needs
partial section support that is unavailable without modifying RMC.
- Streaming caps: effective generation cap 14, pending max 14, CAP HIT. Mesh applies
per frame 4 (not hit), 2 ms apply budget (not hit), unloads 6 (not hit).
⇒ The generation core cap is what binds during startup fill.
- Peak export RSS 1.70 GB (was 19.5 GB before the memory work).
- LOD4 empty outliers gone. LOD0 not solved: 4,600 empty tiles at 3 us median, but 11
mixed-classifier fallbacks over 100 ms, max 554 ms -- verdict=Mixed, then the full
mesher, producing no triangles.
⚠️ UNVERIFIED AND CONCERNING: the reported in-game meshed times are far worse than
412a7ad's -- p50 498.8 ms vs 115 ms, p95 1.227 s vs 410 ms, max 1.974 s vs 844 ms.
The samples differ (9,336 ready events vs 841 requests, different traversal, possibly
queue wait included), and the export path is flat, so I do not know whether this is a
real regression or a different measurement. I have NOT reproduced it myself. It is
the first thing the next round must settle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aheo2crrZmHuYtPpdY2Cb
|
||
|
|
e91f1c44bb |
wip(tunnels): checkpoint -- floor parameters exposed, round cut short by Codex credit limit
⚠️ THIS IS A CHECKPOINT, NOT A FINISHED CHANGE. The agent hit its usage limit
mid-round (locked out until 2026-09-15) after compacting its context, and never
filed a report or capability numbers. Committing so 1,344 lines are not left
uncommitted for five days. Verified by me only to the extent stated below.
WHAT LANDED
The tunnel floor controls are now real strate parameters under
"Cave Morphology|Tunnels|Floor", which is what the owner asked for -- hand-made
assets can tune them and the composer can roll them later:
bTunnelFloorEnabled true
bTunnelFloorTerracingEnabled true
TunnelFloorTerraceStepHeight 1.71 voxels (the existing 42.75 cm riser)
TunnelFloorMaxLedgeHeight 12.0 voxels (3 m -- climbable, not walkable)
TunnelFloorGentleSlopeThreshold tan(44 deg)
TunnelFloorLedgeCountPreference 0 (0 = old per-segment staircase;
>0 = whole-chain ledge policy)
TunnelFloorMaxLedges 4096
⭐ So the staircase-vs-ledges question the owner raised is now answerable IN THE
EDITOR without a rebuild: set LedgeCountPreference to 2-3 and the whole-chain
policy takes over from the per-segment one.
VERIFIED BY ME
build 0 errors
export, 2 runs 1.321 / 1.357 s (
|