Step 2 keyed each refusal by the dinner's name, so a second add of the
same name still in flight replaced the first add's refusal when it was
refused too. Each attempt now keys its refusal uniquely; trying a change
again once it has been refused still clears that earlier refusal.
A refused removal was put back at the index it had in the list as it
stood when it was removed, so refusing two overlapping removals of A and
B restored B, A, C until a reread corrected it. A removal now only marks
its Regular in the cache and the list hides it; a refusal clears the
mark, so the Regular returns to its own place whatever else changed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Step 2 read the refusal from the mutation hooks, which only report their
latest change: an add refused while another add was in flight was rolled
back with no message, and the same for removals. Each change now records
its own refusal, keyed by the change, so it stays shown whatever the
other changes in flight do; trying the same change again replaces it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Next: notifications counted optimistic chips, so a household with two
saved Regulars could tap a third and leave step 2 before the server
refused it. Next now waits until no add is pending and three Regulars
have server ids.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While household_settings.onboarding_completed_at is null, OnboardingGate
sends every app route to /onboarding, a full screen outside the shell.
The household settings parser now reads onboarding_completed_at from the
existing GET /api/v1/settings/household.
Step 1 welcomes the household and explains Regulars, Side quests and the
Quest log. Step 2 follows mock 1h: progress pills, the add pill with its
grape "+" (Enter also adds), Regulars chips with remove, dashed Common
picks, and "Next: notifications" enabled at 3 Regulars. Adds and removes
go through new dinners API hooks (POST /api/v1/dinners, DELETE
/api/v1/dinners/{id}) optimistically, rolled back if the server refuses.
Step 3 is a placeholder until its task lands.
Maestro task 5a43f813-c940-4f79-a2be-027644ae9e6c.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>