Recover Tomorrow plans after missed midnight and interrupted promotion #1154

Closed
opened 2026-08-19 23:18:56 +00:00 by rockachopa · 0 comments
Member

Problem

Tomorrow promotion currently requires plan_date === localDate() and generates a fresh random promotion ID for each attempt. A phone that is offline/asleep across midnight or receives a lost response can strand the saved plan. The server also accepts promotion before the planned date.

User flow

A saved Tomorrow plan promotes when the phone reaches or returns after its local target date. Retries use one deterministic plan identity, and the server rejects early promotion using the stored IANA timezone without mutating Today. Lifecycle checks run at the next local midnight, on foreground, and on reconnect without polling.

Acceptance

  • Overdue plans promote after an offline/app-closed gap.
  • A lost response retries with the same promotion ID and returns the existing receipt exactly once.
  • Early server requests return 409 tomorrow_not_due and preserve both plans.
  • A foreground app checks once at local midnight; online/visibility recovery checks are single-flight.
  • Existing stale-Today conflict behavior remains intact.
  • Focused behavioral tests and full suite pass.

Evidence / non-duplication

frontend/tomorrow-plan.js only promotes on exact date and creates a random ID per call; src/today_store.py has receipt storage but no due-date guard. Historical title review (579 issues), open issues, open PRs, releases, and recent commits found only closed #1152 for initial Tomorrow planning, not missed-midnight/lost-response recovery.

## Problem Tomorrow promotion currently requires `plan_date === localDate()` and generates a fresh random promotion ID for each attempt. A phone that is offline/asleep across midnight or receives a lost response can strand the saved plan. The server also accepts promotion before the planned date. ## User flow A saved Tomorrow plan promotes when the phone reaches or returns after its local target date. Retries use one deterministic plan identity, and the server rejects early promotion using the stored IANA timezone without mutating Today. Lifecycle checks run at the next local midnight, on foreground, and on reconnect without polling. ## Acceptance - Overdue plans promote after an offline/app-closed gap. - A lost response retries with the same promotion ID and returns the existing receipt exactly once. - Early server requests return `409 tomorrow_not_due` and preserve both plans. - A foreground app checks once at local midnight; online/visibility recovery checks are single-flight. - Existing stale-Today conflict behavior remains intact. - Focused behavioral tests and full suite pass. ## Evidence / non-duplication `frontend/tomorrow-plan.js` only promotes on exact date and creates a random ID per call; `src/today_store.py` has receipt storage but no due-date guard. Historical title review (579 issues), open issues, open PRs, releases, and recent commits found only closed #1152 for initial Tomorrow planning, not missed-midnight/lost-response recovery.
timmy was assigned by rockachopa 2026-08-19 23:18:56 +00:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: stackchain/stackchain-dashboard#1154
No description provided.