Skip to content

fix(reauth): stop polling terminal unknown flows - #5428

Closed
luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:fix/585-reauth-poll
Closed

luvs01 wants to merge 1 commit into
lidge-jun:devfrom
luvs01:fix/585-reauth-poll

Conversation

@luvs01

@luvs01 luvs01 commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

Motivation

  • A canceled reauthentication flow could remain owned by the client and continue polling every two seconds when the management API returned a terminal 404 with code: "unknown_flow", leaving the UI in a stale pending/committing state and pausing account-pool refresh.

Description

  • In gui/src/components/use-main-device-reauth.ts the GET poll path now treats a 404 with dto.code === "unknown_flow" as terminal by stopping the poll, clearing the stored flowId, and transitioning to the existing generic failure state instead of scheduling another tick.
  • The change preserves existing retry behaviour for transient GET/DELETE failures and only short-circuits the authoritative unknown_flow terminal condition.
  • Added a focused regression test gui/tests/main-device-reauth-ownership.test.tsx that reproduces a failed cancellation followed by a 404 unknown_flow and asserts the hook stops polling and enters the failure state.
  • No user-facing copy, API surface, or authentication logic was changed.

Testing

  • bun test ./gui/tests/main-device-reauth-ownership.test.tsx: 34 tests pass.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

@coderabbitai

coderabbitai Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • UI screenshot required.

What to do

  • Add a screenshot of the UI change to the PR description.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request was already a draft. Its draft status will be preserved after every issue above is resolved.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 24 / 80

이 PR은 메인 기기 재인증(reauth) 화면에서 “취소”를 눌렀는데 서버가 잠깐 실패하고, 그다음 상태 조회(GET)에서 “그런 flow 없음”(404 + unknown_flow)이 오면 클라이언트가 그걸 끝으로 받아들이지 못하고 2초마다 계속 물어보던 버그를 고칩니다. 지금은 DELETE 쪽과 같이 폴링을 멈추고, 저장해 둔 flowId를 지우고, 이미 쓰던 실패 상태(failed / request_failed)로 넘깁니다. 임시 네트워크/HTTP 실패는 예전처럼 다시 시도합니다. 같은 상황을 재현하는 테스트도 하나 추가했습니다. UI 문구·API 계약·로그인 로직 자체는 건드리지 않았습니다.

라인 gui/src/components/use-main-device-reauth.ts (GET 폴 분기) - 404 + unknown_flow일 때 stopPolling()flowRef = null은 맞지만, cancellationRequestedFlowRef는 그대로 둡니다. 지금은 start()가 비워 주니 큰 사고는 아닙니다. 다만 DELETE의 unknown_flow 처리와 맞추려면 여기서도 같이 비우는 편이 더 깔끔합니다.
경로 gui/tests/main-device-reauth-ownership.test.tsx - 회귀 테스트는 “취소 실패 → GET unknown_flow”만 봅니다. 정상 폴링 중(취소 없이) 같은 404가 와도 멈추는지, 그리고 code 없는 그냥 404는 예전처럼 취소 중 폴링을 이어가는지는 이 PR에 없습니다. 이번 버그 한 줄에는 충분하지만, 유지보수 관점에선 한 케이스 더 있으면 좋습니다.
프로세스 - base는 dev로 올바릅니다. 그런데 PR이 아직 draft이고 enforce-target이 “UI screenshot 없음”으로 실패합니다. 코드 변경은 훅/테스트뿐이고 화면 카피·레이아웃 변경은 없습니다.

메인테이너의 판단이 필요한 지점

스크린샷 게이트를 이 PR에 그대로 적용할지, 아니면 “보이는 UI 변경 없음”으로 면제할지. 면제 기준이 없다면 작성자가 기존 reauth 화면 캡처를 하나 올리면 draft/enforce-target이 풀릴 가능성이 큽니다.

너의 추천

코드 방향은 맞고 DELETE 처리와도 대칭입니다. cancellationRequestedFlowRef 정리와 테스트 한 케이스 추가는 있으면 좋고, 없어도 머지 차단할 정도는 아닙니다. 먼저 스크린샷(또는 면제)으로 게이트만 풀고 ready로 올린 뒤 머지하는 쪽을 추천합니다.

이 댓글은 grok-bot이 작성했습니다

@luvs01

luvs01 commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator Author

Behavior-only fix in the reauth ownership hook (no visual change to the dialog or screens), so there is no meaningful screenshot to attach — requesting \gui-screenshot-waived\ from a maintainer. cc @lidge-jun

@lidge-jun

Copy link
Copy Markdown
Owner

Thanks @luvs01. This is carried in #5600 with your commit (8895312) kept as authored, plus a structure-doc update (2c15f14) and a before/after screenshot. Closing in favor of #5600.

@lidge-jun lidge-jun closed this Sep 22, 2026
lidge-jun added a commit that referenced this pull request Sep 23, 2026
…top, reauth unknown_flow, Raycast probe, pool golden, no-renames) (#5600)

* docs: harden branch content classification against renames

* docs: date the no-renames correction and align sibling commands

* test(oauth): exercise configured generic pool validators

* test(oauth): prove the generic null-strategy clear and harden test teardown

* test(oauth): require the strategy property in the cleared response

* fix(integrations): harden Raycast defaults probe

* test(integrations): cover killed defaults probe in Raycast detection

* fix(reauth): stop polling terminal unknown flows

* fix(qoder): preserve offsets in scaffold scanning

* fix(responses): keep a cyber-policy stop when a 5xx body has malformed UTF-8

consumeComboFailure read 5xx bodies with fatalUtf8, so a single malformed
byte rejected the whole read and replaced an otherwise recognizable
cyber-policy refusal with "Provider error <status>". The combo then hopped
instead of stopping.

readBoundedResponseBody gains reportUtf8Validity: it decodes with
replacement characters and reports utf8Valid at EOF (true by construction
when fatalUtf8 is also set). consumeComboFailure keeps every existing trust
rule for malformed 5xx bodies -- no quota evidence, usage, or ordinary
classification -- and only lets the lenient decode through when it
identifies a cyber-policy refusal. The quota agreement with
shouldRetryCodexPoolAccountQuota is unchanged.

Reimplements #5307 with a narrower classification gate.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs: separate the campaign command from the corrected rerun command

The branch and PR classification summaries showed the --no-renames form as though the campaign had used it. State the command that produced the recorded verdicts and the form any rerun must use, matching the correction in 010_method.md.

Follow-up to #5461.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(oauth): restore the pool-validator home even when shutdown throws

A throwing server.stop skipped the OPENCODEX_HOME restore and temp-dir removal, leaking both into later cases. Run cleanup in an inner finally.

Follow-up to #5442.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(integrations): model a killed defaults probe with a type-safe result

The timeout case cast a result with exitCode null directly to typeof Bun.spawnSync, which strict TypeScript can reject, and its empty stdout could not tell an exit-code check from an empty read. Cast through unknown, cover null and non-zero exits, and return "1" on stdout so ignoring the exit code would visibly report Pro.

Follow-up to #5244.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs(structure): record the terminal unknown_flow GET in the reauth contract

The dashboard contract said a non-2xx GET keeps cancellation ownership and polling, and that no replacement login POST can appear before DELETE settles. A GET 404 unknown_flow now ends the flow the same way the DELETE path does, so qualify both statements as applying to retryable GET errors and state the exception in the overview.

Follow-up to #5428.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* fix(qoder): keep single-unit Unicode case folding in scaffold scanning

Matching markers with ASCII-only folding kept offsets correct but dropped matches the lowercased scan used to make: U+212A KELVIN SIGN lowercases to an ASCII k, so <invo\u212Ae> tool markup passed through unsuppressed, whole or split across deltas. Fold each code unit as toLowerCase() does when the result is a single code unit; characters that expand, such as U+0130, still cannot shift offsets.

Follow-up to #5366.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* docs(pr-assets): add the reauth unknown_flow GET before/after capture

Main-account card rendered with the dev hook and the branch hook against a mocked management API (Cancel DELETE 503, then GET 404 unknown_flow). Synthetic identity only.

Follow-up to #5428.

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

* test(responses): keep a non-replayable malformed cyber stop free of retry metadata

Carries the #5307-related part of cc466ed, which the author added after consolidating #5307 into #5553: a malformed 502 cyber-policy body that was marked non-replayable must keep the marker, carry no Retry-After or quota reset, and still stop the combo. Document the malformed-body contract in the responses structure doc, matching the narrower classification gate this branch implements.

Follow-up to #5307 (via #5553).

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>

---------

Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants