Ship-audit P0/P1 sweep on open5e: prose, combat math, UX hygiene

P0 — actual bugs:
- eldritch_blast: SRD-imported "Whatever" placeholder leaked to players;
  overlay added in dnd_spells_data.go.
- Battle Master disarming_attack + parry: math.Max on multiplicative
  DamageReduct was a no-op vs the 1.0 default. Switched to *= and added
  regression tests covering the stacking case too.
- Extended TestSpellDescriptionsAreJargonFree to catch "Whatever",
  trailing ellipses, mid-word truncation, and empty-size phrases. This
  surfaced 4 more genuinely-broken SRD descriptions (find_familiar,
  clairvoyance, glyph_of_warding, teleportation_circle); all now
  overlayed in dnd_spells_data.go.

P1 — UX hygiene:
- Setup completion now nudges new casters toward !spells/!cast.
- Magic-item attunement vocab unified to "bond" everywhere user-facing;
  renamed the Treasures sheet section to avoid clashing with the bond
  vocab.
- Ambient DM footers stripped of "Threat +N" / "Supplies −N SU" hidden-
  meter leakage; verb-form footers instead.
- !expedition status defaults to a days-left + threat-label summary;
  raw SU / threat-out-of-100 / zone-stack / roll-modifier moved behind
  `!expedition status --debug`.
- !zone taunt/compliment help text dropped the "(mood −10)" / "(mood +5)"
  numerics that turned the hidden TwinBee-mood mechanic into a min/max
  knob.
- TwinBee pronoun pass: switched she/her to singular they on the two
  surfaces I touched plus achievements.bj_beat_twinbee.

P1 — correctness/scale:
- adventure_shop curio purchase now guards the euro.Debit bool return
  before inventory grant + pot cut; the GetBalance preflight isn't
  enough since a concurrent blackjack/lottery debit can slip the balance
  across BLACKJACK_DEBT_LIMIT between read and write.
- equipMagicItem reordered: remove inventory item BEFORE equip, with a
  best-effort rollback if equip fails. The prior order left a dup
  window if the inventory delete tripped on a transient DB error.
- magicItemsByRarityCache promoted to sync.Once — concurrent cold-start
  loot rolls otherwise raced on the lazy assignment.

Stale-audit verifications (no code change needed):
- light / druidcraft / water_walk overlays already exist and win the
  SRD merge — the broken raw text never reaches players.
- bootstrapPhase5BHPRefresh is already wired at adventure.go:228.

Deferred:
- combatantsForSession per-turn 6-load DB chatter (perf P1-A): touches
  the hot combat path; needs its own test pass before shipping. Tracked
  in memory at project_combat_session_cache_deferred.

go vet clean; go test -race ./... green (229s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-15 14:43:11 -07:00
parent ba84d38979
commit f424300d87
12 changed files with 190 additions and 50 deletions

View File

@@ -413,6 +413,24 @@ func buildSpellList() []SpellDefinition {
{ID: "druidcraft", Name: "Druidcraft", Level: 0, School: "transmutation",
Classes: []DnDClass{ClassDruid}, Effect: EffectUtility, CastTime: CastAction, AOE: true,
Description: "Whisper to the spirits and they whisper back — usually about tomorrow's weather, sometimes a tiny gust, sometimes a sapling. Mostly harmless theatre."},
{ID: "eldritch_blast", Name: "Eldritch Blast", Level: 0, School: "evocation",
Classes: []DnDClass{ClassWarlock}, Effect: EffectDamageAttack, CastTime: CastAction,
AttackRoll: true, DamageDice: "1d10", DamageType: "force",
Description: "A lance of pact-fed force punches out of your palm and into a target. Your patron's idea of a polite greeting."},
{ID: "find_familiar", Name: "Find Familiar", Level: 1, School: "conjuration",
Classes: []DnDClass{ClassMage}, Effect: EffectBuffSelf, CastTime: CastRitual,
Description: "Call up a small spirit-companion in animal shape — cat, raven, frog, the usual. It scouts, fetches, and judges you silently."},
{ID: "clairvoyance", Name: "Clairvoyance", Level: 3, School: "divination",
Classes: []DnDClass{ClassMage, ClassCleric, ClassBard, ClassSorcerer, ClassWarlock},
Effect: EffectBuffSelf, CastTime: CastAction, Concentration: true, MaterialCost: 100,
Description: "Plant an invisible eye-or-ear in a place you know or can describe, and watch the world through it from afar."},
{ID: "glyph_of_warding", Name: "Glyph of Warding", Level: 3, School: "abjuration",
Classes: []DnDClass{ClassMage, ClassCleric, ClassBard}, Effect: EffectDamageSave, CastTime: CastAction,
SaveStat: "DEX", DamageDice: "5d8", DamageType: "thunder", MaterialCost: 200, AOE: true,
Description: "Etch a hidden rune on a surface or in a sealed object. Whoever trips the trigger eats the blast — not you."},
{ID: "teleportation_circle", Name: "Teleportation Circle", Level: 5, School: "conjuration",
Classes: []DnDClass{ClassMage, ClassBard, ClassSorcerer}, Effect: EffectUtility, CastTime: CastAction,
Description: "Trace a sigil-circle on the ground that links to a far-off permanent circle you know. Step through and arrive there."},
{ID: "light", Name: "Light", Level: 0, School: "evocation",
Classes: []DnDClass{ClassMage, ClassCleric, ClassBard, ClassSorcerer}, Effect: EffectUtility, CastTime: CastAction, AOE: true,
Description: "Tap an object and it glows like a friendly torch. Easy to carry, harder to lose."},