Pool admin: empty-pool safety net + honest removal copy (Codex audit)

Two hardening fixes from Codex's audit:
- _pick_answer falls back to the curated baseline if the live pool is empty,
  so an admin tombstoning every answer in a variant can't divide-by-zero the
  daily picker. Test added (test_picker_survives_empty_live_pool). Chosen over
  a minimum-count block: robust without refusing legitimate removals.
- Removal copy is now honest — "Removed from future puzzles (today's answer is
  already set)" — since a tombstone doesn't rewrite today's generated
  daily_puzzles row. Panel intro updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-11 19:04:49 -04:00
parent 2461584052
commit 90da4be083
3 changed files with 17 additions and 3 deletions
+4 -3
View File
@@ -76,7 +76,7 @@
async function removeWord(w) {
try {
wpPool = await delJSON('/api/admin/word/pool/' + encodeURIComponent(w));
wpMsg = `Removed “${w}. It wont appear as an answer — restore it any time below.`;
wpMsg = `Removed “${w} from future puzzles (todays answer is already set). Restore it any time below.`;
await refreshLookup();
} catch { /* ignore */ }
}
@@ -817,8 +817,9 @@
{:else if section === 'games'}
<h2>Daily Word pool</h2>
<p class="muted">Look up a word and add it to the answer pool. Only real, 5- or 6-letter
words in the guess dictionary qualify, so the daily answer is always solvable.</p>
<p class="muted">Look up a word to add or remove it from the answer pool. Only real, 5- or 6-letter
words in the guess dictionary qualify, so the daily answer is always solvable. Removals take
effect for future puzzles and can be restored any time.</p>
<div class="wp-lookup">
<input type="text" bind:value={wpWord} oninput={onWpInput} maxlength="6" autocapitalize="off"