Repository navigation
feat(durable): add wait_for_approval and the approvals client - #389
Merged
Merged
Conversation
Regenerates the internal client from the Hosting spec with the durable approval request, list, get, stats, approve, and deny operations, and requires the operations the SDK calls. Co-authored-by: Cursor <cursoragent@cursor.com>
DurableContext.wait_for_approval registers an approval with Volcano from the runtime's callback submitter and suspends until a person decides. A denial or a timeout returns an ApprovalDecision rather than raising. @durable reads the execution reference from the invocation and passes it to child, map, and parallel contexts. client.durable.approvals lists, reads, summarizes, approves, and denies approvals. HTTP 403 now raises PermissionDeniedError, a subclass of AuthenticationError. Co-authored-by: Cursor <cursoragent@cursor.com>
Retry registration on network errors, timeouts, 404, 429, any 5xx, and 409 approval_not_ready, on the JS SDK's delay schedule within one 30-second deadline that also caps each attempt's timeout. A 409 approval_closed now counts as registered, so an approval whose timeout passed first resumes with the expired decision instead of failing the execution. Refuse text that cannot be encoded as JSON and approvals over 64 KiB (with room for the longest callback id) before the callback opens, and send the exact bytes that were measured. Out-of-range approval timeouts raise TypeError, as ctx.wait does. Correct the guide: approvals have no name filter, and a refusal reaches the handler as the runtime's CallbackSubmitterError. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…eniently Co-authored-by: Cursor <cursoragent@cursor.com>
…from its context Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…avaScript SDK does Co-authored-by: Cursor <cursoragent@cursor.com>
This was referenced Oct 7, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
subnetmarco
commented
Oct 8, 2026
subnetmarco
left a comment
Member
Author
There was a problem hiding this comment.
Reviewed at 424d6f4. The core holds up against the runtime and Hosting:
- Registration runs in the checkpointed submitter, and a retried POST is idempotent by callback id.
- The runtime's own retry is disabled, and running out of the deadline fails the execution instead of hanging.
- Only
CallbackTimeoutErrorbecomesexpired, andPermissionDeniedErrorsubclassesAuthenticationError. - The 64 KiB check measures the exact UTF-8 bytes sent, and the retry policy matches JS.
ruff, mypy, basedpyright, and the generated-client check pass. pytest gives 2626 passed and 1 failed, and the failure comes from FORCE_COLOR=0 in the local shell.
Release order: Hosting's E2E pins volcano-sdk-python~=0.14.0, so this needs to be released before Hosting merges (details on Kong/volcano-hosting#1678).
Co-authored-by: Cursor <cursoragent@cursor.com>
Names are the runtime's operation name, so they hold to printable ASCII and 237 characters. NUL is refused before the callback opens, details are copied when checked, and a stalled host lookup no longer outlasts its attempt. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # openapi/openapi.yaml
… wins Co-authored-by: Cursor <cursoragent@cursor.com>
subnetmarco
marked this pull request as ready for review
October 8, 2026 19:05
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 8, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 8, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 8, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 8, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 8, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 8, 2026
A command normally arrives within a millisecond. The 0.2 s wait failed the cancelled-unsubscribe tests whenever a loaded runner stalled the loop, which made mutation stats collection fail on random modules. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change
Durable workflows can wait for a person's approval. Tracks https://github.com/Kong/volcano-hosting/pull/1678.
ctx.wait_for_approval(name, *, title, description=None, details=None, timeout=None)suspends the execution until a person approves or denies, or the timeout passes, and returns anApprovalDecision. Registration runs inside the callback submitter, so a replay never registers twice; a timeout resolves tostatus="expired".approval_not_readywithin one 30 s deadline. Each attempt is bounded as a whole (connect, headers, and body) by min(10 s, remaining). The request is validated against the 64 KiB body limit before the callback opens.namemust be printable ASCII of at most 237 characters, since it is the runtime's operation name, and NUL is refused anywhere in the text ordetails.detailsis copied when checked, so a later change by the caller cannot alter what was validated. A host lookup that stalls is bounded by its attempt's deadline.client.durable.approvals:list,get,stats,approve,deny. A project access token is refused deciding withPermissionDeniedError.status;comment,decided_by, anddecided_atread as empty when malformed, so a recorded decision never fails a replay.decided_atmust be an RFC 3339 date-time, matching JavaScript.Verification
poe checks: pass. Policy, audit, generated client, ruff, mypy, basedpyright, 2615 tests at 100% line and branch coverage, package check, and all four tox environments.test_realtime_presence_sync_coalesces_latest_backpressured_stateis timing-sensitive under heavy load and also fails intermittently onmain; it passed in the final run.Cross-language impact
Classify this change: public facade / wire contract / shared behavior.
tests/sdk-contract/features/durable-approvals.featurewith JS, Python, and Ruby bindings in https://github.com/Kong/volcano-hosting/pull/1678.docs/functions.mdandREADME.mdhere; JS and Ruby in their PRs; Hosting'sdocs/public/functions/durable-approvals.md.Merge order
404.localmode-e2e. That suite needs a nightly local-mode image with approvals, which exists only once Hosting merges. Hosting's merge queue runs its CLI E2E against CLImain, so the CLI goes first.