Skip to content

Fix CLI Approval Polling Bugs (surfaced by #63)#95

Open
googleknight wants to merge 2 commits intostripe:mainfrom
googleknight:fix-approval-polling-terminal-statuses
Open

Fix CLI Approval Polling Bugs (surfaced by #63)#95
googleknight wants to merge 2 commits intostripe:mainfrom
googleknight:fix-approval-polling-terminal-statuses

Conversation

@googleknight
Copy link
Copy Markdown

Summary

Addresses CLI-side issues surfaced by #63 (spend-request approval flow getting stuck on pending_approval).

Note: The reported web-UI failure at app.link.com/activity/approve/... is server-side and outside this repo. However, investigating it surfaced three real bugs in the CLI's polling code worth fixing independently. Two focused commits, no API changes.


What's Fixed

1. Recognize All Terminal Statuses in Approval Polling

The interactive spend-request retrieve TUI only treated approved and denied as terminal statuses. Any other terminal status — expired, succeeded, failed, canceled — caused continued polling until the local timeout fired, ultimately surfacing a misleading "Timed out waiting for approval" error for requests that had already reached a terminal state on the server.

The same misclassification affected:

  • The useApprovalPolling hook (used by interactive create and request-approval)
  • Both demo flows (demo/card-flow, demo/spt-flow)

In all of these, pollUntilApproved resolves on any non-pending terminal status (per its own unit-test contract), but every call site treated resolution as success — meaning a denied or expired request was rendered as "✓ Spend request approved".

Fix: Introduced a shared TERMINAL_STATUSES set in the TUI (mirroring the JSON path's set in commands/spend-request/index.tsx) with a new 'finalized' render branch. Added explicit status === 'approved' checks in useApprovalPolling, demo/card-flow, and demo/spt-flow.

pollUntilApproved itself is unchanged — its tests assert the current contract, and the right fix is at the call sites.


2. Extend Default Polling Window Past Server-Side Expiry

The Link approval UI shows an ~8-minute expiry countdown, but retrieveOptions.timeout defaulted to 300 s, and the _next.command hint emitted by create/request-approval recommended --interval 2 --max-attempts 150 (also 300 s).

Users or agents racing the 8-minute window could hit POLLING_TIMEOUT purely because the CLI gave up before the request itself expired.

Fix:

  • Bumped --timeout default to 600 s
  • Updated _next.command hint to --max-attempts 300
  • Updated matching README example

Polling now comfortably outlives the server-side expiry. No effect when callers pass explicit values.


What's Not Fixed (and Why)

The root cause of #63 — clicking "Approve" in the Link web app and the UI silently failing to transition the request out of pending_approval — occurs in the Link web application, which is not in this repository.

The CLI faithfully reports whatever status the API returns; only the API can advance the state machine. These changes fix adjacent CLI bugs that became visible because of the incident, not the incident's root cause itself.


Test Plan

Check Result
pnpm typecheck ✅ 3/3 packages clean
pnpm test ✅ 204/204 tests pass (91 SDK + 113 CLI)
pnpm biome check . ✅ Clean

Relevant test coverage: packages/cli/src/__tests__/cli.test.ts:711–781 — exercises --max-attempts exhaustion, --timeout expiry, and terminal-status detection in JSON-mode polling integration tests.

@googleknight googleknight requested a review from a team as a code owner May 9, 2026 04:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant