Skip to content

feat(sessions): unread indicator for scheduled-run deliveries#572

Merged
philmerrell merged 1 commit into
developfrom
feature/sessions-unread-scheduled-runs
Jul 6, 2026
Merged

feat(sessions): unread indicator for scheduled-run deliveries#572
philmerrell merged 1 commit into
developfrom
feature/sessions-unread-scheduled-runs

Conversation

@philmerrell

Copy link
Copy Markdown
Contributor

Surfaces scheduled-run results the user hasn't seen — the sidebar shows an unread dot on a session a scheduled (unattended) run delivered, until they open it. Natural UX follow-on to the scheduled-runs engine.

Behavior

  • Backendset_session_unread / mark_session_read (sessions/metadata.py): a targeted single-attribute UpdateExpression on the row's current SK (GSI-resolved), concurrent-safe with the title/activity writes, preview-session-guarded, best-effort. run_agent_headless marks the session unread only on a completed run with trigger == "schedule" — attended "Run now" and failed/consent-blocked runs never set the dot.
  • APIPOST /sessions/{id}/read clears the durable flag when the user opens the session (idempotent, ownership-enforced via the GSI lookup, 204).
  • SPA — durable server-persisted unread on SessionMetadata (survives reload, reaches other devices) ORed with ChatStateService's ephemeral in-tab unread for interactive background completions; session-list renders the dot.

Verification

  • Backend: 108 tests pass (test_harness_runner, test_sessions, test_sessions_metadata).
  • Frontend: 25 specs pass (session-list, chat-state.service) via ng test.

Depends on the is_preview_session leaf from #567 (merged).

🤖 Generated with Claude Code

A scheduled (unattended) run delivers a session the user wasn't watching.
Surface it: the sidebar shows an unread dot until they open it.

- sessions/metadata.py: set_session_unread / mark_session_read — a targeted
  single-attribute UpdateExpression on the row's current SK (GSI-resolved),
  concurrent-safe with the title/activity writes; preview-session guarded;
  best-effort (never raises).
- harness/runner.py: mark the delivered session unread only on a *completed*
  run with trigger == "schedule" — attended "Run now" and failed/consent-
  blocked runs never set the dot (the user is present / there's nothing to
  read).
- app_api POST /sessions/{id}/read: clears the durable flag when the user
  opens the session; idempotent, ownership-enforced via the GSI lookup.
- SPA: durable server-persisted unread on SessionMetadata (survives reload,
  reaches other devices) ORed with ChatStateService's ephemeral in-tab
  unread for interactive background completions; session-list renders the dot.

Backend 108 + frontend 25 tests pass.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@philmerrell philmerrell merged commit 68502ee into develop Jul 6, 2026
4 checks passed
@philmerrell philmerrell deleted the feature/sessions-unread-scheduled-runs branch July 6, 2026 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant