Menu

#289 feat(classifier): boost today's declared plan as Tier-1 candidates

closed
nobody
None
2026-06-16
2026-06-15
Anonymous
No

Originally created by: adityaharishch

Stacked on [#288] (base = feat/daily-plan-today-tasks). Retarget to main once [#288] merges.

What

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.

How

  • _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.
  • Prompt★ 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.

Boost, never a filter

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).

Verified against the live DB

  • _local_day('2026-06-15T14:01:26+00:00')2026-06-15
  • confirmed day → ['KAN-230','KAN-109']; unconfirmed day → []
  • candidate ordering: the 2 focus tickets lead (marked), other 21 follow — all 23 present
  • no-focus path sets no is_today_focus key → prompt header byte-identical to before (fully backward compatible)
  • rendered prompt shows the header note + ★ TODAY'S FOCUS tag

🤖 Generated with Claude Code

Related

Tickets: #288
Tickets: #289
Tickets: #292

Discussion

  • Anonymous

    Anonymous - 2026-06-15

    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_day timezone handling is correct. app_sessions.started_at is RFC3339 UTC with offset (chrono Utc::now().to_rfc3339()…+00:00; column documented -- ISO8601 UTC in 001_initial.sql). So datetime.fromisoformat(s).astimezone() parses an aware datetime and converts UTC→local properly — it is not the naive-datetime astimezone() trap (which would misread a UTC string as local). And the except ValueError fallback returns "" → no boost, so even a future format change degrades safely rather than misattributing a day.
    • Dict-style row access is valid. con.row_factory = sqlite3.Row is set (run_task_linker_mlx.py:885), so meta["skipped"] / meta["confirmed_at"] / r["task_key"] work.

    Other checks

    • Both classify paths wired (_classify_one and _classify_one_logged) — no path silently skips the boost. 👍
    • Stable sort key (0, position) vs (1, 0) floats focus tasks in declared order while non-focus retain original order; order[...] is only dereferenced when is_today_focus is true. Safe.
    • OperationalError catch makes this no-op on a pre-#288 DB. Good — the daily_plan tables ship in [#288] (this PR is stacked on feat/daily-plan-today-tasks), so the dependency is real but handled.

    Minor (optional)

    • Redundant per-session plan queries_fetch_plan_focus runs 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 by plan_date would save the repeated daily_plan_meta/daily_plan lookups on large /classify_sessions calls. Low priority.

    🤖 Assisted review via Claude Code.

     

    Related

    Tickets: #288

  • Anonymous

    Anonymous - 2026-06-15

    Originally posted by: adityaharishch

    Thanks — agree there were no correctness issues. On the one optional note (memoizing _fetch_plan_focus by plan_date across 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_one for 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: #289

  • Anonymous

    Anonymous - 2026-06-16

    Ticket changed by: adityaharishch

    • status: open --> closed
     

Log in to post a comment.