diff --git a/internal/plugin/dnd_setup.go b/internal/plugin/dnd_setup.go index 7348cf5..ad79f73 100644 --- a/internal/plugin/dnd_setup.go +++ b/internal/plugin/dnd_setup.go @@ -258,7 +258,13 @@ func (p *AdventurePlugin) dndSetupConfirm(ctx MessageContext) error { // Initial D&D level seeded from existing combat_level (v1.1 §4.1). // combat_level "freezes" thereafter — dnd_level is canonical. - advChar, _ := loadAdvCharacter(ctx.Sender) + // + // ensureCharacter (not a bare loadAdvCharacter) so the canonical + // player_meta seed row + tier-0 equipment exist for D&D-only players + // who reach !setup confirm without ever touching the legacy adventure + // path. Without this seed, loadAdvCharacter returns "sql: no rows in + // result set" on every legacy-layer command (arena, npcs, events, …). + advChar, _, _ := p.ensureCharacter(ctx.Sender) startLevel := 1 if advChar != nil { startLevel = dndLevelFromCombatLevel(advChar.CombatLevel) diff --git a/internal/plugin/wotd.go b/internal/plugin/wotd.go index be50a29..5f05319 100644 --- a/internal/plugin/wotd.go +++ b/internal/plugin/wotd.go @@ -247,8 +247,17 @@ func (p *WOTDPlugin) prefetchWord(force bool) error { if _, delErr := d.Exec(`DELETE FROM wotd_log WHERE date = ?`, today); delErr != nil { slog.Error("wotd: force delete failed", "err", delErr) } - // Also clear job-completed flags so PostWOTD will re-post - d.Exec(`DELETE FROM job_completed WHERE job_name = 'wotd' AND job_key LIKE ?`, today+"%") + // Also clear job-completed flags so PostWOTD will re-post. The + // per-room dedup keys are ":" in daily_prefetch, so + // match every room's flag for today. (Was targeting a non-existent + // job_completed/job_key table — a silent no-op that left forced + // re-posts blocked by the stale dedup row.) + if _, delErr := d.Exec( + `DELETE FROM daily_prefetch WHERE job_name = 'wotd' AND date LIKE ?`, + today+"%", + ); delErr != nil { + slog.Error("wotd: force clear dedup flags failed", "err", delErr) + } } _, err := d.Exec(