feat(rules): encode SRD spell components for all 108 registry spells

- Every data/spells/*.json now carries a "components" field with the
  V/S/M/F/DF tokens from its KB Components line (material/focus
  descriptions dropped; M/DF and F/DF alternatives kept verbatim).
- 107/108 encoded. Create Alcool (data/spells/create_alcool.json) is
  left without the field: it is a homebrew cantrip (level 0) with no KB
  entry - the closest real spell, Enhance Water (Inner Sea Gods, V, S),
  is already a separate registry entry.
- summon_monster_i/ii map to the KB's numeric files (summon-monster-1/2);
  hidden_diplomacy maps to its KB name Egorian Diplomacy (same spell,
  Spymaster's Handbook rename): V, S, M.
- tests/test_spell_failure.py: the placeholder asserting the registry was
  not yet encoded is replaced by an encoded-state smoke test (all spells
  but Create Alcool declare components; five spot-checks against the SRD
  stat blocks). Golden transcripts unchanged: the component gates still
  need deafened/ASF conditions no golden combat has.
This commit is contained in:
2026-09-20 14:21:15 +02:00
parent 1f8f068dd1
commit 91666d84b9
108 changed files with 123 additions and 4 deletions
+16 -4
View File
@@ -331,9 +331,21 @@ def test_lich_is_arcane_oni_is_not() -> None:
assert oni.armor_spell_failure == 0
def test_registry_spells_have_no_components_yet() -> None:
"""The full component encoding is a follow-up: no shipped spell
declares components, so no golden combat can roll a failure."""
def test_registry_spells_declare_kb_components() -> None:
"""Every shipped spell encodes its KB Components line (V/S/M/F/DF
tokens, material/focus descriptions dropped) except Create Alcool,
whose SRD entry is not in the KB yet."""
registry = load_spell_registry(DATA_DIR / "spells")
assert registry
assert all(spell.components == frozenset() for spell in registry.values())
for name, spell in registry.items():
if name == "Create Alcool":
assert spell.components == frozenset()
continue
assert spell.components, name
# spot-checks against the SRD stat blocks
assert registry["Acid Arrow"].components == frozenset({"V", "S", "M", "F"})
assert registry["Bless"].components == frozenset({"V", "S", "DF"})
assert registry["Bladed Dash"].components == frozenset({"V"})
# slash alternatives (M/DF, F/DF) expand to both tokens
assert registry["Alarm"].components == frozenset({"V", "S", "F", "DF"})
assert registry["Bear's Endurance"].components == frozenset({"V", "S", "M", "DF"})