Files
dwroller/BESTIARY_SANITIZATION_PROGRESS.md

128 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Bestiary Sanitization — Progress Report
_Last updated: 2026-07-02 (session in progress)_
## Why this exists
The extracted bestiary was badly corrupted: distinct creatures shared mis-aligned
statblocks (e.g. Civilian / Servo-Skull / Imperial Agent all got the Hive Tyrant's
line — T78 / W120), and several NPCs stored **Strength/Toughness bonuses** (single
digits) where the characteristic should be. This report tracks the repair.
## Effective data source (important)
- Runtime reads **`public/deathwatch-bestiary-extracted.json`** (34 entries).
`loadBestiaryData()` tries a MariaDB `bestiary` table first, but **that table does
not exist**, so it falls back to this JSON. Fixing the JSON fixes the app.
- `database/deathwatch-bestiary-extracted.json` is a **stale 24-entry subset**, not
used at runtime. (Left mostly alone; safe to regenerate from public later.)
- Sources of truth for stats: the rulebook PDFs in `database/rules/`
(`CR.pdf` = Core Rulebook, `MoX.pdf` = Mark of the Xenos), read with `pdftotext`
(raw mode linearizes statblocks; `-layout -f P -l P` per page pairs name→profile).
Plus `database/remote-extract/all_deathwatch_statblocks.json` (5 NPCs).
## DONE ✅
### Roller code fixes (src/components/DeathwatchRoller.jsx, SkillRoller.jsx)
- GM "Roll as" any player/enemy; players added to Target/defender list.
- Fate now loads for the acting-as player (`fateSubject`).
- Player self-load reads lower-case chars + `{total,current}` wounds (was broken).
- Enemy 0/again wounds coerced robustly (strings, 0, missing → usable tracker).
- `/api/bestiary/enemies` now returns the **full** bestiary (filter relaxed) and
`transformBestiaryEntry` coerces wounds + honours `stats.toughnessBonus`.
- Fire-mode +10/+20, jam 96/94/100, Advanced-untrained skill gate, Dodge/Parry
burst negation = DoS (earlier in session). Full CRA build compiles.
### Bestiary data
- `scripts/sanitize-bestiary-canonical.js` written and **run** against
`public/…json`. Backups written (`*.pre-sanitize.<ts>.json`).
- Result on the 34 public entries:
- **PDF-verified (9):** Chaos Space Marine, Chaos Heretic, Gun Drone, Hive Tyrant,
Hormagaunt, Tau Commander, Tau Fire Warrior, Tau Stealth Suit, Tyranid Warrior.
- **Canonical-fill, review (13):** Termagant, Renegade Militia, Imperial Guardsman,
Daemon Prince, Ork Nob, Battle/Monotask/Industrial Servitor, Servo-Skull,
Civilian, Chapter Serf, Imperial Agent, Imperial Guard Field/Senior Officer.
- **OCR-restored (5):** caele Rylus Darkscourge, Father Marius, Infected Auran
warrior, Feynir Surbryte, Arcus Dyre.
- **Structural-only, review (8):** the TEP named NPCs (Agamorr, Skarjaw, Vex,
Genestealer Patriarch, Zephon, Chaos Cultist Champion, Prince-Prefect Allewis,
Alexei Drahj — S/T bonus→char fixed).
- Each touched entry records `stats.statSource` ('pdf'|'canon'|'ocr'|'structural')
and `stats.needsReview`, and an effective `stats.toughnessBonus` (includes
Unnatural Toughness, e.g. Tyranid Warrior 10, Hive Tyrant 15, Genestealer 8).
## PDF-verified statblocks (authoritative, WS BS S T Ag Int Per WP Fel | W | armour)
```
Chaos Space Marine 50 50 65 45 40 35 40 43 17 | 29 | Power Armour H8/A8/B10/L8 CR363
Tyranid Warrior 55 30 60 50 44 20 35 50 | 48 | Reinforced Chitin All8 CR370
Hive Tyrant 78 33 60 53 45 45 49 70 | 120 | Bonded Exoskeleton All10 CR371
Hormagaunt 45 20 35 30 55 10 40 30 | 9 | Chitinous Carapace All3 CR372
Tau Fire Warrior 25 35 30 30 25 30 20 30 30 | 12 | Fire Warrior Armour All6 CR369
Tau Stealth Suit 30 42 42 47 38 30 40 40 40 | 30 | XV15 H8/B8/A7/L7 CR368
Gun Drone 20 25 20 40 40 15 25 20 10 | 15 | (machine) CR368
Chaos Heretic 35 35 35 35 30 20 30 35 20 | 10 | Flak All4 CR361
Tau Commander 41 57 50 57 48 45 45 50 50 | 90 | XV-8 Crisis Suit All9 MoX
Genestealer 55 0 45 40 50 20 40 40 10 | 16 | Reinforced Chitin All4 MoX44
Apostle Bellephrades75 60 66 45 48 48 48 75 30 | 80 | Armour of Chaos All12 CR363
```
## DONE ✅ (continued)
- **Sanitizer now also ADDS missing canonical creatures** and mirrors public→DB
copy. Public + database JSON are both **38 entries** and identical. New entries
added: **Genestealer, Ork Nob, Apostle Bellephrades, Industrial Servitor**.
- **Bestiary UI redesign** (`src/components/BestiaryTab.jsx`): colour-coded stat
chips (WS/BS/S/T/Ag/Int/Per/WP/Fel each with its own colour), tier bar + badge
(Troops/Elite/Master by wounds), Wounds + TB pills, `verified`/`review` badges
from `statSource`/`needsReview`, and smart armour rendering (`{all:8}`→"All 8",
location objects → "Head 8 · Body 10 · …"). Build compiles clean.
- **Long-entry cleanup**: `scripts/sanitize-bestiary-canonical.js` now strips raw
`pageText`/`snippet` extraction text, removes copied root-level spillover from
canonical entries, and trims OCR/structural `skills`/`talents`/`traits`/`gear`
at section boundaries. Public + database JSON remain identical, 38 entries,
with no rendered text field over 300 chars.
- **40k RPG Tools index staging**: `scripts/import-40krpgtools-bestiary-index.js`
downloads the public master bestiary index from `https://www.40krpgtools.com/bestiary/`
and writes Deathwatch-only missing references to
`database/remote-extract/40krpgtools-bestiary-index.json`. This is an index
only (name/type/affiliation/book/page/source URL), not statblocks, so it does
not write directly into the live bestiary.
- **DB-backed live bestiary**: `database/mariadb.js` now creates the `bestiary`
table and exposes replace/upsert helpers. `scripts/import-bestiary-json-to-db.js`
imports the sanitized active bestiary into MariaDB. Current DB import: **84
rows**, **57 PDF-verified**, all 84 are roller-ready because `/api/bestiary/enemies`
reads the same `bestiary` table before falling back to JSON.
- **40k RPG Tools hydration**: `scripts/hydrate-bestiary-from-40krpgtools.js`
uses the staged index as a page map and local PDFs as the stat source. First
Mark of the Xenos pass added **46** compact statblocks to the active bestiary.
The remaining index-only rows stay out of the live combat table until a real
profile and wounds can be extracted.
- **First Founding pass**: hydrated **4** additional compact statblocks from the
local `FF.pdf`: The Headsman of Cellebos, Blight-Master Ussax, Atum Sum, and
Warsmith Koros. Re-imported MariaDB afterward; current live DB count is **88**
bestiary rows. Verified these four through `/api/bestiary/enemies` with valid
Wounds/TB/armour output for the combat roller.
## TODO / NEXT (in priority order)
1. **More NEW creatures**: the PDF scan found ~40 more clean profiles whose names
need pairing via per-page `-layout` extraction (Ork Boy, Broadside XV-88, Kroot
Carnivore, Bloodletters/greater daemons, more Tyranids). Extend the `CANON` table
in `scripts/sanitize-bestiary-canonical.js` (auto-adds if missing).
The 40k RPG Tools staging file currently has **344 Deathwatch index rows not
already in the active bestiary**; use it to prioritize local PDF page extraction.
Do not import index-only rows into the live `bestiary` table because live
bestiary rows automatically appear in the combat roller.
2. Re-verify canonical-fill entries against PDFs (Termagant, Ork Nob, Daemon Prince,
servitors, officers) to promote them from `needsReview` to `pdf` (verified).
3. **ComfyUI (192.168.1.96)** image generation for players/beasts — user asked;
feasible. Plan: backend `POST /api/imagegen` proxy → ComfyUI `/prompt` API with a
stored workflow JSON, poll `/history/{id}`, save PNG under `/avatars` or a new
`/beast-images`; UI "Generate portrait" buttons on PlayerTab + BestiaryTab.
NOT STARTED (needs the ComfyUI workflow JSON + confirmation the box is reachable).
## How to continue
- Re-run sanitizer: `node scripts/sanitize-bestiary-canonical.js` (idempotent;
writes fresh backups each run).
- Extract a creature page: `pdftotext -layout -f <page> -l <page> database/rules/CR.pdf -`
(or MoX.pdf). Profile = the 9-number row; Wounds/Armour/Weapons lines follow.
- The DoS/roller conventions and the jsdom-segfault test workarounds are in
project memory (`~/.claude/projects/-nas-git-dwroller/memory/`).
```
```