chore: resync the production spec and document the two generators - #4
Conversation
Pulls the production OpenAPI and regenerates src/generated/schema.ts, which is byte-identical to the daily automation branch (automation/production-spec, PR #3). The upstream additions are cursor pagination on the list endpoints and the account-secrets paths, both additive. Adds the changeset the automation deliberately does not write: without one, a merged spec update never reaches npm, so a consumer pinning this package cannot take up the new types. Documents the relationship with runpod-mcp in docs/development.md. Both repos generate from the same spec — this one emits types, the MCP server emits tool definitions — and the MCP server's hand-written tools call this SDK, so an upstream change has to be taken up in both, in order. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lukepiette
left a comment
There was a problem hiding this comment.
Approving. Verified locally on the branch:
git diff origin/automation/production-specis limited to the changeset and the docs section, so the spec and schema really are identical to #3.sync_spec.py --check,generate.mjs --check,pnpm typecheck,pnpm test(61 passed, 1 skipped),test_query_contract.mjs, and the Python spec tests all pass.- The changeset's "additive" claim holds. Deleted lines in the spec diff are description rewrites and moved lines;
ListPodsResponseandListTemplatesResponsestill exist, and therequiredlists only gainpagination. - The runpod-mcp claims are accurate: the pin is exactly
0.1.1under devDependencies andsrc/specgen/generated/tools.gen.tsexists. version.ymlruns on push to main via changesets/action, so merging this opens a Version Packages PR. Publishing still needs that second merge.
Two non-blocking nits, one inline on the docs and one here:
The description says runpod/runpod-mcp#98 "vendored the same spec and regenerated its tool surface, so its generated tools already paginate." #98 is still open, so nothing there paginates yet. Worth rewording so the sequencing reads correctly for whoever picks this up later.
| query parameters it accepts, and what shape comes back. Everything around it — | ||
| retries, deadlines, rate-limit metadata, the SSE iterator — is written by hand. |
There was a problem hiding this comment.
Nit: house style avoids em dashes in docs. Commas or a colon read the same here, e.g. "Everything around it (retries, deadlines, rate-limit metadata, the SSE iterator) is written by hand." Same applies at lines 86, 96, and 99.
The update PR now carries a minor version bump and changelog entry, and the release workflow accepts a merge from automation/production-spec as a release.
lukepiette
left a comment
There was a problem hiding this comment.
Approving again on the new head. Verified locally on 6b7f458:
- Spec and schema are still byte-identical to
origin/automation/production-spec; the diff against it is only the changeset, the docs, and the new CI/release files. generate.mjs --check,pnpm typecheck,pnpm test(61 passed, 1 skipped),test:release(5 passed, including the new branch and its fork rejection), andtest:scripts(8 passed) all pass. The Node 20/22/24 matrix is green on GitHub.- I ran the new "Version the spec update" step verbatim on a copy of
mainwith the PR's spec applied and its changeset pending. It went 0.1.1 to 0.2.0, wrote both entries toCHANGELOG.md, deleted both changesets, and leftpnpm-lock.yamluntouched. Everythinggit statusshowed is covered byadd-paths, including the changeset deletion. - Both em-dash nits from the last round are addressed.
One thing worth fixing soon, inline on the version step: version.yml gates the publish on has_changesets == 'false', so a changeset landing on main between the daily run and the merge of the spec PR silently skips the publish that the PR body promises. It's recoverable and doesn't block this, but it's a one-line change in version.yml, and I'd do it before the team starts relying on "merging the bot PR releases."
The rest are non-blocking notes on the generic changelog entry, the hard-coded minor, and a wrap nit in the docs.
Small description nit: it still says #3 is open since Sept 18 and that the automation will close it on its next run. You closed #3 yourself today, so that paragraph can go.
| - run: pnpm test:examples | ||
| # The update PR carries its own version bump and changelog, so merging it | ||
| # releases. Main's pending changesets are consumed into the same version. | ||
| - name: Version the spec update |
There was a problem hiding this comment.
This is the one I'd fix before relying on the new flow.
version.yml only runs the eligibility and publish jobs when has_changesets == 'false'. That holds if main had nothing pending when this branch was last regenerated. But the branch is only refreshed once a day, so there's a window of up to 24 hours where a changeset merges to main after the 09:23 UTC run and before someone merges the spec PR.
In that case the merge commit has package.json at 0.2.0, a ## 0.2.0 changelog entry, and one unconsumed changeset. changesets/action reports hasChangesets: true, eligibility is skipped, nothing publishes, and a new Version SDK PR opens at 0.3.0. So 0.2.0 exists in the changelog but never reaches npm, and the PR body's "merging it publishes" is wrong for that merge with no signal beyond a skipped job. (The existing changeset-release/main flow doesn't have this problem in practice because the action re-pushes that branch on every push to main.)
Suggested fix: drop the has_changesets == 'false' condition on the eligibility job in version.yml. release.mjs plan already requires a merged PR from a release branch whose merge commit is exactly this SHA, so evaluating it on every push to main is safe, and in the race case it publishes 0.2.0 while the version job opens the 0.3.0 PR in parallel. Happy for that to be a follow-up if you'd rather keep this PR to what it is.
| '@runpod/typescript-api-sdk': minor | ||
| --- | ||
|
|
||
| Refresh the vendored production spec and regenerate the types. |
There was a problem hiding this comment.
Non-blocking. Every automated release will get this exact line in CHANGELOG.md, and release.mjs copies the same block into the GitHub release notes, so consumers get no hint of what changed between 0.2.0 and 0.3.0.
Cheap improvement: put the validation run URL (or the date) in the changeset body. The heredoc is quoted, so you'd pass ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} in via env: and reference it with printf or an unquoted heredoc.
| fi | ||
| cat > .changeset/production-spec-update.md <<'EOF' | ||
| --- | ||
| '@runpod/typescript-api-sdk': minor |
There was a problem hiding this comment.
Non-blocking, design note. This replaces "classify the bump explicitly" with a fixed minor. On 0.x that's the right maximal choice, since caret ranges don't cross a 0.x minor anyway. After 1.0 a removed operation would still ship as a minor.
The escape hatch already exists: land a major changeset on main and re-dispatch this workflow, and Changesets takes the highest bump. Worth one sentence in docs/development.md so a reviewer of a bot PR knows to do that instead of editing the bot branch, which gets overwritten.
| version bump and changelog entry, consuming any changesets pending on the | ||
| default branch. Merging it publishes that version (see | ||
| [releases](releases.md)). Nothing merges automatically, so review the | ||
| compatibility impact before merging. Bot-branch edits can be overwritten on the next refresh; land durable fixes on |
There was a problem hiding this comment.
Nit: this line runs well past the 80-column wrap the rest of the file uses.
Also dates the automated changelog entry and links its validation run, and documents how to force a larger bump than minor.
Takes up the production spec (cursor pagination on the list endpoints, plus the account-secrets paths) and documents how this repo's generation relates to the MCP server's.
What the automation does not do is write a changeset, by design — it never versions or publishes. So #3 on its own lands types that never reach npm, and
@runpod/typescript-api-sdkstays at 0.1.1 for consumers. This adds theminorchangeset so the update can actually ship.That matters right now:
runpod-mcppins this package and bundles it, and its hand-written list tools can't pass the newcursor/limitparameters until a published version carries the types.The docs section (
docs/development.md→ "The other generator: runpod-mcp") explains the split — this repo generates types for the compiler, the MCP server generates tool definitions read at runtime by a language model — and that an upstream change is normally taken up twice, SDK first. Nothing documented that relationship in either repo, which is how a resync ends up looking complete while half a surface is stale.Merging the daily spec PR now releases it
The daily spec PR (like #3) now carries a minor version bump and changelog entry, so merging it publishes to npm. You no longer need a separate changeset and "Version SDK" PR.
spec-drift.yml: when the spec changed, it writes a changeset and runschangeset versionbefore opening the PR. Changesets already pending onmainare folded into the same version.release.mjs:automation/production-specnow counts as a release branch alongsidechangeset-release/main. It must be a same-repo branch merged intomain, as before.version.yml: the release check now runs on every push tomain. So a spec PR merge still publishes when changesets from other PRs landed after the bot's last refresh. Those go into the next version PR.mainand run the workflow again.This PR itself still goes through the existing flow: merging it opens the Version SDK PR for 0.2.0.
What this unblocks
runpod/runpod-mcp#98 (still open) vendors the same spec and regenerates its tool surface. Once it merges, its generated tools (
list-pods,list-endpoint-releases,list-endpoint-builds) paginate without this release, because they dispatch from the spec and never consult these types.Its curated tools cannot.
list-endpointsandlist-templatesare hand-written and call the typed client here, so passingcursor/limitor readingpagination.nextCursorfailstscagainst the pinned 0.1.1.So once this merges and is released to npm, the sequence there is: bump the pin, then teach those two handlers the new parameters. Merging this without a release does not unblock anything — which is why the changeset matters here more than the regenerated types.
Verification
I ran the new version step on a copy of
mainwith a changed spec and one pending changeset. It bumped 0.1.1 → 0.2.0, wrote both entries toCHANGELOG.md, deleted both changesets, and leftpnpm-lock.yamlunchanged.The regenerated schema carries
nextCursorandhasNextPage, thecursor/limitquery parameters on the paginated paths, and the five account-secret operations.🤖 Generated with Claude Code