Guard plan drafts against swaps and keep confirm on single-flight
CI / ci (push) Successful in 3m20s
CI / ci (pull_request) Successful in 3m6s

Return the draft job id as jobId, as the plan API contract specifies.

Add a week_plans revision (migration 0013) that every swap and stored
draft raises. A draft_week job reads the revision before draft_week runs
and stores its week only while the plan still has it; a plan edited
while the AI ran is left as it is and the job fails plan_changed, so a
draft never erases the household's swap.

A confirmed draft now joins only a confirmed queued or running job, so a
job asked for without confirm can no longer fail it with
confirm_required after the plan was synced.

Test simultaneous drafts, a swap during a draft, a confirmed draft while
an unconfirmed one runs, impossible calendar dates and start_by across
the end of daylight saving time.

Maestro task ea48e650-d510-49cc-8485-0f07174ee731.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 06:32:51 -04:00
co-authored by Claude Opus 5.5
parent 75d6ad4e19
commit 7e6e49f6b1
12 changed files with 352 additions and 45 deletions
+6 -4
View File
@@ -69,7 +69,8 @@ type Querier interface {
// Returns sql.ErrNoRows until the row exists.
GetAISettings(ctx context.Context) (AiSetting, error)
// The id of the job of kind queued or running for the week starting
// week_start. Returns sql.ErrNoRows when there is none.
// week_start, one whose payload has confirm when confirmed is 1. Returns
// sql.ErrNoRows when there is none.
GetActiveDraftJobID(ctx context.Context, arg GetActiveDraftJobIDParams) (string, error)
// The batch still pending or running, oldest first. Returns sql.ErrNoRows
// when there is none.
@@ -148,8 +149,8 @@ type Querier interface {
// The ids of the dinners planned in the week starting week_start, Monday
// first.
ListWeekPlanDinnerIDs(ctx context.Context, weekStart string) ([]sql.NullString, error)
// Records an edit of plan id: a synced plan becomes changed, any other
// keeps its status.
// Records an edit of plan id, raising its revision: a synced plan becomes
// changed, any other keeps its status.
MarkWeekPlanEdited(ctx context.Context, arg MarkWeekPlanEditedParams) error
// Moves a dinner still suggested to status (quest_log or archived),
// recording updated_by; a dinner no longer suggested is left as it is
@@ -160,7 +161,8 @@ type Querier interface {
// Plans dinner_id on date of plan_id, keeping the day's calendar event id
// when the day exists.
PutPlanDay(ctx context.Context, arg PutPlanDayParams) error
// Records a new draft over plan id: its status and note.
// Records a new draft over plan id: its status and note, raising its
// revision.
RedraftWeekPlan(ctx context.Context, arg RedraftWeekPlanParams) error
// An unknown id returns sql.ErrNoRows.
SetDinnerFavorite(ctx context.Context, arg SetDinnerFavoriteParams) (Dinner, error)