# Polling and recovery

Source: https://convergingthought.com/docs/sdk-reference/polling

> Keep one durable operation through retries, process restarts, and long-running work.



A reliable integration treats submission and observation as separate activities. Submission establishes the job. Observation reads the same job until its outcome is known. A browser refresh or an impatient caller should not create a second model operation.

## Store the intent before sending [#store-the-intent-before-sending]

Create an application operation record with an idempotency key, subject, kind, and the exact payload or a secure reference to it. Persist it before making the POST. When admission returns, add the job ID and status URL to that same record.

```text
Application intent
  operation_key   stable before first POST
  payload_ref     authorized storage for the original input
  job_id          saved as soon as admission returns
  last_status     most recent observation
  next_check_at   when the application should read again
```

This record is your recovery boundary. Keep private source content in appropriate storage rather than copying it into an ordinary task log. Idempotency keys should also be opaque, not encoded user messages.

## Observe with bounded backoff [#observe-with-bounded-backoff]

Read the job immediately after admission, then increase the delay between reads. One second growing to 15 seconds is suitable for the current asynchronous workflow. Add jitter if many application workers might poll together. Use a maximum observation window so a request handler is not held open indefinitely.

If your hosting environment has short request deadlines, return the application operation ID to the caller and schedule later reads in your own durable worker. There is no requirement to keep the original HTTP connection open, and no public callback registration exists yet.

## Decide from the full state [#decide-from-the-full-state]

When `billing.settled` is true, inspect the terminal status and result. `succeeded` is an inference result. `ready` is a validated candidate and still needs an activation check. `failed` and `rejected` are known completed outcomes, not exceptions that automatically justify resubmission.

When `reconciliation_required` appears, stop the automatic paid workflow and preserve the job. You may continue occasional read-only observation, but do not release your own notion of the operation and start another one as a substitute.

## Recover each interruption [#recover-each-interruption]

| Interruption                    | Recovery                                               |
| ------------------------------- | ------------------------------------------------------ |
| POST timed out before receipt   | Repeat the original key and body to recover admission  |
| Polling GET failed              | Back off and read the same job                         |
| SDK polling deadline elapsed    | Save the ID and resume observation later               |
| User closed the browser         | Resume from your server's operation record             |
| Application worker restarted    | Load the saved intent and receipt                      |
| Candidate activation conflicted | Read the subject and make an explicit release decision |
| Provider outcome is ambiguous   | Keep the reservation and request reconciliation        |

## Cancellation and user-facing status [#cancellation-and-user-facing-status]

The API has no cancellation endpoint. An AbortSignal only stops the client from waiting. If a user dismisses a loading panel, label that action as closing or stopping observation rather than cancelling the model job.

Expose useful distinctions in your own UI: queued, running, completed, learning ready but not active, and needs investigation. Show a recoverable operation ID so a user can return later. Avoid a generic timeout message that encourages them to click a button that starts the same paid work again.

## Retry ceilings [#retry-ceilings]

Bound transport retries by both count and elapsed time. After persistent failures, retain the intent and mark it for later inspection. Do not change payloads in-place under an existing key; corrections are deliberate new operations with new identities.

For manual adapter activation, use read-after-write recovery instead of the model-job idempotency pattern. Read [Activate an adapter](/docs/api-reference/activation) for that distinct contract.
