A 6h gap meant weekend visitors could see the feed sit on the same
1pm batch through to dinner. Tightening to 2h gives roughly 12
ingests/weekend-day at a fraction of the active-window load (which
stays at 20-min cadence).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Move news_job from hourly to 3x/hour (cron 10,30,50), with a CadencePolicy
gate that throttles to active hours (07-21 UTC weekdays at 20 min), off-hours
(3 h), weekends (6 h). Keeps the daytime feed fresh without spamming RSS
sources overnight.
- Tag each headline on ingestion via DeepSeek (BATCH_SIZE=25, max_tokens=4000,
json.JSONDecoder().raw_decode + per-row regex recovery for resilient parsing).
Vocabulary: 16 tags including new EU / USA / AI / Conflict. NULL tags are
picked up automatically on the next news_job run, so back-tagging is implicit
rather than a separate migration step.
- Tag UI: pill bar above the feed with off → include → exclude cycle on click;
shift-click jumps straight to exclude. State persists in localStorage and is
injected into /api/news requests via htmx:configRequest. Per-row chips sit to
the right of the headline (new 5-column grid: age | source | title | tags |
UTC) so vertical density stays high.
- Strategic log header bug: model was hallucinating "(Updated 21:30 UTC)" in
future tense. Bumped PROMPT_VERSION 6→7, added explicit ban on time-of-day
clauses, and supply the actual current UTC time in the user prompt so the
model has no need to invent one.
Migration 0012 adds headlines.tags (JSON, nullable). Tests cover vocabulary
integrity, validation/normalisation, and the JSON-recovery parser (17 tests).
Refactored CadencePolicy.active_start_hour/active_end_hour into a tuple
of (start, end) hour pairs so additional regional windows can be added
without code changes. Default keeps EU/US-only behaviour identical.
The Asia window (00:00-08:00 UTC — Tokyo + HK + Shanghai) is included
as a commented-out tuple in the dataclass default. Uncomment one line
to enable hourly AI cadence during the Asia session as well.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two changes that together cut OpenRouter spend ~50% and give the daily
log temporal awareness.
1. CadencePolicy (app/services/cadence.py): expensive AI jobs only
fire hourly during the EU/US active window (Mon-Fri 07-21 UTC).
Off-hours weekdays throttle to every 4h; weekends to every 12h.
ai_log_job and indicator_summary_job both consult the policy before
doing real work; market/news/portfolio ingest jobs stay hourly
(cheap, no API cost). Skipped runs land in job_runs with status
'skipped' and the throttle reason in error.
2. Update mode for ai_log_job: when an earlier log exists for the
current UTC day, it's passed to the model as 'Earlier log from
today (generated HH:MM UTC)'. The system prompt grows an Update
mode section instructing the model to revise — not restart — and
anchor on what has CHANGED since the earlier draft. The TL;DR
leads with intra-day change when meaningful, the watch list evolves
rather than restarts. PROMPT_VERSION bumped to 5.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>