Skip to content

feat(durable): list, read, and decide durable approvals - #341

Merged
subnetmarco merged 11 commits into
mainfrom
feat/durable-approvals
Oct 8, 2026
Merged

subnetmarco merged 11 commits into
mainfrom
feat/durable-approvals

Conversation

@subnetmarco

@subnetmarco subnetmarco commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Change

List, read, and decide durable approvals from Ruby. Tracks https://github.com/Kong/volcano-hosting/pull/1678.

  • client.durable.approvals: list(project_id, filters), get, stats(function:, from:, to:), approve(..., comment:), deny(..., comment:), returning frozen Data records. A decider with an empty email is accepted, and a string window bound must carry an offset (Z or ±hh:mm), since one without would be read in the host's time zone.
  • HTTP 403 now raises Volcano::Error::PermissionDeniedError, a subclass of AuthenticationError, so existing rescue AuthenticationError still catches it. A project access token deciding an approval gets this error.
  • Ruby has no durable authoring, so there is no wait_for_approval; workflows request approvals from JavaScript or Python.
  • Generated client synced from Hosting's OpenAPI.
  • Steep 2.1 (from main) flagged an unreachable branch in a type fixture; it now checks by identity.

Verification

  • bundle exec rake quality: pass. Audit, generated client check, RuboCop (no offenses), Steep (both configurations), 2020 examples with 100% line and branch coverage, all injected defects detected, package smoke, documented quickstart.

Cross-language impact

Classify this change: public facade / wire contract / shared behavior.

Merge order

  1. SDK releases: a maintainer merges and releases the JS SDK 1.16 (feat(durable): add waitForApproval and the approvals client volcano-sdk-js#315), Python SDK 0.14 (feat(durable): add wait_for_approval and the approvals client volcano-sdk-python#389), and the Ruby SDK (feat(durable): list, read, and decide durable approvals #341). Hosting's E2E fixtures install those versions from the registries. Until Hosting deploys, the new approval methods get 404.
  2. CLI (feat(durable): add durable approvals commands volcano-cli#282), with a one-time maintainer override of 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 CLI main, so the CLI goes first.
  3. Hosting (https://github.com/Kong/volcano-hosting/pull/1678).
  4. Dashboard (https://github.com/Kong/volcano-web/pull/836, https://github.com/Kong/volcano-web/pull/837, then https://github.com/Kong/volcano-web/pull/832) and agent skills (docs(durable): teach agents to request and decide durable approvals volcano-skills#57).

subnetmarco and others added 9 commits October 7, 2026 10:41
Add client.durable.approvals with list, get, stats, approve, and deny over
the durable approvals endpoints, backed by the regenerated client. Responses
map to frozen Data records; a deleted function, execution, or decider keeps
its name with a nil id. Decision times and daily dates are validated, and
daily dates stay YYYY-MM-DD UTC strings.

HTTP 403 now raises Volcano::Error::PermissionDeniedError, a subclass of
AuthenticationError, so existing rescues keep working.

Co-authored-by: Cursor <cursoragent@cursor.com>
Match the Python SDK's name for the HTTP 403 error. Neither SDK has
released it yet. Also say that an approval's decision is nil unless it was
approved or denied, and document the nil decided_by in docs/functions.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
… defect checkout

Co-authored-by: Cursor <cursoragent@cursor.com>
…s exception

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Steep 2.1 types DurableApproval.members.first as the literal :id, so
`== :id` narrows to always true and the raise reads as an unreachable
branch. Symbols are singletons, so an identity check keeps the same
runtime assertion without that narrowing, as main did for true/false.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

@subnetmarco subnetmarco left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 561e1a3. I found no P1 or P2 issues:

  • Mapping 403 to PermissionDeniedError < AuthenticationError is backward compatible. 403 used to raise AuthenticationError, nothing compares exact error classes, and the refresh paths still key on 401.
  • The OpenAPI matches Hosting's bundle, and query names, enums, conflict codes, and pagination all match.
  • The records are frozen all the way down, and the RBS signatures match the implementation.
  • rubocop, Steep, and the approval specs pass.

Two P3s inline.

Comment thread lib/volcano/durable_approval_responses.rb Outdated
Comment thread lib/volcano/durable_approvals.rb Outdated
… on window bounds

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	lib/volcano/generated/README.md
#	lib/volcano/generated/lib/volcano-generated/api/durable_functions_api.rb
#	openapi/openapi.yaml
#	spec/volcano_generation_spec.rb
@subnetmarco
subnetmarco marked this pull request as ready for review October 8, 2026 19:06
@subnetmarco
subnetmarco requested a review from a team as a code owner October 8, 2026 19:06
@subnetmarco
subnetmarco added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit 66d0076 Oct 8, 2026
8 checks passed
@subnetmarco
subnetmarco deleted the feat/durable-approvals branch October 8, 2026 19:15
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