Re-vendor the OpenAPI spec from conductor main - #8
Merged
Conversation
The vendored spec predated conductor's autoscaling and domain-claim work and its un-gating of listPermissions, so the generated client was missing operations and the OAuth-gate table was wrong. Re-vendored with `make spec` from conductor main (7601b14), which is byte-identical to the spec DBOS Cloud serves at /conductor/v2/openapi.json, then `make generate`. Seven new operations reach the client: getAutoscale, the three autoscaling policy operations, and the three domain-claim operations. No command maps to them yet; AGENTS.md now tracks them as unmapped surface. Two consequential source changes: - listQueues gained an optional applicationName parameter, so ListQueuesWithResponse takes a params argument. Passed nil, matching listSchedules and preserving today's behavior (the parameter defaults to the application in the path). - listPermissions lost x-dbos-requires-oauth, so it left the gate table. Per the plan recorded in AGENTS.md, this removes `permission list`'s interim mode-aware refusal: the command now works against a no-auth deployment, resolving the org to `local` like every other unauthenticated command. Its no-auth unit test now asserts that rather than the refusal. The gated-operation count goes 14 -> 16: listPermissions leaves, the three domain-claim operations join. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Tests for what the re-vendor actually changed: - permission list against a real no-auth conductor (tier 3). The un-gating is the behavioral claim of the last commit, and a mock server cannot check it: what matters is that a no-auth conductor now registers the route at all. This is the test that would have caught the stale gate. - queue list sends no applicationName. The CLI exposes no flag for the new filter, so it must stay unsent and let the server default it to the app in the path, rather than pinning it to an empty name. - queue get renders applicationName when set and omits the row when null. This one needed a fix, not just a test: the field is new in the spec and queueFields() didn't project it, so `queue get` hid the owning app in exactly the case the field exists for -- several apps sharing a system database. Detail already omits empty fields, so nothing changes for the common null case. And a daily spec-drift workflow. CI's existing check is hermetic: it proves the generated client matches the vendored spec, never that the snapshot still matches reality -- which is how the spec went stale unnoticed. scripts/check-spec-drift.sh compares the vendored spec against the deployed one at cloud.dbos.dev, ignoring the `servers` field cloud rewrites, and reports the operation-level difference when they diverge. Deployed is the only other copy compared. Conductor's own spec would catch a re-vendor gap sooner, but that repo is private and this one is about to be public, so CI would need a token to read it -- and conductor's main legitimately runs ahead of the deployment between a merge and its release, so the extra pair is mostly noise. Deployed is the copy dbosctl actually talks to, so drift against it is always actionable. The job needs no secrets: cloud serves the spec publicly. Also available as `make check-spec` for local use. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The re-vendor added applicationName to three response schemas -- Queue, Schedule, and Workflow -- and the last commit only projected it on Queue. So `schedule get` and `workflow get` still hid the owning application in exactly the case the field exists for: several applications sharing one system database. Same nullable *string shape, same fix, and Detail already omits empty fields, so nothing changes for the common null case. Tests cover both states for each, and were confirmed to fail without the projection rather than merely pass with it. Nothing else in the re-vendor reaches a command. The seven new operations (getAutoscale, the autoscaling policy trio, the domain-claim trio) have no CLI surface, so there is nothing here to test yet -- exercising the generated client alone would test oapi-codegen, not this repo. The new applicationName query parameters on listQueues/listSchedules/listWorkflows are all passed nil, which the queue test already pins. Also adds tests for scripts/check-spec-drift.sh, hermetically via httptest. It is the only thing that notices a stale vendored spec, and its dangerous failure mode is silent: a regression that made it always report "match" would retire the check without breaking anything visibly. These pin that drift is detected, that an unreachable server fails rather than passes, and that the `servers` field cloud rewrites stays excluded -- which, if it regressed, would fail the daily job every day until it was ignored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…uctor Scheduling the vendored-vs-deployed comparison from this repo was always the constrained version of the check. The useful comparison has three sources -- conductor's own spec, this repo's vendored copy, and what is deployed -- and conductor is the only one of the three repos that can read all of them: it has its own source, this repo will be public, and the deployed spec is already public. From here the conductor leg is unreachable without handing a public repo's CI a token for a private one. So this removes the daily workflow and the tests for the script it ran. scripts/check-spec-drift.sh and `make check-spec` stay: still worth running by hand after a re-vendor, and the natural starting point for the conductor implementation. AGENTS.md now records why nothing is scheduled here, so the workflow does not get helpfully re-added later. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
listQueues takes an applicationName parameter that narrows results to objects owned by a named application, plus unclaimed ones. That is a different axis from -a/--app, which chooses the application the request is addressed to and goes in the URL path, so it needs its own flag rather than overloading that one. --owner-app is defined once in addRequestFlags and read through ownerAppFilter, so the endpoints that take the same parameter -- listSchedules and listWorkflows today, more later -- reuse the flag and the helper instead of each inventing a spelling. AGENTS.md records the convention, including that a list-valued endpoint should make the flag repeatable rather than rename it. Unset stays unset: conductor defaults the scope to the addressed application, and no value means "everything", so the helper returns nil rather than sending an empty name (which would scope to an application called ""). Naming another application requires application.read on it, so the filter cannot widen a caller's access. The test declares the flag via addRequestFlags rather than hand-rolling it -- the test command builder registers flags by hand, and a hand-rolled declaration would pass while the real command forgot to register it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each sat in a table of ~20 uniform field projections that carries no other comments, so annotating one entry implied it was special when its code is identical to its neighbors. Both claims were also already stated elsewhere: nullability on the generated field's own doc comment, and the omit-empty behavior on output.Detail, where it holds for every field rather than just this one. The tests still say it where it matters. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This reverts commit 5b49980. --app already carries the meaning users want: conductor defaults the applicationName scope to the application in the path, so `queue list --app B` already returns B's queues. --owner-app only did anything when it differed from --app, which only helps when the app you want has no healthy executor and a co-tenant sharing its system database does. That is too narrow to justify a second app-shaped flag in the help text of an unshipped CLI. Leaves the parameter unused. If the dead-executor case turns out to matter, the better fix is probably in conductor -- falling back to a co-tenant's executor -- which would serve the console and every generated client rather than teaching each one a routing override. The applicationName display work is unaffected: queue, schedule, and workflow detail views still show the owning application when there is one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The workflow and its tests went earlier; this takes the script, the check-spec target, and the docs with them, leaving nothing spec-drift shaped in this repo. Comparing the vendored spec against reality is still worth doing, but not from here. This repo is about to be public and conductor never will be, so the comparison that matters most -- vendored against conductor's own spec, which catches a gap before it reaches a deployment -- is one a public repo structurally cannot make. Conductor can reach all three copies. Where the check lives, and what it compares, is a decision to make there rather than something to leave a half-version of here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Picks up conductor b2b9285 (#187), which removes the six caller-settable applicationName inputs -- the query parameters on listQueues, listSchedules and listWorkflows, and the body properties on searchWorkflows and the two aggregates operations. The three response fields stay, so `queue get`, `schedule get` and `workflow get` still show a row's owning application. The `nil` argument to ListQueuesWithResponse goes in the same commit, and has to. applicationName was that operation's only query parameter, so ListQueuesParams no longer exists and the fourth argument is now the variadic reqEditors. `nil` is a valid RequestEditorFn, so the call still compiles -- and then applyEditors invokes it, panicking on every `dbosctl queue list`. Neither go build, go vet, nor the generate drift check catches that; only TestRunQueueList does. No operations were added or removed, and nothing became newly required. Note that cloud has not deployed #187 yet, so this spec is briefly ahead of what it serves. That is safe in this direction: every removed input was optional and dbosctl never sent any of them, so a client generated from this spec behaves identically against a server on either side of the revert. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The existing drift check is hermetic: `make generate && git diff --exit-code` proves the vendored spec and the committed client agree, which stays true no matter how far a deployed API moves. Nothing in CI notices when an upstream server changes shape. Add an api-compat job that regenerates the client from each upstream spec — the dbosdev/conductor:latest image via its openapi subcommand, and cloud's public /conductor/v2/openapi.json — and builds and unit-tests the result. The two targets are not redundant: cloud serves conductor's spec with `servers` repointed, from whichever conductor it has actually deployed, which lags the released image. Today that gap is real — cloud still advertises the applicationName filters conductor reverted in #187, and generating from it adds a params argument to ListQueues that queue.go does not pass. Advisory, not blocking. The job is sensitive by construction: oapi-codegen renders query parameters as a params-struct argument, so upstream adding one optional parameter breaks the build here while the API stays backward compatible and the CLI keeps working at runtime. That is worth surfacing but not worth failing an unrelated PR over, so it runs continue-on-error and writes the spec delta to the step summary. A failed fetch warns rather than reporting a compatibility problem we never observed.
Collaborator
Author
|
Note, managed conductor is awaiting an update that has already been applied to latest conductor docker image. Managed conductor will be updated soon. We can choose to bypass failing check and merge anyway or wait until cloud is updated and rerun |
Collaborator
Author
kraftp
approved these changes
Aug 13, 2026
kraftp
left a comment
Member
There was a problem hiding this comment.
It should pass + merge tomorrow
# Conflicts: # internal/cli/permission.go
Conductor's "Cleanup Unused Endpoints" (dbos-inc/conductor#190) dropped the restartWorkflow endpoint, and the autoscale request gained maxOldApplicationVersions. Re-vendored with `make spec` from a local conductor checkout at 0b85c57, then `make generate`. The CLI's `workflow restart` command is already gone (#10), so nothing referenced RestartWorkflowWithResponse. The OAuth-gate table is unchanged: restart was never gated, so it stays at 16 operations. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
kraftp
approved these changes
Aug 14, 2026
devhawk
added a commit
to dbos-inc/dbos-docs
that referenced
this pull request
Aug 17, 2026
Conductor's HTTP API and the `dbosctl` CLI had no documentation. This adds two pages under **Deploy To Production** and links them from the Conductor overview. Both are new files, so the diff is additive — nothing existing is rewritten beyond one bullet on `conductor.md`. ## The pages **[Conductor API](docs/production/conductor-api.md)** — base URLs, the three ways to get the OpenAPI spec, authentication, resource scoping, the RFC 9457 error model, listing and filtering conventions, a map of all 64 operations by area, the operations a no-auth self-hosted deployment does not register, and how to generate a client. **[dbosctl CLI Reference](docs/production/dbosctl.md)** — installation, profiles, authentication, configuration precedence, output formats, exit codes, and a command-by-command reference. Follows the shape of the existing Cloud CLI reference page. The sidebar is autogenerated from the directory, so no `sidebars.js` change is needed. ## Where the content came from Not from the READMEs. The endpoint reference, parameter lists, and error shapes were read out of the OpenAPI spec, and the CLI reference was generated from a recursive `--help` dump of a real build, then diffed back against it mechanically — 38 leaf commands, no undocumented commands, no invented flags. Details that came from reading the implementation rather than the spec text, because a reader would otherwise hit them as surprises: - **Workflow mutations need a live executor.** Cancel, resume, restart, fork, and delete are dispatched to a healthy connected executor rather than applied in Conductor's database, so they fail outright when nothing is running — resume and restart additionally need an executor on the latest version. - **The autoscaling operations require a DBOS Teams plan** and return 403 otherwise. - **Getting the spec from the Conductor image needs `--entrypoint`.** The image's entrypoint waits for Postgres and runs migrations without forwarding arguments, so the obvious `docker run <image> openapi` hangs waiting for a database the subcommand does not need. ## Two scoping calls worth a look **The API is not "everything the console does."** An earlier draft said so; it is wrong, because the console also drives DBOS Cloud — deploying applications, provisioning databases, billing — none of which this API touches. Both pages now scope it to the Conductor control plane, which is what the console shows for a Conductor-connected application whether it runs on your own infrastructure or on DBOS Cloud, and point the cloud-specific operations at the pages that own them. **Nothing is framed as versioned.** There is one public API; the predecessor is internal. `v2` appears only in URLs and paths, where you actually type it, and never in prose as though it were a choice. ## Verified against the shipped API The pages track conductor `main` as of the `applicationName` revert (dbos-inc/dbos-conductor#187) and the CLI as of dbos-inc/dbos-ctl#8 and #9: - the `listWorkflows` query parameters and the full workflow-search body field list match the spec exactly; - all 64 operations appear in the endpoint tables, and all 16 OAuth-gated operations are named by operation ID; - `applicationName` is documented as a **response** field only — the request filters were removed by #187; - install instructions follow the `dbos-cli` → `dbos-ctl` repository rename and lead with the new install script. The site builds. The only broken-anchor warnings are pre-existing ones on the Go reference pages, untouched by this branch. ## One sequencing note The `dbosctl` page links to the CLI's releases page and its `raw.githubusercontent.com` install script, both of which are only reachable once that repository is public and a release is tagged. The page carries an early-access admonition, so it is not misleading in the meantime, but this probably wants to land alongside that flip. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.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.
Re-vendors
internal/api/openapi-3.1.jsonfrom conductormainand follows the API where it moved. The vendored spec is now byte-identical to whatdbosdev/conductor:latestemits from itsopenapisubcommand.Changes
client.gen.go.permission listloses its client-side OAuth gate. conductor madelistPermissionsreachable without OAuth (dbos-inc/conductor#177), so the mode-aware error ininternal/cli/permission.gowas rejecting a call that now works. The gate table regenerates fromx-dbos-requires-oauth, so this follows automatically — 16 gated operations remain.applicationNamein the workflow, queue, and schedule detail views.main(Run the integration tests against the published conductor image #7), picking up the image-based integration harness.api-compatCI job — see below.api-compatThe existing drift check (
make generate && git diff --exit-code) is hermetic: it proves the vendored spec and the committed client agree, which stays true no matter how far a deployed API moves. Nothing noticed when an upstream server changed shape.This job regenerates the client from each upstream spec and builds it:
dbosdev/conductor:latest— the image the integration tier already runs against./conductor/v2/openapi.json— not a separate spec. Cloud fetches conductor's live spec and rewrites onlyservers(~/cloud/controllers/public/conductor/openapi.go), so this tracks whichever conductor cloud has actually deployed, which lags the released image. The pair brackets the range of servers a released CLI must work against.The cloud target fails today, for a known and benign reason. Production still advertises the
applicationNamefilters conductor reverted in dbos-inc/conductor#187, so generating from it adds a params argument:That is a codegen incompatibility, not a runtime one — the parameters are optional and the current CLI talks to cloud fine. It also retroactively validates reverting
--owner-appon this branch: had it stayed, it would compile against cloud and break againstlatest.So the job is advisory (
continue-on-error). It is sensitive by construction — oapi-codegen renders query parameters as a params-struct argument, so upstream adding one optional parameter fails the build here while the API stays backward compatible. Worth surfacing, not worth failing an unrelated PR over. It writes the spec delta to the step summary, and a failed fetch warns rather than reporting a compatibility problem we never observed.It triggers on PR and push, like the rest of
ci.yml— so it does not catch upstream changes that land while the repo is quiet. Aschedule:trigger would; left off deliberately, since the daily drift check was dropped as belonging in conductor.Verification
Run locally on the merged branch:
make generate+ driftmake lintmake test-integrationdbosdev/conductor:latestlatestspecNote for the reviewer
The history has add-then-undo churn —
--owner-appis added in5b49980and reverted indadb450; the spec-drift check is added ind697f10and removed across4c67e96and85826cd. Squash-merging is probably what you want.🤖 Generated with Claude Code