Files
healer-man/scripts/runewaker-pipeline/README.md
T
2026-10-06 22:25:34 -04:00

546 lines
29 KiB
Markdown

# RuneWaker dungeon pipeline
This pipeline converts preserved RuneWaker `.ros` dungeon assets into the same
browser-facing GLB roles used by HealerMan's WoW dungeon pipeline:
1. the preserved Rune engine reads every WDB descriptor and exports each unique ROS once into a normalized-path cache validated by the source SHA-256;
2. Microsoft `texconv` decodes each cached resource's legacy DDS textures to PNG;
3. Blender converts the Y-up resources to reusable visual and collision GLBs;
4. the assembler applies every placement's full translation/quaternion/scale transform relative to the reviewed primary WDB anchor;
5. glTF Transform instances and optimizes the assembled visual with meshopt;
6. HealerMan's Recast stage bakes static navigation and the Khronos validator gates every GLB.
Run the Forsaken Abbey pilot from the HealerMan root:
```powershell
npm run runewaker:forsaken
```
Optional environment variables:
- `RUNEWAKER_ROOT`: preserved backup root containing `Resource` and `Tools`
- `BLENDER_BIN`: Blender 5 portable executable
- `TEXCONV_BIN`: Microsoft DirectXTex `texconv.exe`
- `MSVC_V142_ROOT`: portable MSVC v142 root used by the native build script
The shipping environment is written to
`src/assets/game/dungeons/forsaken-abbey` and registered as a playable
dungeon. The build reads all 184 WDB entity descriptors, uses the primary ROS
placement only as the server-to-local coordinate anchor, reads the entrance from
`Resource/luascript/03242.lua`, and requires that entrance to project within 2
meters of the generated navmesh.
All valid ROS placement resources are assembled by default. Use `--primary-only`
only for a deliberate compatibility/debug build. The build writes
`wdb-placement-manifest.json` with stable placement IDs, source TRS, the complete
primary-local Three.js matrix, resource-cache keys, bounds, flags, asset status,
and reviewed dynamic-object metadata. Static placements enter visual, collision,
and navigation assets. Explicit dynamic placements ship separately so runtime
state can move, hide, or replace them without baking their collision into the
static world.
Audit the checked-in WDB coverage without regenerating GLBs:
```powershell
npm run runewaker:audit:environment-assembly
```
See
[RUNEWAKER_ENVIRONMENT_ASSEMBLY_REPORT.md](./RUNEWAKER_ENVIRONMENT_ASSEMBLY_REPORT.md)
for unsupported types and dynamic candidates that still need source review.
Population and creature assets are separate, offline-capable stages:
```powershell
npm run runewaker:forsaken:actors
npm run runewaker:forsaken:population
```
Source-shaped combat coefficients and boss loot are refreshed independently:
```powershell
npm run runewaker:spells:refresh
npm run runewaker:loot:refresh
```
See [RUNEWAKER_FORMULA_AND_LOOT.md](./RUNEWAKER_FORMULA_AND_LOOT.md) for the exact formula mapping boundary and [RUNEWAKER_LOOT_IMPORT_REPORT.md](./RUNEWAKER_LOOT_IMPORT_REPORT.md) for every boss's loot status.
Only an explicit forensic refresh connects to the isolated development SQL
instance:
```powershell
npm run runewaker:forsaken:population:refresh
```
The normal population build consumes the checked-in 251-row Zone 102 snapshot
and never connects to SQL Server. It packages 150 combat spawns, eight boss
objectives, and nine authentic native-animation creature GLBs. The remaining 101 rows are
retained in the source report for later quest-object, door, transport, script,
and treasure passes.
## All configured instances
### Environment texture and lighting quality
The visual optimizer uses `lib/environment-optimization.mjs`. RoM architecture
keeps its source triangles and atlas UV interpolation: `--simplify false` is
required because generic mesh simplification collapses UVs on large planar
walls and floors. Meshopt compression and instancing remain enabled. Native
water and source-detail variant carriers disable joining, pruning and attribute
pruning so auxiliary maps and their mappings survive optimization.
`--texture-compress false` also prevents the optimizer's default
2048-pixel image resize; the separate KTX2 pass encodes the source dimensions.
`src/game/runewakerDungeonEnvironment.ts` supplies reviewed fallback palettes
for all 30 registered base dungeons. The registry applies this adapter before
creating Bite-Sized derivatives. A separate WDB zone exporter and
`DungeonLighting.tsx` now own recovered ambient/directional lighting and fog;
this is not embedded GLB light-component preservation. Native Standard shadows
follow player footing and High follows the camera. Fallback profile Standard
targets the entrance; WoW retains its existing lighting path.
Native entrance directions pass through the same primary-placement frame as
source points. `transformSourceHeadingToPrimaryThree` applies inverse primary
rotation and component scale, bridges source handedness, and normalizes XZ
before deriving runtime yaw. Preserve the Lua direction in source provenance;
using it directly as local yaw faces the wrong way in rotated WDB assemblies.
The selective texture compressor applies UASTC to explicitly reviewed base-color
basenames. Its initial eight-name policy covered 16 images in nine packages;
the current list also covers Barren's exact native atlas/floor crops and HOTO's
four stone/cliff maps and Origin's exact `elves_vine` cutout. Read
`compress-environment-textures.mjs` for the current
list. Those targets use UASTC level 2 with Zstandard 18 and RDO disabled,
retaining source dimensions and the complete mip chain; other images retain the
existing ETC1S path. Pass explicit GLBs or directories so the compressor never
scans the workspace implicitly:
```powershell
node scripts/runewaker-pipeline/compress-environment-textures.mjs <rom-glb-or-directory> --report <report.json>
```
Run the source-resolution, sampler and floor/wall UV diagnostics with:
```powershell
npm run runewaker:audit:environment-quality
node --test scripts/runewaker-pipeline/environment-optimization.test.mjs scripts/runewaker-pipeline/audit-environment-quality.test.mjs scripts/runewaker-pipeline/rom-visual-uv-adaptations.test.mjs
```
The generated `RUNEWAKER_ENVIRONMENT_QUALITY_REPORT.md` covers every registered
RoM visual. Density and UV-rank measurements identify candidates for review,
rather than certifying every polygon. The initial 30-dungeon hotspot dispositions
are recorded in
`artifacts/playtest/rom-environment-quality/rom-texture-pipeline-triage/uv-hotspot-triage.md`.
The later production review supersedes Barren's whole-atlas repeat with exact
floor islands and native wall detail. HOTO retains cliff gradients while adding
source-rock detail. Durable recipe opt-ins are implemented in
`lib/rom-surface-quality-policies.mjs`; current evidence is under
`artifacts/playtest/rom-deep-review/uv-stretch-review/` and
`docs/ROM_ENVIRONMENT_REVIEW_2026-10-06.md`.
Exact native atlas crops carry `texture.extras.romSourcePixelCrop`. The quality
audit verifies the native PNG hash and DDS dimensions, crop rectangle, canonical
PNG's exact RGBA bytes, shipped island dimensions and full mip chain through
`lib/source-pixel-crop-proof.mjs`. Verified island dimensions are reported
separately from the full native atlas; this does not exempt resized images.
`verify-native-uv-source-layout.mjs` independently compares hierarchy/TRS and
expanded ordered triangle attributes while allowing presentation UV1 and
primitive/material regrouping. Original source images must remain byte-identical.
`src/scene/runewakerSurfaceDetailMaterial.ts` supports source-pinned static rock
detail carried by named `KHR_materials_variants` materials. `useGameGLTF.ts`
registers it and `productionDungeonMaterials.ts` preserves it through cloning.
Triplanar sampling uses real world metres and inverse-transpose normals,
including instance transforms. Mean-normalized source textures modulate diffuse
RGB within bounded strength. Reviewed metadata can reduce wall base contrast
around the source mean and blend rotated tile samples to soften repetitions.
`floorBaseStrength` permits a verified full stone/moss tile to supply floor RGB
directly at the chosen world scale; it must not repeat a mixed cliff atlas.
Original UV0, base-map alpha and lighting semantics remain intact. Texture
uniforms participate in existing filtering/disposal. Carrier
variants require the reviewed optimizer's join/prune protections. These detail
scales are browser presentation adaptations, not reconstructed native UVs.
HOTO v2 migrates only complete source-pinned v1 metadata, verified carriers and
all 72 variant mappings; reapplication is idempotent. Its reviewed continuation
uses `promote-hoto-surface-v2.mjs`: the default mode verifies immutable candidates,
source/layout/codec proofs and screenshot hashes without writing. `--apply`
creates a new exclusive backup before replacing only HOTO's three visual GLBs
and current metadata. All non-JSON chunks are byte-identical to v1; historical
codec reports retain their original GLB hashes.
Sand Vortex uses nine native WDB terrain
chunks selected from authoritative encounter bounds, with the original per-chunk
indices, visibility, vertex normals, two DXT1 splat maps, five source tile DDS
layers, and their native tile scales. Runtime material blending normalizes the
source RGB weights and samples the full-resolution layer textures at their
source scales; this replaces the old flat, untextured arena fallback.
Sand Vortex opts into source-scaled side projection on steep terrain through
`source.nativeTerrain.cliffProjection`. The runtime retains native XZ sampling
on level ground and blends height-aware side sampling only on slopes. It uses
the original smooth normals, layer scales, and splat weights; topology and
flat-floor UVs remain unchanged. The asset-root inverse transform keeps this
projection stable through package placement, quantization, and instancing.
The Origin now recovers all 256 WDB terrain chunks selected by the full source
manifest. Four source DDS layers, their per-layer tile scales, and both DXT1
splat maps feed the same linear runtime blend. The previous `[2,2]` chunk
review was only an early ground probe and is not the current coverage claim.
The independent native-water builder decodes all 126 selected version-3 WDB
water layers with exact GUID descriptor joins. It recreates source visibility
masks, vertex color and alpha, and packages the 30-frame animated normal
sequence as exact top-mip PNG carriers. The runtime applies those frames as
animated source normal maps and samples transformed source-world coordinates;
the glTF `TEXCOORD_0` on water layers is a source-world XZ validator carrier
only. The original DDS files and all mip hashes remain in the source audit
cache. Source-enabled non-DIRECT water now uses a bounded browser adaptation of
AquaFX camera reflection and pre-water refraction, with the native first-vertex
split planes, bump scale and Fresnel coefficients. The serialized
`waterDesc:full:enable` Boolean selects this branch even for the Origin's raw
effect value 4; its enum name is not inferred. Up to four active 512-pixel target
pairs share a ten-capture-per-second budget per tagged asset root. Old invisible
planes release their slots; additional active planes and below-plane views use
the lit animated fallback. Source reflect-class filtering and the original
water SH shader remain unsupported. Water remains visual-only and is not added
to source collision.
`export-native-lighting.mjs` decodes all 30 dungeons' exact WDB environment
settings and zone triggers into `src/game/generated/runewakerNativeLighting.generated.ts`.
`src/game/runewakerNativeLighting.ts` resolves source zones from runtime player
coordinates; `src/scene/DungeonLighting.tsx` applies their linear ambient and
three directional colors, directions, and camera-scaled fog. Time/weather
groups default deterministically to 0/0. Missing zones retain the dungeon's
reviewed presentation profile (including Grafu's entrance). The browser supplies
Rune's unoccluded SH constant-band energy as ambient fill (4/17) and uses the
remaining 13/17 in Three.js directional lighting. Angular diffuse response and
PBR specular remain browser adaptations, not the complete original SH/specular
shader. Standard shadows follow the player's footing and High shadows follow
the camera; WoW retains its existing presentation path.
Build all water-bearing chunks, or restrict water to the exact coordinates in
an existing ground manifest whose WDB hash matches:
```powershell
node scripts/runewaker-pipeline/build-native-water.mjs
node scripts/runewaker-pipeline/build-native-water.mjs --ground-manifest runewaker-export-work/the-origin/native-terrain-source/terrain-native-source.json
node scripts/runewaker-pipeline/build-native-water.mjs --ground-manifest runewaker-export-work/the-origin/native-terrain-source/terrain-native-source.json --audit-cache-root runewaker-export-work/the-origin
```
The builder writes `native-water-visual.glb`, `conversion-report.json`, and a
per-descriptor archive of the source DDS frames and lossless PNG carriers under
`runewaker-export-work/<slug>/native-water-source` by default. Use `--recipe`,
`--source-root`, and `--wdb-report` to select its local recipe and source
inputs; `--output-root` must remain inside the active project workspace.
The optional `--audit-cache-root` writes exact, hash-verified aliases named from
each GLB texture/variant into `raw/textures` and `prepared/textures` under that
root, allowing the quality audit to resolve water DDS and PNG source pixels.
Recipes may opt into pipeline integration with
`source.nativeWater.kind: "runewaker-wdb-water-layer"`. This mode requires
`source.nativeTerrain` and a full WDB assembly. The environment builder always
passes the selected native-terrain manifest to the water builder, so water
chunks follow the same reviewed source-ground selection. It merges the result
as a visual-only WDB record; no water geometry is added to source collision or
navigation.
Three reviewed primary-only recipes use `source.primaryNativeCollision` to
replace imported collision with an options-aware query of the exact primary ROS
plus source-coordinate support geometry. The reusable candidate producer hashes
the current recipe, import metadata, ROS/WDB sources, placement reports, and
native extractor; it invokes the native collision query in
`respect-options` mode or accepts a query cache only when its provenance
sidecar matches those inputs. It regenerates support boxes from the recipe and
resolved primary WDB transform rather than reading a previously transformed
GLB. The proof file names the full collision candidate (which the build splits
to the configured per-GLB triangle limit), the native-core/overlapping-support
Recast input, and the baked navigation candidate and report.
Run the candidate producer directly for one of its configured recipes with:
```powershell
node scripts/runewaker-pipeline/build-native-core-support-candidate.mjs aeternal-circle --respect-options
```
Use `--stage-only` to write only the source-verified collision inputs and proof
before Recast, or `--output-root=runewaker-export-work/<slug>/<new-directory>`
to select a fresh artifact directory under that dungeon's work folder. A second
run consumes staged inputs only after rechecking their source and GLB hashes.
The Aeternal entry-support omission is independently ray-checked against the
current option-enabled native collision query each run. Remote support pads
remain separate navigation components; when present, the report declares
`navigationComponentPolicy: "all-components"` without inventing links.
`recipes/the-origin.json` keeps the Lua-authored spawn `[828,263,963]` and
direction `343` as source provenance. The reviewed runtime entrance instead
uses source path graph 1026 node 854, projected to the recovered ground and
navigation. Current native collision selection honors serialized collision
options and Trekker's water/foliage exclusion mask: 865,100 eligible triangles
across 20 collision chunks. The current Recast/Detour artifact contains
103,582 triangles and 24,612 polygons. In that graph, node 854 reaches Life Leecher;
Life Leecher and node 854 both terminate in partial routes to Holy Tree
Falynum. That early collision-graph review covered only two short entrance walking
legs (2.85 m, with all three samples grounded). A later final v5 material review
walked 19/19 legs along the connected Life route (48.56 m, all 42 samples grounded).
Neither certifies a full clear or an approach route to Falynum; evidence and
scope are in `docs/ROM_ENVIRONMENT_REVIEW_2026-10-06.md`.
Rebuild with:
```powershell
npm run runewaker:build:all -- --only the-origin
npm run runewaker:register:all
```
The base Demon Stronghold recipe opts into
`rom-demon-stronghold-derived-support-entrance-floor-02` through
`lib/rom-derived-support-styling-file.mjs`. Exact ROS, DDS, and converted PNG
hashes gate the native entrance-floor texture applied to its 186 generated
support boxes. Added UV1 preserves every existing geometry accessor and uses
the native floor scale/phase at the entrance; vertical box faces retain full
UV rank. This is explicitly a derived support fallback, not native floor
recovery throughout the dungeon. Demon Stronghold 125 has no such opt-in.
`scripts/playtest-rom-visual-routes.cjs --dist=<build-directory>` can freeze an
isolated production build for ordinary UI entry and walking QA when the shared
`dist` directory is locked. Its runtime telemetry is read-only.
Native ROS material alpha provenance is captured by
`native/runewaker_model_exporter.cpp` and applied by
`blender/native_material_alpha.py` through `blender/convert-runewaker.py`. The
export report records material/lighting types, diffuse source-channel identity,
and native alpha-test/blend parameters; the builder stamps the exact ROS
`sourceResourceSha256` before Blender conversion. The converter only applies
those flags when source hash, model, material index and diffuse texture identity
all match. Normal translucent alpha maps to glTF `BLEND`; alpha-tested images
with cutout pixels map to `MASK` with the native threshold, while fully opaque
images stay `OPAQUE`. Exact native `SRCALPHA:ONE` materials are recorded as
additive and use glTF `BLEND`; the runtime applies additive blending only when
that conversion provenance is complete. Unknown or incomplete native modes stay
unsupported. Exact native prelit materials receive `KHR_materials_unlit` before
the optimizer runs, so deduplication keeps them separate from standard-lit
materials sharing the same map. Resource-cache validation includes exporter,
converter and alpha-policy hashes so a semantics change forces re-conversion.
`lib/native-alpha-cache-validation.mjs` also requires the current ROS hash,
complete native alpha parameters and diffuse-channel joins, and identical raw
and prepared material reports. A matching old cache stamp alone is insufficient.
The prelit annotation removes Blender's unused `KHR_materials_specular` metadata
from those same verified materials, avoiding an incompatible glTF extension pair.
Protect alpha matching with
`python scripts/runewaker-pipeline/blender/test_native_material_alpha.py`, the
pre-optimizer semantics with
`node --test scripts/runewaker-pipeline/lib/native-material-semantics.test.mjs`,
and runtime behavior with
`npm test -- --run src/scene/dungeonMaterialAudit.test.ts`.
The environment builder runs terrain extraction and GLB generation as part of
the Sand Vortex recipe. Rebuild and register that package with:
```powershell
npm run runewaker:build:all -- --only sand-vortex
npm run runewaker:register:all
```
The extraction and terrain GLB stages are also available directly for inspection:
```powershell
node scripts/runewaker-pipeline/sand-vortex/extract-native-terrain.mjs
node scripts/runewaker-pipeline/sand-vortex/build-native-terrain.mjs
```
`src/scene/runewakerTerrainMaterial.ts` owns native splat-layer blending in the
browser. `src/game/runewakerDungeonEnvironment.ts`, applied through
`src/game/dungeonRegistry.ts`, owns the runtime lighting profiles; these lights
remain approximations because static imported GLBs contain no authored light
records.
`scripts/playtest-rom-visual-routes.cjs` checks normal offline entry, ordinary
keyboard movement, footing, and Standard/High graphics options using read-only
production telemetry. Pass explicit RoM slugs with `--dungeon=...`, optional
waypoints with `--routes=<json>`, or `--entry-only` for graphics-only captures.
It freezes the production distribution for each run and requires the geometry
loading state to settle before collecting evidence. These checks do not certify
combat, every route, or a full dungeon clear.
Repackage existing converted visuals without rebuilding collision or navigation:
```powershell
node scripts/runewaker-pipeline/reoptimize-environment-visuals.mjs
node scripts/runewaker-pipeline/reoptimize-environment-visuals.mjs --apply-staged
npm run runewaker:register:all
```
The first command stages every configured environment; the second validates all
staged hashes before replacing shipped visuals and their metadata. Forsaken
Abbey's authored visual descriptor must also match its updated import metadata.
For repeatable rendered review, start Vite on port 4207, run
`node scripts/playtest-rom-environments.cjs`, then
`node scripts/runewaker-pipeline/make-environment-review-sheets.mjs`. The preview
uses the shipped GLBs/KTX2, production material preparation and lighting
palettes at entrance, middle/final boss and reverse entrance viewpoints. Captures
and results live in `artifacts/playtest/rom-environment-quality`. This isolated
asset review does not simulate movement, collisions or combat; supplement it
with ordinary in-dungeon checks for runtime changes.
### Configured package workflow
The generalized batch now packages and registers all 30 configured RuneWaker
instances (Forsaken Abbey plus 29 generated definitions). The normal workflow is
fully local and does not use SQL:
```powershell
npm run runewaker:prepare:all
npm run runewaker:build:all
npm run runewaker:register:all
```
`runewaker:prepare:all` consumes the portable forensic JSON already under
`runewaker-export-work`. `runewaker:build:all` is resumable and writes a result
after every dungeon. `runewaker:register:all` exposes only instances whose full
validation report is green.
Creature animation policy is audited separately:
npm run runewaker:audit:animations
The audit opens every referenced creature GLB, checks its glTF header and
animation table, resolves every spawn and entity in all 30 runtime definitions,
and exercises the available native or procedural state paths. Pasper's Shrine
is the compact direct-mesh reference package. The full batch now uses original
GR2 skeletons and sampled RAS clips for validated direct actors, while runtime
paperdoll containers are assembled into exact image-specific actors from a
portable appearance snapshot. Genuinely unsupported pose-only or triangle-free
displays remain explicit exceptions rather than silently claiming native motion.
See [ORIGINAL_ANIMATION_IMPORT.md](./ORIGINAL_ANIMATION_IMPORT.md) for the
reproducible conversion and rollout process, and
[RUNEWAKER_ANIMATION_AUDIT.md](./RUNEWAKER_ANIMATION_AUDIT.md) for the package
historical baseline and current all-dungeon status.
Paperdoll appearance recovery is an explicit forensic refresh, separate from
normal builds:
~~~powershell
npm run runewaker:paperdolls:refresh
npm run runewaker:build:all -- --phase actors,population --force
~~~
The refresh restores `ObjectEdit.bak` under a temporary read-only database,
exports only combat-template image rows, writes the checked-in portable
`runewaker-paperdoll-appearances.json`, and drops the temporary database in
`finally`. Normal actor builds, tests, production builds, and browser play use
that JSON and packaged GLBs with SQL stopped. Appearance provenance preserves
component names and color layers; any unresolved composite-mask color bake is
reported explicitly in the actor manifest.
## Portable populations, source spells, and objective routes
NPC spell evidence is exported from the preserved read-only RuneWaker client
catalogs into a checked-in portable snapshot:
~~~powershell
npm run runewaker:bosses:refresh
npm run runewaker:build:all -- --phase population --force
npm run runewaker:forsaken:population
npm run runewaker:audit:gameplay
~~~
The existing all-instances runner starts a separate Node population-builder
process for each of the 29 generalized packages. Forsaken Abbey keeps its
special pilot builder. Both builders emit ordinary TypeScript definitions and
JSON reports; the browser never opens the original client catalogs or SQL
backups.
Spell conversion is deliberately fail-closed. Only a MagicObject component
positively classified as direct HP damage becomes an executable HealerMan
attack. Buffs, healing, summons, plot hooks, and unknown effects remain
evidence-only. The portable mapping preserves source spell identity, name,
damage family, school, range, cooldown, source power fields, and source-code
formula provenance. Live damage uses a labeled HealerMan baseline adapter because
the required native ATK/MATK, DEF/MDEF, weapon, resistance, critical, level-rate,
and global-rate inputs are not packaged; it is not represented as source-exact.
`runewaker:bosses:refresh` first rebuilds that portable spell snapshot, then
statically follows each packaged boss's preserved AutoPlot/template callbacks
and writes modular `rw-<dungeon>-<entity-id>` kits to
`dungeon-pipeline/boss-mechanics.json`. Each special is an independent record
with stable ID, trigger, target, effects, and explicit circle, cone, or line
telegraph geometry. Both population builders copy those IDs into
`combat.mechanicIds`, so the same runtime loadout boundary is shared by
Runewaker and WoW encounters and can later support reviewed randomization.
Source-backed records identify the RuneWaker Lua and spell evidence they came
from. If the preserved scripts expose only encounter-progression hooks, the
importer creates a conservative playable mechanic marked
`source.kind: "healer-man-source-gap"`; it never labels that fallback as an
original RuneWaker ability. Edit or append a boss kit in the shared catalog,
then rerun the population build and gameplay audit to update an encounter.
The gameplay audit also:
- verifies every executable attack.spellId against both its source template
assignment and the portable spell catalog;
- rejects evidence-only spell IDs if they enter runtime combat data;
- requires every boss objective to resolve a modular catalog kit and validates
its source label, telegraph, timed trigger, and health trigger;
- reuses the live party-navigation graph to inspect boss approach points
projected to the retained surface within 6m;
- validates native animation families, with Rune Device's missing locomotion
documented as a stationary-device exception while its attack/activation
clips remain mandatory.
The generated
[RUNEWAKER_GAMEPLAY_CONTENT_REPORT.md](./RUNEWAKER_GAMEPLAY_CONTENT_REPORT.md)
is the current cross-dungeon content baseline. The generalized population
builder currently falls back to straight-line distance from the entrance when
ordering bosses. That fallback is labeled `healerMan-distance-derived`: an
unreachable heuristic leg is navigation/order review evidence, not a claimed
source-authored structural failure. A future explicit recipe order must include
preserved local source evidence before it can become authoritative. The builder
accepts that reviewed override only as `bossObjectiveOrder: { kind:
"source-authored", spawnIds: [...], evidence: [...] }`; it rejects missing
evidence, duplicates, or an order that does not account for every boss spawn.
The same gameplay audit also regenerates the deterministic
[RUNEWAKER_ENCOUNTER_IMPLEMENTATION_REPORT.md](./RUNEWAKER_ENCOUNTER_IMPLEMENTATION_REPORT.md)
and its exhaustive JSON companion. The ledger records all deferred source spawn
rows and direct mechanics evidence with stable IDs, source files and hashes,
fidelity, implementation status, blocker, next work, and a clearing test.
Category totals are overlapping review labels, never a claimed count of unique
mechanics. Unproven behavior remains `deferred-source-gap` instead of being
silently inferred from a name or regex match.
Run only that ledger and its pipeline tests with:
~~~powershell
npm run runewaker:audit:encounters
~~~
Run the component-level navigation review separately:
~~~powershell
npm run runewaker:audit:navigation
~~~
It writes
[RUNEWAKER_NAVIGATION_GAP_REPORT.md](./RUNEWAKER_NAVIGATION_GAP_REPORT.md),
measures every unreachable heuristic leg against all raw Recast components,
and records reviewed source evidence for support-pad environments, authored
room placements, doors, drops, and teleports. It never writes navigation links.
No automatic links are currently approved: the observed gaps either depend on
mechanics/order evidence or on modular environment assembly, so bridging them
would bypass gates or cross missing geometry.
The forensic source refresh is intentionally separate:
```powershell
npm run runewaker:refresh:all
```
It requires the isolated `HEALERMAN_RW` SQL service to be running, restores both
backups read-only under temporary names, exports all configured zones, drops the
temporary databases in `finally`, and regenerates the portable snapshots. Stop
the SQL service again before running the normal build or game.
See [INSTANCE_IMPORT_GUIDE.md](./INSTANCE_IMPORT_GUIDE.md) for provenance,
coordinate rules, special WDB cases, mechanics review, validation, and the
step-by-step process for adding future instances.