Small joys: Codex audit #2 fixes (route resolution, noindex, sense/tone, exclude-current re-pick)

- Admin joy item route moved to /api/admin/joys/{kind}/items/{item_id} so the
  /add and /repick verbs resolve to their own routes instead of 422-ing as a
  non-int item id (the launch blocker). Frontend mutate URL updated to match.
- Re-pick now excludes the currently-shown item: the endpoint reads today's
  daily pool_id and passes it as `avoid`, so "Re-pick today" yields a different
  item. Added `avoid` to pick_daily/_candidates across wotd/quote/onthisday.
- WOTD sense selection: the LLM now proposes word + intended part of speech, and
  _lookup prefers that sense (fixes "serene" returning the archaic noun).
- On This Day tone prompt tightened to favor genuinely uplifting events and
  exclude merely procedural/political-administrative ones.
- Caddy @hidden now also noindexes /word /quote /onthisday /admin (+ .html).
- Regression tests: add/repick resolve (401 not 422), add/feature/block/delete,
  re-pick excludes current; WOTD pos-preference + proposal parsing units.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-22 20:19:02 -04:00
parent 3bde6534e9
commit 84b1fb514f
9 changed files with 217 additions and 51 deletions
+22 -1
View File
@@ -24,7 +24,7 @@ class FakeClient:
@pytest.fixture
def conn(tmp_path, monkeypatch):
monkeypatch.setenv("GOODNEWS_WOTD_AUDIO", str(tmp_path / "audio"))
monkeypatch.setattr(wotd, "_lookup", lambda w: FAKE_DICT.get(w)) # no dictionary network
monkeypatch.setattr(wotd, "_lookup", lambda w, prefer_pos=None: FAKE_DICT.get(w)) # no dictionary network
monkeypatch.setattr(wotd, "_cache_audio", lambda url, word: f"{word}.mp3" if url else None)
c = connect(":memory:"); init_db(c)
yield c
@@ -64,3 +64,24 @@ def test_get_today_never_empty(conn):
def test_run_daily_bootstraps(conn):
r = wotd.run_daily(conn, client=FakeClient())
assert r["pool"] == 2 and r["picked"] in ("serene", "dawn")
def test_lookup_prefers_intended_pos(monkeypatch):
"""When the LLM says 'serene' as an adjective, _lookup must pick the adjective sense,
not an earlier archaic noun sense the dictionary lists first."""
entry = {"word": "serene", "phonetics": [], "meanings": [
{"partOfSpeech": "noun", "definitions": [{"definition": "Serenity; clearness; calmness."}]},
{"partOfSpeech": "adjective", "definitions": [{"definition": "Calm, peaceful, untroubled."}]},
]}
monkeypatch.setattr(wotd.daily, "http_json", lambda url, timeout=20: [entry])
assert wotd._lookup("serene", "adjective")["part_of_speech"] == "adjective"
assert wotd._lookup("serene", "adjective")["definition"] == "Calm, peaceful, untroubled."
assert wotd._lookup("serene")["part_of_speech"] == "noun" # no preference → first usable sense
def test_propose_words_accepts_dicts_and_strings():
class C:
def chat_text(self, m):
return '{"words": [{"word": "Serene", "pos": "Adjective"}, "dawn", {"word": ""}]}'
out = wotd._propose_words(C(), 3)
assert out == [{"word": "serene", "pos": "adjective"}, {"word": "dawn", "pos": None}]