Make the Supply run from the plan revision Push to Calendar pushed
CI / ci (push) Successful in 5m6s
CI / ci (pull_request) Successful in 5m40s

A plan edit landing between a successful Push and the Generate that
followed it made the Supply run from the newer plan while the push answer
reported supply_run generated, so the list could hold a dinner Calendar
never showed (MQ-133-01).

Push now returns the revision it pushed, and the push hook calls
shopping.GeneratePushed, which checks inside its transaction that the
week's plan is still at that revision (week_plans.revision, as the draft
path does) and otherwise fails with ErrPlanChanged, leaving the Supply run
as it was. The push answer then reports supply_run failed with error
plan_changed (retryable: push again), logged as a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 04:59:16 -04:00
co-authored by Claude Opus 5.5
parent 6aa5113488
commit a31bbce1dc
7 changed files with 168 additions and 53 deletions
+7 -7
View File
@@ -84,20 +84,20 @@ type pushDay struct {
//
// A successful Push is the household confirming the week's plan, which is
// what the week's Supply run (Feature 17) is made from; the returned plan
// is the one pushed.
func (s *Service) Push(ctx context.Context, weekStart store.LocalDate) (Plan, error) {
// is the one pushed, and revision is its revision as pushed, so the Supply
// run can be made from that plan and no later edit of it.
func (s *Service) Push(ctx context.Context, weekStart store.LocalDate) (p Plan, revision int64, err error) {
if _, err := household.WeekDays(weekStart); err != nil {
return Plan{}, &InvalidWeekError{Value: weekStart.String()}
return Plan{}, 0, &InvalidWeekError{Value: weekStart.String()}
}
planID, revision, days, err := s.pushDays(ctx, weekStart)
if err != nil {
return Plan{}, err
return Plan{}, 0, err
}
events := make([]gcal.Event, len(days))
for i, d := range days {
events[i] = d.event
}
var p Plan
record := func() error {
return s.st.WithTx(ctx, func(tx *sql.Tx) error {
q := db.New(tx)
@@ -133,9 +133,9 @@ func (s *Service) Push(ctx context.Context, weekStart store.LocalDate) (Plan, er
})
}
if err := s.cal.PushEvents(ctx, events, record); err != nil {
return Plan{}, fmt.Errorf("plan: push %s to Calendar: %w", weekStart, err)
return Plan{}, 0, fmt.Errorf("plan: push %s to Calendar: %w", weekStart, err)
}
return p, nil
return p, revision, nil
}
// pushDays reads, in one read transaction, the plan of the week starting