Handoff: a pasteable resume prompt at the plugin root -- read order, exact state (Phase 0.5 green, Phase 1 done and measured, step 3 written but not compiled), the immediate next action, hard rules, open items, and the method lesson from this session. Skills: Jahni's UE library was at .claude/skills/core/<name>/SKILL.md, two levels deep, where Claude Code discovers skills one level deep -- so none of the 39 were loading. Flattened; 124 reference files intact, all frontmatter valid, folder names already matched their name: field. core/category.md left as documentation. Confirmed loading. They are untracked and cannot be tracked without un-ignoring .claude/ itself (git cannot re-include a file whose parent directory is excluded). Same shape as AUDIT P1; flagged, not actioned. Note for the next session: module-and-build-system documents PCHUsage, shared PCHs and IWYU -- the exact mechanism that blocked C10's settling experiment. That skill was in the repo, undiscovered, while it was worked out the slow way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.4 KiB
Handoff — VoxelForge operator stack, 2026-07-27
Paste the block below into a fresh session. Everything it refers to is on disk and in git.
You're picking up an agreed refactor of the VoxelForge UE5 voxel plugin, on branch experimental
(already checked out — do not create another). I'm Jahni. Design and progress are written down so you
don't re-derive them.
Read first, in this order
CLAUDE.md— project rules. Rule #1 is absolute: never build, compile, or run the editor. I build everything myself. When code is done, stop, say "ready to build", list the likely compile-error spots, and wait.OPSTACK-PROGRESS.md— THE LAST ENTRY FIRST. Append-only log of what is built vs merely written. This is the resume point.OPSTACK-PLAN.md— the plan. §2.5 op taxonomy, §2.6 acceptance bar, §4 phases, §5 invariants.OPSTACK-DECOMPOSITION.md— all 8 archetypes broken into ops, every param traced. §10.4 is the port order, §11 the open questions.AUDIT-2026-07.md§C10 — read before touching the Maze equivalence test. Six builds were spent there; it is parked deliberately.CODEMAP.md— navigation. Trust symbol names over line numbers.
Where things stand
Phase 0.5 — DONE, green. Five automation tests, all passing (Session Frontend → Automation,
filter VoxelForge): DensityPurity, ClassifyTileSoundness, DiffLayerContention,
LiveEditInvalidation, OpStack.BoxVerdictFold, OpStack.MazeEquivalence. They found and fixed a
real bug (AUDIT C2 — five caches missing LayoutVersion).
Phase 1 — DONE and verified. Maze decomposes into seven ops with no contortion:
ConstantRock → LatticeCorridor → SdfRoughness → SdfCarve → Spine → Seal → Passage. Measured:
SDF reproduced bit for bit, zero isosurface crossings out of 20 000, window-invariant across
worker threads, every box verdict survives brute force, and 23 of 60 tiles proved uniform where
ClassifyTile proves zero for any cave archetype. That last number is the perf case for the whole
refactor, measured rather than argued.
Phase 1 step 3 — WRITTEN, NOT COMPILED. The stack is wired into GetDensityAt behind
UVoxelStrateDefinition::bUseOperatorStack, with the ported-archetype list living only in
UVoxelStrateManager::UsesOperatorStackForChunk(). This is the immediate next thing to build.
The immediate next action
- I build. Likely error spots: the
else switchform inGetDensityAt,FVoxelOpStackas athread_local(it is move-only, reset by move-assigning a temporary), the new include. - Then the visual A/B, which is the last thing Phase 1 needs: tick
bUseOperatorStackon a Maze strate, regenerate, compare against the same seed with it off. Pass = recognisably the same maze (same corridor scale, connectivity, feel). That isOPSTACK-PLAN §2.6's bar — judged on a screenshot, not a diff. - Then Phase 2, starting with the cheapest win:
FlatPlain+CrystalChambercollapse into one op (OPSTACK-DECOMPOSITION §3). Ask me §3.1 first — whether the slab floor noise's Z term is intentional; if it can go, both archetypes become XY-pure and start skipping tiles.
Hard rules that prevent real bugs
- Density sign: negative = solid, positive = air at the mesher. Inside the op stack the
convention is INTERNAL (positive = solid), negated once by the caller. The SDF channel uses
standard SDF convention, so
min()means opposite things on the two channels. This is the #1 source of confusion in the plugin —VoxelDensityOp.hexplains it. - Never run both density paths in one world, and never compare them for equality (§C10).
- Every cache key includes
LayoutVersion;ProcessQueuestaysEQueueMode::Mpsc;Epochcarries through every async path; don't "optimize" theARCHITECTURE §8.10perf invariants. - Never edit
Binaries/,Intermediate/,*.generated.h. Comments are French + English — match the surrounding file. - Commit per coherent unit with a real message. Never push.
mainis the known-good fallback. - Update
CODEMAP §3for new/renamed symbols,ARCHITECTURE §8for design changes, tick phases inOPSTACK-PLAN.md, and append toOPSTACK-PROGRESS.md.
⚠️ The lesson from this session — it cost six builds
Chasing a 1-ULP difference in the Maze port, I proposed five hypotheses and every one was refuted
by measurement: the FVector round-trip, a transcription slip, /fp:fast across translation units,
inlining context, and compile-time-constant vs runtime parameters. Each was plausible. Each cost a
build. What actually produced information was instrumenting — a bisect, a three-way comparison, a
variable-isolation harness.
Worse, twice I reasoned confidently from a premise I hadn't checked (a build flag that had landed in the wrong module; a comparison that was circular by construction and could not fail).
So: on any numeric discrepancy, instrument before hypothesising, and verify the premise before reasoning from it. And know when to stop — Jahni called it, correctly, once the port was proven correct on every axis that affects the game and only the last rounding was unexplained.
New this session: 39 Unreal skills are installed
.claude/skills/<name>/SKILL.md — they were nested one level too deep and invisible; now flattened
and loading. Directly relevant: automation-and-testing, coding-standards,
module-and-build-system (covers PCHUsage / shared PCH / IWYU — the exact thing that blocked
§C10's settling experiment), game-thread-performance, memory-and-gc, navigating-engine-source.
Use them — the one that would have explained the shared-PCH failure was sitting in the repo,
undiscovered, while I worked it out the slow way.
Known open items, deliberately not done
- AUDIT C1 — unbounded
SeedF, one line at six sites. Dormant at small seeds; applying it re-rolls the world's noise and forces a re-tune, so it wants its own build. Still a real bug. - IWYU debt — seven headers use engine types they never include; the plugin only compiles because
of the shared PCH. Blocks
FPSemanticsexperiments. Worth clearing on its own terms. - AUDIT C10 — the parked ULP residue. Read it before reopening; five hypotheses are already refuted in a table there.
OPSTACK-DECOMPOSITION §11— five design questions for me, most importantly whether the two-channelEval(already implemented) stays.