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
+3 -3
View File
@@ -43,9 +43,9 @@ func getPlan(logger *slog.Logger, svc *plan.Service) http.HandlerFunc {
}
// postPlanDraft enqueues the draft of the week and answers 202 with the
// job_id that GET /jobs/{id} reports on, without waiting for the job. When
// a draft of the week is already queued or running it answers 202 with
// that job instead.
// jobId that GET /jobs/{id} reports on, without waiting for the job. When
// a draft of the week is already queued or running, confirmed if this one
// is, it answers 202 with that job instead.
func postPlanDraft(logger *slog.Logger, svc *plan.Service) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
week, ok := weekStartOrFail(w, r, logger)