Skip to content

client: add timeout exit code for wait polling (PRINFRA-125)#46

Merged
somanshreddy merged 1 commit into
mainfrom
04-06-poll_timeout_exit_code_and_resource_id
Apr 6, 2026
Merged

client: add timeout exit code for wait polling (PRINFRA-125)#46
somanshreddy merged 1 commit into
mainfrom
04-06-poll_timeout_exit_code_and_resource_id

Conversation

@somanshreddy

@somanshreddy somanshreddy commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator

Description

Poll timeouts (--wait exceeding --timeout) now return exit code 4 instead of exit code 1, distinguishing "resource created but not yet complete" from "operation failed." This was prompted by dogfood feedback where a user resubmitted a video create because the timeout error gave no indication the resource already existed — wasting a credit.

Three changes:

  1. Exit code 4 (ExitTimeout) — new exit code meaning "the side-effect happened but completion wasn't confirmed." The agent reads exit 4 and knows not to retry create; instead it polls manually with the hinted get command. Exit 1 remains "failure or unknown" — retry is not always safe (transport failure after server processes create leaves the outcome ambiguous).

  2. Partial result on stdout — on timeout, the last polled status response is emitted to stdout (same shape as a successful video get). The agent gets the resource ID, current status, and any other fields without parsing stderr. Builder uses "data", nil (key-value rendering in --human, matching the success path).

  3. HintCommand on PollConfig — timeout hints are explicit per poll config, not inferred from spec.Group. This matters for video-agent create, which polls /v3/videos/{video_id} — the correct hint is heygen video get <id>, not heygen video-agent get <id> (which doesn't exist).

Cancel vs timeout distinction preserved: classifyPollContextError checks context.DeadlineExceeded (→ ErrPollTimeout, exit 4) vs context.Canceled (→ CLIError{Code: "canceled"}, exit 1). Ctrl-C produces no partial result and no special exit code.

Error handling flow:

  • Pre-resource-ID errors (create call fails/times out): translateCreateContextError → exit 1. The CLI can't confirm whether the resource exists.
  • Post-resource-ID timeout: classifyPollContextErrorErrPollTimeout → builder outputs partial result + exit 4.
  • Post-resource-ID cancel: classifyPollContextErrorCLIError → exit 1, no partial result.
  • Terminal failure (status: failed): ErrPollFailed path unchanged → exit 1 with failure response on stdout.

Linear: PRINFRA-125

Testing

  • TestExecuteAndPoll_TimeoutWhileWaiting — verify ErrPollTimeout with ResourceID and last status Data
  • TestExecuteAndPoll_TimeoutDuringRequest — timeout before first poll, Data is nil, ResourceID still populated
  • TestExecuteAndPoll_Cancel — cancel returns CLIError{Code: "canceled", ExitCode: ExitGeneral}, not ErrPollTimeout
  • TestGenBuilder_VideoCreate_Wait_Timeout — exit 4, partial result on stdout, hint in stderr
  • TestGenBuilder_VideoCreate_Wait_TimeoutBeforeFirstPoll — exit 4, empty stdout
  • TestGenBuilder_VideoCreate_Wait_Timeout_Human — human mode renders partial result as key-value
  • TestGenBuilder_VideoAgentCreate_Wait_Timeout_UsesVideoGetHint — hint says "video get", not "video-agent get"
  • TestGeneratedRoot_RootHelp_ListsTimeoutExitCode — root --help includes exit code 4

@linear

linear Bot commented Apr 6, 2026

Copy link
Copy Markdown
PRINFRA-125 CLI M1: Pagination, polling + HTTP hardening

Implement the framework features that make generated commands production-ready: pagination, polling, and HTTP client hardening.

Scope

Pagination

  • --all flag: generic paginator that accumulates cursor-based pages into flat array
  • --limit and --token flags for manual pagination
  • Warn on stderr if --all count exceeds 1000
  • Paginator reads TokenField/DataField from CommandSpec — zero per-command code

Polling

  • --wait flag: poll until async operation reaches terminal state
  • --timeout flag (default 10m)
  • PollConfig type: status endpoint, status field, terminal states, ID field
  • Exponential backoff: min(2s * 2^attempt, 30s) with 10% jitter
  • Timeout exits with code 1 (general error)

HTTP Client Hardening

  • Retries with exponential backoff for transient errors (5xx, network)
  • Retry-After header respect for 429 rate limits
  • Configurable timeout

Not in scope (moved to PRINFRA-139)

  • --force, --quiet, -o/--out, stdin reading

Acceptance Criteria

  • heygen video list --all accumulates all pages into single JSON array
  • heygen video create --wait polls until completion or timeout
  • 429 responses are retried automatically respecting Retry-After
  • Transient 5xx errors are retried with backoff

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@somanshreddy somanshreddy marked this pull request as ready for review April 6, 2026 08:11

somanshreddy commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator Author

Merge activity

  • Apr 6, 8:21 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 6, 8:21 AM UTC: @somanshreddy merged this pull request with Graphite.

@somanshreddy somanshreddy merged commit 57e3b02 into main Apr 6, 2026
8 checks passed
@somanshreddy somanshreddy deleted the 04-06-poll_timeout_exit_code_and_resource_id branch April 6, 2026 08:21
@somanshreddy somanshreddy changed the title add timeout exit code for wait polling (PRINFRA-125) client: add timeout exit code for wait polling (PRINFRA-125) Apr 6, 2026
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