# 7DTD Cluster — Canonical-Compatible New World Provisioning (RUNBOOK)
# Validated 2026-06-13. Tooling: this dir. Canonical: ~/nimcanon/canonical_final/{block,item}mappings.nim

## WHERE TO RUN (prerequisites — read first)
Run on **figaro** (`<user>@<agent-host>`) as user **refuge**. Requires `~/nimcanon/{tool,canonical_final,remap}` present (the `.nim` parser, the canonical, the cached native table). The repo `remap_7dt.py` hardcodes `sys.path.insert(0,'/home/refuge/nimcanon/tool')` and imports `nimtool` — it will **NOT** run on the Windows dev box or kaiten. (The in-container copy invoked automatically by the entrypoint is the self-contained `remap_7dt.vendored.py` — a different file.)

Saves live in a **docker volume**, not a host path — `$W` below is only reachable by mounting the volume. Run file ops inside a throwaway container, e.g.:
```sh
CL=/home/refuge/panel/data/7dtdcluster/cl_37e3a7f72cdc
VOL=panel-<inst>-saves          # e.g. panel-cluster-seed-test-saves
docker run --rm -v $VOL:/sv -v $CL:/cl debian:12-slim sh -c '
  W="/sv/.local/share/7DaysToDie/Saves/<World>/<GameName>"; <ops on "$W/decoration.7dt" etc.>'
```
STOP/START **only via the panel** (agent-owned; sends SIGTERM→tini→7DTD clean shutdown, which flushes the native `.nim`). A `docker kill`/`docker stop` would NOT flush and can corrupt the capture.

## CORRECTED ROOT CAUSE
7DTD V2.6(b14) auto-assigns block ids at config-load. The cluster's CURRENT runtime
(RefugeBot v1.2.39) puts the tree-decoration band at native ids 21895+, while the
season10-anchored CANONICAL puts the same trees at 24141+ (season10's world was baked
PRE-RefugeBot-rebuild). At world GENESIS the engine bakes decoration.7dt / multiblocks.7dt
BY NUMERIC BLOCK ID using native runtime ids. The entrypoint guard then stamps the
canonical .nim over the world's .nim every boot (so inventory/.ttp decode uniformly →
clean transfers). MISMATCH: native-baked deco (21895) read against stamped canonical
(24141) → null Block → DecoManager.TryAddToOccupiedMap NRE → world load hangs → never
GameStartDone. season10/creative load clean only because their deco was baked when the
runtime == canonical (pre-rebuild).

## KEY FACTS
- .nim: u32 ver=1, u32 count, recs[u16 id, u16 flag(block=0/item=1), u8 namelen, name]. Parser: ~/nimcanon/tool/nimtool.py
- decoration.7dt / multiblocks.7dt: u8 ver=6, u32 count, count*17B recs; block id = u16@+12 & 0x7FFF; high bit + bytes +14/+16 = rotation/placement (PRESERVE).
- Engine PRESERVES loaded deco ids on save; only writes native ids at GENERATION. So a canon-remapped decoration.7dt stays canon across reboots → STABLE.
- The cluster runtime native table is IDENTICAL across all instances (insane==pvp deco band 33/33). One captured native table is authoritative cluster-wide: ~/nimcanon/remap/cluster_native_deco.nim
- Remapper: remap_7dt.py  (apply|analyze|decodecheck). Self-verifies byte-safety + 100% canon resolution.

## PROVISION A NEW CANONICAL-COMPATIBLE WORLD (do this on a FRESH/0-region world)
CL=/home/refuge/panel/data/7dtdcluster/cl_37e3a7f72cdc ; VOL=panel-<inst>-saves ; W="<World>/<GameName>"
1. Gen the world (set seed, recreate/start). It bakes a NATIVE decoration.7dt.
2. CAPTURE the world's native table:
   a. Stop the instance (panel Stop — NOT `docker stop`).
   b. **First BACK UP the canonical** (`cp $CL/canonical/*.nim ~/canon-backup/`), THEN move the originals aside so the guard skips the stamp:
      `mv $CL/canonical/*.nim $CL/canon_test_aside/`
      ⚠️ **The canonical is the SHARED stamp source for EVERY cluster member.** While it is moved aside, do **NOT** boot any other member — it would stamp nothing and could append/diverge (cluster-wide inventory risk). Keep this window short; restore in step 5 and confirm by `sha256sum` before starting anything else.
   c. printf '\x01\x00\x00\x00\x00\x00\x00\x00' > "$W/blockmappings.nim" ; same for itemmappings.nim
   d. Start instance → loads clean on native → engine writes the world's native .nim (covers its deco blocks). Graceful-stop to flush.
   e. Copy out "$W/blockmappings.nim" as <native.nim>.
3. REMAP: python3 remap_7dt.py apply <native.nim> ~/nimcanon/canonical_final/blockmappings.nim "$W/decoration.7dt" /tmp/deco.canon.7dt
   (repeat for multiblocks.7dt if present). Require: "byte-diff outside id field: 0" and "ids unresolved in canon: 0".
4. Backup native (cp decoration.7dt decoration.7dt.native-bak) then apply the remapped file; chown 1000:1000.
5. mv $CL/canon_test_aside/*.nim $CL/canonical/                # restore the stamp source
6. Start instance → guard stamps canon → loads canon-remapped deco → GameStartDone, NRE=0, on canon.
7. VERIFY: decoration.7dt id band = 24xxx ; GameStartDone ; NRE=0 ; .nim stamped 38626/2719 at boot.

## REPAIR AN ALREADY-STUCK WORLD (canon stamped, native deco, NRE) — same as above from step 2.

## CAVEATS
- Region/*.7rg voxel ids + Player/*.ttp item ids are NOT remapped (codecs unsolved). Do the remap on a FRESH 0-region world BEFORE exploration. Existing 87 shared .ttp are fine (written in canon by season10/creative).
- Deco block ids must be < 32768 (15-bit field); the tree-deco band is far under.
- PERMANENT fix (removes the per-world remap step): pin block ids explicitly in a high-priority modlet so the runtime native table == canonical, OR freeze the RefugeBot build that season10 was baked under. Until then each new world needs this one-time remap.
