Surface replenish failures, follow the active batch, scope deck keys, keep three deck depths
Fixes the Feature 13 review findings on the Discover deck (Maestro task 4fc551f0-3c11-4c15-b638-f2c08a28eb29): - F13-01: a batch failure (start, poll or job) is shown with its Retry whatever the deck has, so a replenish that fails while cards remain is no longer silent until the deck runs out. - F13-02: GET /api/v1/suggestions/deck reports the batch pending or running (active_batch, read in the deck's snapshot), and a decision that calls for a replenish returns the job of the batch it started or joined. The page follows a newly reported active batch, so a reopened page or a second session shows skeleton cards while the batch runs instead of "All caught up". - F13-03: ← / → leave the deck alone while it is inert behind a modal (the Quest log sheet or its confirmation). - F13-04: a one- or two-card deck keeps all three depths: skeleton cards stand in for the missing ones while a batch finds more Side quests, blank stack-edge cards while none is coming. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,10 +10,6 @@ import (
|
||||
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/suggest"
|
||||
)
|
||||
|
||||
type deck struct {
|
||||
Suggestions []suggest.Suggestion `json:"suggestions"`
|
||||
}
|
||||
|
||||
// postSuggestionBatch starts a manual suggestion batch and answers 202 with
|
||||
// its batch_id and the job_id that GET /jobs/{id} reports on, without
|
||||
// waiting for the job. When a batch is already pending or running it
|
||||
@@ -30,15 +26,15 @@ func postSuggestionBatch(logger *slog.Logger, svc *suggest.Service) http.Handler
|
||||
}
|
||||
|
||||
// getSuggestionDeck answers GET /suggestions/deck with the pending
|
||||
// suggestions, oldest first.
|
||||
// suggestions, oldest first, and the batch pending or running, or null.
|
||||
func getSuggestionDeck(logger *slog.Logger, svc *suggest.Service) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
list, err := svc.Deck(r.Context())
|
||||
d, err := svc.Deck(r.Context())
|
||||
if err != nil {
|
||||
writeSuggestionError(w, r, logger, "list suggestion deck", err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, r, logger, http.StatusOK, deck{Suggestions: list})
|
||||
writeJSON(w, r, logger, http.StatusOK, d)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,8 +148,44 @@ func TestSuggestionDecisions(t *testing.T) {
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("decline = %d: %s", rec.Code, rec.Body)
|
||||
}
|
||||
if id, _ := body["replenish_job_id"].(string); id == "" {
|
||||
t.Errorf("decline leaving 4 = %v, want a replenish_job_id", body)
|
||||
replenish, _ := body["replenish_job_id"].(string)
|
||||
if replenish == "" {
|
||||
t.Fatalf("decline leaving 4 = %v, want a replenish_job_id", body)
|
||||
}
|
||||
|
||||
// A fourth decision joins the batch already pending and reports its job.
|
||||
rec, body = callDinners(t, h, http.MethodPost, suggestionsPath+"/"+ids[3]+"/accept", "")
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("accept = %d: %s", rec.Code, rec.Body)
|
||||
}
|
||||
if body["replenish_job_id"] != replenish {
|
||||
t.Errorf("accept leaving 3 = %v, want replenish_job_id %s", body, replenish)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuggestionDeckActiveBatch(t *testing.T) {
|
||||
t.Parallel()
|
||||
h, _, _ := newSuggestionsRouter(t, "Pho")
|
||||
|
||||
rec, body := callDinners(t, h, http.MethodGet, suggestionsPath+"/deck", "")
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("GET deck = %d: %s", rec.Code, rec.Body)
|
||||
}
|
||||
if active, ok := body["active_batch"]; !ok || active != nil {
|
||||
t.Fatalf("deck = %v, want active_batch null", body)
|
||||
}
|
||||
|
||||
rec, started := callDinners(t, h, http.MethodPost, suggestionsPath+"/batches", "")
|
||||
if rec.Code != http.StatusAccepted {
|
||||
t.Fatalf("POST batches = %d: %s", rec.Code, rec.Body)
|
||||
}
|
||||
rec, body = callDinners(t, h, http.MethodGet, suggestionsPath+"/deck", "")
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("GET deck = %d: %s", rec.Code, rec.Body)
|
||||
}
|
||||
active, _ := body["active_batch"].(map[string]any)
|
||||
if active == nil || active["batch_id"] != started["batch_id"] || active["job_id"] != started["job_id"] || active["status"] != "pending" {
|
||||
t.Errorf("deck active_batch = %v, want the started batch %v", body["active_batch"], started)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user