# Layout rules

```
data/
├── README.md                      this contract
├── tables/                        one registry per file
│   ├── skills.srd.ron             Table<SkillDef>       (18)
│   ├── weapons.srd52.ron          Table<Weapon>         (38)
│   ├── weapon_masteries.srd52.ron Table<WeaponMasteryAssignment> (36)
│   ├── armor.srd52.ron            Table<Armor>          (12 + shield)
│   ├── cr_xp.srd52.ron            Table<CrXp>           (34)
│   ├── encounter_xp_budgets.srd52.ron Table<EncounterXpBudget> (20)
│   ├── advancement.srd.ron        Table<AdvancementRow> (20)
│   ├── multiclass_spell_slots.srd.ron Table<SpellSlotRow> (20, SRD Multiclass Spellcaster table)
│   ├── damage_kinds.srd.ron       Table<VocabRow>       (13 — open vocabulary)
│   ├── schools.srd.ron            Table<VocabRow>       (8 — open vocabulary)
│   ├── creature_types.srd.ron     Table<VocabRow>       (14 — open vocabulary)
│   ├── languages.srd.ron          Table<VocabRow>       (16 — open vocabulary)
│   ├── quality_profiles.ron       Table<QualityProfile> (5 classes × 7 tiers, ours)
│   ├── alignment.ron              AlignmentRules        (moral motive weights, ours)
│   ├── material_classes.ron       Table<MaterialClass>  (5, ours — [](../docs/adr/0070-vocabularies-are-registries.md))
│   └── terrain_tags.ron           Table<TerrainTag>     (7, ours — [](../docs/adr/0070-vocabularies-are-registries.md))
├── professions/                   ours — one profession per file (17; the
│   └── {fisher,brewer,baker,farmer,miller,tanner,smith,mason,merchant,innkeeper,
│       harbor_clerk,fixer,noble,guildmaster,captain,priest,sage}.ron — canonical
│       set mirrors crates/engine/src/professions.rs
├── buildings/                     ours — one building TYPE per file (21)
│   └── {smithy,tannery,carpentry,masonry,weaver,ovens,mill,mash_house,tavern,
│       fields,dock,mine,lumber_camp,pasture,manor,guildhall,watch_house,house,
│       town_wall,shrine,tower}.ron
├── races/                         one race per file, subraces inside as variants
│   └── {dwarf,elf,halfling,human,dragonborn,gnome,half_elf,half_orc,tiefling}.srd.ron
├── classes/                       one class per file, the SRD subclass inside
│   └── {fighter,rogue,cleric,barbarian,monk,paladin,ranger,bard,druid,sorcerer,warlock,wizard}.srd52.ron  (12)
├── feats/                         OPEN collection: one feat per file
│   ├── grappler.srd.ron           SRD 5.1's ONE feat (prereq-only; riders ledgered)
│   └── {alert,savage_attacker,boon_of_truesight}.srd52.ron  the SRD 5.2.1 feats
│                                   with engine substrate ; the rest is a mod surface
├── spells/                        OPEN collection: one spell per file
│   └── {fire_bolt,magic_missile,fireball,cure_wounds,…}.srd*.ron (83: 79 SRD 5.1,
│                                   4 SRD 5.2.1),
│                                   every one scoped to the class list the book
│                                   gives it — ; ALL of them, since the
│                                   one non-SRD file left for the private
│                                   book-mod tree at . No shipped spell
│                                   pulls: Effect::Pull's lock builds its own)
├── magic_items/                   OPEN collection: one magic item per file
│   └── {plus_one_longsword,plus_one_chain_shirt,ring_of_protection,
│       cloak_of_protection,wand_of_magic_missiles}.srd.ron  (5: the SRD starter set)
│       ring_of_resistance_{acid,…,thunder}.srd.ron  (10: the SRD 5.1 Ring of Resistance gem table, one row per line)
├── conditions/                    OPEN collection: one condition per file
│   └── {blinded,charmed,deafened,frightened,grappled,…}.srd52.ron  (14)
│                                   unconditional ConditionComponent reads plus
│                                   contextual ConditionFact entries
│       {ability_guided_weapon,innately_sorcerous,raging,reckless,
│        walking_speed_flight}.ron  (5 Original class-helper conditions)
├── traps/                          OPEN collection: one trap per file
│   └── {poison_needle,poison_darts,fire_breathing_statue}.srd.ron  (3: the SRD
│                                   "Traps" device samples; the container trap is
│                                   the poison needle — the rest a mod surface)
├── diseases/                       OPEN collection: one disease per file
│   └── {sewer_plague,sight_rot,cackle_fever}.srd.ron  (3: the SRD "Diseases"
│                                   sample diseases — a contraction save, an
│                                   incubation, an effect (exhaustion/condition/
│                                   check penalty), and a long-rest recovery save
│                                   track; the rest a mod surface)
├── creatures/                     OPEN collection: one entity per file,
│   ├── humanoids/                 in stable taxonomic folders
│   │   └── {commoner,guard,bandit}.srd.ron
│   ├── beasts/wolf ; undead/{skeleton,zombie} ; dragons/black_dragon_wyrmling
│   ├── fiends/dretch ; elementals/magma_mephit ; giants/ogre ; oozes/gray_ooze
│   ├── constructs/animated_armor ; monstrosities/worg ; fey/satyr
│   └── celestials/pegasus ; aberrations/gibbering_mouther ; plants/awakened_shrub
│                                   (the  bestiary — one per type)
├── goods/                         ours (unsuffixed) — one material/tool per file
│   └── iron_ore, iron_ingot, coal, timber, hide, leather, cotton, cloth,
│       sinew, bedroll, bed, smiths_tools, leatherworkers_tools,
│       carpenters_tools, weavers_tools  (.ron, source: Original)
├── expected/
│   └── npc_blocks.srd.ron         verification corpus (see Derivations)
├── art/                           runtime pictures a row names by path (see below)
│   └── furniture/                 one per furnishing good's `art:` field
└── names/                         ours (unsuffixed) — per-race name tables
```

- **Art is named by path, and a mod layers it.** A furnishing good's `art:`
 names a picture inside `art/`, e.g. `"furniture/trestle-table.webp"`. It is
 drawn from above facing north (back edge at the top, `width_cells` across,
 `length_cells` down, 128 px per cell) and the board rotates it for the other
 facings. A mod's own `art/` is searched before this one, so a mod replaces a
 picture by shipping the same path or adds one under a new path. A path that
 resolves nowhere fails the load. Every picture carries a provenance header
 that says whether it is an AI placeholder or who made it and under what
 licence; stamp one with `cargo xtask art stamp`
 (
).

- **Registries vs. entities.** Compact row collections (the SRD's
 tables) live as ONE registry file per set under `tables/`. Collections
 that will someday hold tens of thousands of entries (creatures, and
 later items, spells,...) grow one-file-per-entity inside stable
 taxonomic folders — `creatures/humanoids/` plus the thirteen monster
 folders (`beasts/`, `undead/`, `dragons/`, `fiends/`, `elementals/`,
 `giants/`, `oozes/`, `constructs/`, `monstrosities/`, `fey/`,
 `celestials/`, `aberrations/`, `plants/`) the bestiary filled,
 one exemplar per non-humanoid type. `magic_items/` is the
 README's own "later items" made real — an entity collection, not a
 `tables/` registry, because the SRD's Magic Items chapter grows to
 thousands and a mod adds one as a file. Both kinds are OPEN:
 mods add weapons, armor, races, and creatures (the
 moddable-data amendment — data loads at boot).
 A creature's optional `doors` field is a closed set of `Encounter`, `Battle`,
 `Form`, and `Summon`; when absent it defaults to all four. Author at least one
 distinct door to narrow which builders and catalogues may enumerate the body.
 A swarm (any creature with `swarm_member_size`) never opens `Form`, whatever
 its list says: a form takes one body, and a swarm is many.
- **Suffix + source provenance.** A provenance suffix marks files whose
 content derives from an SRD, and names WHICH one: `.srd.ron` for SRD 5.1,
 `.srd52.ron` for SRD 5.2.1.
 Every file's top-level value also carries a required `source` field
 (`Srd51`, `Srd52`, or `Original` in the base), and the two must agree — `data_lock`'s
 `the_suffix_and_the_source_field_agree` fails the build otherwise, so the
 path can be trusted without opening the file. Book mods use their matching
 `Phb2024`, `Dmg2024`, `Mm2024`, `Tce`, or `Xge` source; the loader refuses a
 missing source, a book source in base data, or a book/namespace mismatch.
 That is what makes
 `*.srd*.ron` auditable against the repository's `ATTRIBUTION.md`, which
 states the two grants separately. Files without a suffix (`names/`,
 `goods/`) are ours.
- **id equals filename.** For one-entity-per-file collections, the file
 stem IS the entity's `id`: `half_elf.srd.ron` ↔ `id: "half_elf"`,
 `guard.srd.ron` ↔ `id: "guard"`. The future parse-everything lock test
 asserts this. Ids are snake_case throughout — chosen over kebab
 because the pre-existing `names/` files (`half_orc.ron`) already use
 it, and the race key contract (below) shares filename ids with them.
- **No organization by tunables.** Directories follow stable taxonomy
 ONLY — never CR, level, cost, or any other property that balancing may
 move. By-CR (or any) access is a load-time index. This is
 derive-don't-store applied to layout.
