UX S3: SRD copy-edit pass — sanitize jargon + curated overrides

Plumbed through the open5e importer so regen stays safe:

- New cmd/open5e-import/desc_overrides.go holds two per-ID override
  maps (spellDescOverride, magicItemDescOverride) and a regex-driven
  cleanDesc sanitizer. Override wins outright; otherwise the SRD
  first-sentence runs through cleanDesc, which strips the phrases
  the S3 acceptance criteria forbid (saving throw[s], spell slot,
  within range, 5-foot, DC <n>, "(save DC X)" parentheticals,
  "constitution score is N", "out to a range of N feet"). A small
  post-pass repairs the orphan stubs the strippers leave behind
  (" and." trailers, "must make." after the saving-throw object
  is gone).

- gen.go (spells) + magicitems.go now call spellDescription /
  magicItemDescription instead of raw firstSentence; same hand-
  authored override pattern, same cleanDesc fallthrough.

- Override coverage: the 19 SRD-only spells that show up in
  defaultKnownSpells (call_lightning, charm_person, vicious_mockery,
  …) plus ~35 high-visibility magic items (Amulet of Health, every
  Belt of Giant Strength variant, Cloak of Displacement, etc.).
  Tone is outcome-first second-person with bite — these surface
  in the spellbook and the curio shop, so they get to be funny.

- tuned.go (R21) + magicitems.go strip "(...)" from emitted Names
  via stripNameParenthetical. Slug keeps the variant; only the
  display text loses the qualifier. Two bestiary entries
  (giant_rat_diseased, deep_gnome_svirfneblin) and stone_of_good_luck
  affected.

- Regenerated all three data files. Acceptance grep is clean:
  zero hits for any banned phrase in Description/Desc fields.

- New cmd/open5e-import/desc_overrides_test.go covers the
  sanitizer regressions, orphan-repair, name-strip, and the
  override-wins-but-fallthrough-still-sanitizes path.

Conflicts: none. S4 (magic-item UX) wanted this in first so the
new curio renderer consumes clean text — ready for it now.
This commit is contained in:
prosolis
2026-05-14 21:53:06 -07:00
parent c48e12a296
commit 1512f6cc50
8 changed files with 474 additions and 169 deletions

View File

@@ -96,7 +96,7 @@ func tuneMonster(b genStatBlock) genTunedMonster {
ability := abilityFromTraits(b.Traits)
return genTunedMonster{
ID: b.Slug,
Name: b.Name,
Name: stripNameParenthetical(b.Name),
CR: b.CR,
HP: b.HP,
AC: ac,
@@ -110,6 +110,18 @@ func tuneMonster(b genStatBlock) genTunedMonster {
}
}
// stripNameParenthetical drops a trailing "(…)" qualifier from a monster
// name so the player-facing display reads "Giant Rat" rather than "Giant Rat
// (Diseased)". The slug still carries the variant, so the engine keeps both
// records distinct — only the display text loses the qualifier.
func stripNameParenthetical(name string) string {
i := strings.IndexByte(name, '(')
if i <= 0 {
return name
}
return strings.TrimSpace(name[:i])
}
// traitAbilityRules maps SRD special-ability names onto the engine's
// MonsterAbility effects. Each rule's Match list holds lowercase substrings; a
// creature's trait matches a rule if any substring is contained in the