Originally created by: adityaharishch
Stacked on [#288] (base = feat/daily-plan-today-tasks). Retarget to main once [#288] merges.
Closes the loop on the Plan page: when a developer confirms their daily plan, those tickets become the leading candidates when classifying that day's sessions.
_local_day() — maps a session's UTC started_at to the dev's local calendar day, matching daily_plan.plan_date (stamped from the dashboard's local date). So a session is matched to the plan the dev actually declared for that day — backfilled / cross-midnight sessions use their own day's plan, not "now"._fetch_plan_focus() — ordered task_keys the dev confirmed for the day. Empty (→ no boost) when the day is unconfirmed, skipped, has no rows, or the DB predates migration 041 (OperationalError guard)._fetch_pm_tasks(focus_keys) — tags matched candidates is_today_focus and floats them to the top in the dev's declared order.★ TODAY'S FOCUS marker on those rows + a header note: prefer a ★ ticket when the session plausibly matches, but only if the evidence fits — never force a match.Every other candidate still flows through unchanged, so recall is untouched. An empty/skipped plan behaves exactly as today. A focus key that was excluded by curation simply has no effect (we never resurrect a filtered-out ticket).
_local_day('2026-06-15T14:01:26+00:00') → 2026-06-15['KAN-230','KAN-109']; unconfirmed day → []is_today_focus key → prompt header byte-identical to before (fully backward compatible)★ TODAY'S FOCUS tag🤖 Generated with Claude Code
Originally posted by: Akarsh-Hegde
🔍 Code review — boost today's declared plan as Tier-1 candidates
High-effort pass, every risk verified against source. Clean PR — no correctness bugs found. The "boost, never filter" design holds: recall is preserved (every candidate still listed), and every degradation path (unconfirmed/skipped day, no plan rows, pre-migration-041 DB) safely yields no boost.
Verified (the two things that could have broken this)
_local_daytimezone handling is correct.app_sessions.started_atis RFC3339 UTC with offset (chrono Utc::now().to_rfc3339()→…+00:00; column documented-- ISO8601 UTCin001_initial.sql). Sodatetime.fromisoformat(s).astimezone()parses an aware datetime and converts UTC→local properly — it is not the naive-datetimeastimezone()trap (which would misread a UTC string as local). And theexcept ValueErrorfallback returns""→ no boost, so even a future format change degrades safely rather than misattributing a day.con.row_factory = sqlite3.Rowis set (run_task_linker_mlx.py:885), someta["skipped"]/meta["confirmed_at"]/r["task_key"]work.Other checks
_classify_oneand_classify_one_logged) — no path silently skips the boost. 👍(0, position)vs(1, 0)floats focus tasks in declared order while non-focus retain original order;order[...]is only dereferenced whenis_today_focusis true. Safe.OperationalErrorcatch makes this no-op on a pre-#288 DB. Good — the daily_plan tables ship in [#288] (this PR is stacked onfeat/daily-plan-today-tasks), so the dependency is real but handled.Minor (optional)
_fetch_plan_focusruns 2 queries per session classified. In a batch, sessions usually share the same local day, so the result is identical across most of the batch. Memoizing byplan_datewould save the repeateddaily_plan_meta/daily_planlookups on large/classify_sessionscalls. Low priority.🤖 Assisted review via Claude Code.
Related
Tickets:
#288Originally posted by: adityaharishch
Thanks — agree there were no correctness issues. On the one optional note (memoizing
_fetch_plan_focusbyplan_dateacross a batch): declining for now. A process-lifetime cache would risk serving a stale plan after a mid-day edit, and a per-request memo needs plumbing a cache through_classify_onefor a 2-query saving on a tiny table. Marked low-priority and the staleness risk isn't worth it. Leaving [#289] as-is.Related
Tickets:
#289Ticket changed by: adityaharishch