API client, auth bootstrap and job polling #42

Member

Task: 21051318-15ae-4d0e-a9a1-2143f87de759 API client, auth bootstrap and job polling hook.

What changed: web/src/api adds apiFetch (same-origin, CSRF from cached /me, typed ApiError), 401 redirect, csrf refresh-and-retry once, and a not-in-this-household screen for other 403s. App bootstrap loads /me behind a Skeleton. useJob polls /api/v1/jobs/{id} with 500 ms to 2 s backoff and stops on terminal state or unmount.

Done-condition: Vitest with stubbed fetch covers CSRF, 401, csrf retry, 403 screen, and useJob. Developer reports lint:colors, typecheck, test, and build passed.

Base: feature/64e5bb19-c9a2-4c6a-8f0c-aceae43fb732-frontend-foundation at c899f07b1f.

Task: 21051318-15ae-4d0e-a9a1-2143f87de759 API client, auth bootstrap and job polling hook. What changed: web/src/api adds apiFetch (same-origin, CSRF from cached /me, typed ApiError), 401 redirect, csrf refresh-and-retry once, and a not-in-this-household screen for other 403s. App bootstrap loads /me behind a Skeleton. useJob polls /api/v1/jobs/{id} with 500 ms to 2 s backoff and stops on terminal state or unmount. Done-condition: Vitest with stubbed fetch covers CSRF, 401, csrf retry, 403 screen, and useJob. Developer reports lint:colors, typecheck, test, and build passed. Base: feature/64e5bb19-c9a2-4c6a-8f0c-aceae43fb732-frontend-foundation at c899f07b1fae3daea68ba41e14134693a3f38004.
dev_agent added 1 commit 2026-10-04 08:34:04 -04:00
Add API client, /me bootstrap and useJob polling hook
Independent review Codex gpt-6-sol high: CHANGES_REQUIRED (1 medium)
CI / ci (push) Successful in 1m34s
CI / ci (pull_request) Successful in 1m32s
913c1e5337
web/src/api provides createApiClient().apiFetch: same-origin JSON with
the cached /api/v1/me CSRF token on non-GET requests and a typed
ApiError from the server's error body. A 401 navigates to
/auth/login?return={path}; a csrf 403 refreshes /me once and retries
once; any other 403 shows the "not in this household" screen.

App loads /me before the routes, showing the Skeleton meanwhile. The
QueryClient retries only ApiErrors the server marks retryable. useJob
polls GET /api/v1/jobs/{id} backing off 500 ms to 2 s, exposing status,
partial result and error until a terminal status, and stops on unmount.

Maestro task 21051318-15ae-4d0e-a9a1-2143f87de759.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review_agent left a comment
Member

Independent review — Codex gpt-6-sol, reasoning high

Verdict: CHANGES_REQUIRED
Reviewed SHA: 913c1e5337f77410f6c61e8bdbeb57adb3f5f588

{
  "verdict": "CHANGES_REQUIRED",
  "reviewed_sha": "913c1e5337f77410f6c61e8bdbeb57adb3f5f588",
  "summary": "CSRF handling, auth bootstrap, and terminal job polling match the requested behavior. The color lint passed. Web dependencies are absent, so typecheck, tests, and build were not run.",
  "findings": [
    {
      "id": "job-poll-stops-before-terminal",
      "severity": "medium",
      "location": "web/src/api/useJob.ts:57",
      "failure_case": "If a job is running and one poll fails, polling stops permanently. The hook can remain at status running without ever observing the job's terminal state.",
      "evidence": "The catch block records the request error but schedules no further poll. The test at useJob.test.tsx:88 explicitly expects polling to stop after a failed request.",
      "suggested_correction": "Expose the request error and continue polling with bounded backoff until the job reaches succeeded or failed, the job ID changes, or the hook unmounts. Add a test where a failed poll is followed by a terminal response."
    }
  ]
}

Posted unaltered by review_agent. This is transport, not a second review.

## Independent review — Codex `gpt-6-sol`, reasoning high Verdict: **CHANGES_REQUIRED** Reviewed SHA: `913c1e5337f77410f6c61e8bdbeb57adb3f5f588` ```json { "verdict": "CHANGES_REQUIRED", "reviewed_sha": "913c1e5337f77410f6c61e8bdbeb57adb3f5f588", "summary": "CSRF handling, auth bootstrap, and terminal job polling match the requested behavior. The color lint passed. Web dependencies are absent, so typecheck, tests, and build were not run.", "findings": [ { "id": "job-poll-stops-before-terminal", "severity": "medium", "location": "web/src/api/useJob.ts:57", "failure_case": "If a job is running and one poll fails, polling stops permanently. The hook can remain at status running without ever observing the job's terminal state.", "evidence": "The catch block records the request error but schedules no further poll. The test at useJob.test.tsx:88 explicitly expects polling to stop after a failed request.", "suggested_correction": "Expose the request error and continue polling with bounded backoff until the job reaches succeeded or failed, the job ID changes, or the hook unmounts. Add a test where a failed poll is followed by a terminal response." } ] } ``` --- Posted unaltered by `review_agent`. This is transport, not a second review.
dev_agent added 1 commit 2026-10-04 08:37:47 -04:00
Keep polling a job after a failed poll
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (push) Successful in 1m31s
CI / ci (pull_request) Successful in 1m31s
690e1056a6
A failed GET /api/v1/jobs/{id} no longer ends polling. useJob exposes the
request's error, keeps the last known status and result, and schedules the
next poll on the same 500 ms to 2 s backoff. Polling stops only at a
terminal status, a changed job id or unmount.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review_agent left a comment
Member

Independent review — Codex gpt-6-sol, reasoning high

Verdict: APPROVED
Reviewed SHA: 690e1056a6cf2d8a2a9ef7c2b7f8be02c3388541

{
  "verdict": "APPROVED",
  "reviewed_sha": "690e1056a6cf2d8a2a9ef7c2b7f8be02c3388541",
  "summary": "No findings in the reviewed diff. The prior failed-poll issue is fixed: polling continues after a request error and stops on a terminal job state or unmount. Color lint passed. Typecheck, tests, and build could not be run because web/node_modules is absent.",
  "findings": []
}

Posted unaltered by review_agent. This is transport, not a second review.

## Independent review — Codex `gpt-6-sol`, reasoning high Verdict: **APPROVED** Reviewed SHA: `690e1056a6cf2d8a2a9ef7c2b7f8be02c3388541` ```json { "verdict": "APPROVED", "reviewed_sha": "690e1056a6cf2d8a2a9ef7c2b7f8be02c3388541", "summary": "No findings in the reviewed diff. The prior failed-poll issue is fixed: polling continues after a request error and stops on a terminal job state or unmount. Color lint passed. Typecheck, tests, and build could not be run because web/node_modules is absent.", "findings": [] } ``` --- Posted unaltered by `review_agent`. This is transport, not a second review.
approver_agent merged commit 048d5dd71a into feature/64e5bb19-c9a2-4c6a-8f0c-aceae43fb732-frontend-foundation 2026-10-04 08:46:41 -04:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Maniacs_Mansion/MealQuest#42