Prep prose (services/journal_prep.py):
- Emit explicit "WEATHER: none available — do NOT mention weather"
absent-marker so a small model can't invent partly-cloudy/temperature
prose when both configured locations have empty addresses.
- Replace negative-only system rule with positive-anchored guidance
forbidding weather/temp/precip mentions unless a numeric WEATHER
section is present; also bans echoing parenthetical labels verbatim.
- Reword overdue header to "(past their due date, still open — backlog,
not today's work)" and render lines as "was due <date>, N day(s)
overdue" with correct singular/plural. Supersedes the wording noted
in Fable task #159.
- Deterministic fabricated-weather reconciler: low-false-positive regex
detects fabricated weather phrasing; on trip with an empty section,
regenerate once with a corrective. Persistent fabrication logs ERROR
rather than mangling prose.
Journal route (routes/journal.py):
- Override message_count with len(messages) in _day_payload. The chat
path already does this; the journal path was hitting the
Conversation.to_dict() fallback to 0 because messages aren't
eager-loaded on that instance.
Tests:
- tests/test_journal_message_count.py — pins the model-level trap and
the override contract (3 cases).
- tests/test_journal_prep_hardening.py — 11 cases covering the
fabricated-weather reconciler and absent-marker rendering.
- tests/test_journal_prep_filtering.py — updated one stale assertion.
Tracks Fable task #171.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>