Skip to content

chore: resync the production spec and document the two generators - #4

Merged
justinwlin merged 4 commits into
mainfrom
chore/spec-resync-pagination
Sep 24, 2026
Merged

justinwlin merged 4 commits into
mainfrom
chore/spec-resync-pagination

Conversation

@justinwlin

@justinwlin justinwlin commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

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-sdk stays at 0.1.1 for consumers. This adds the minor changeset so the update can actually ship.

That matters right now: runpod-mcp pins this package and bundles it, and its hand-written list tools can't pass the new cursor/limit parameters 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 runs changeset version before opening the PR. Changesets already pending on main are folded into the same version.
  • release.mjs: automation/production-spec now counts as a release branch alongside changeset-release/main. It must be a same-repo branch merged into main, as before.
  • version.yml: the release check now runs on every push to main. 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.
  • The automated changelog entry includes the date and a link to the validation run. To ship a bigger bump than minor, land that changeset on main and run the workflow again.
  • Nothing merges automatically. A person still reviews and merges.

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-endpoints and list-templates are hand-written and call the typed client here, so passing cursor/limit or reading pagination.nextCursor fails tsc against 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
scripts/sync_spec.py --check    Vendored spec matches normalized production OpenAPI.
scripts/generate.mjs --check    Generated schema is current.
pnpm typecheck                  clean
pnpm test                       61 passed, 1 skipped
node --test scripts/test_query_contract.mjs   pass
npm run test:release            5 passed (incl. the new release branch, and its fork rejection)
npm run test:scripts            8 passed

I ran the new version step on a copy of main with a changed spec and one pending changeset. It bumped 0.1.1 → 0.2.0, wrote both entries to CHANGELOG.md, deleted both changesets, and left pnpm-lock.yaml unchanged.

The regenerated schema carries nextCursor and hasNextPage, the cursor/limit query parameters on the paginated paths, and the five account-secret operations.

🤖 Generated with Claude Code

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
lukepiette previously approved these changes Sep 22, 2026

@lukepiette lukepiette left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approving. Verified locally on the branch:

  • git diff origin/automation/production-spec is 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; ListPodsResponse and ListTemplatesResponse still exist, and the required lists only gain pagination.
  • The runpod-mcp claims are accurate: the pin is exactly 0.1.1 under devDependencies and src/specgen/generated/tools.gen.ts exists.
  • version.yml runs 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.

Comment thread docs/development.md Outdated
Comment on lines +81 to +82
query parameters it accepts, and what shape comes back. Everything around it —
retries, deadlines, rate-limit metadata, the SSE iterator — is written by hand.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 lukepiette left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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), and test: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 main with the PR's spec applied and its changeset pending. It went 0.1.1 to 0.2.0, wrote both entries to CHANGELOG.md, deleted both changesets, and left pnpm-lock.yaml untouched. Everything git status showed is covered by add-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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread .github/workflows/spec-drift.yml Outdated
'@runpod/typescript-api-sdk': minor
---

Refresh the vendored production spec and regenerate the types.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Comment thread docs/development.md Outdated
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.
@justinwlin
justinwlin merged commit 71be666 into main Sep 24, 2026
6 checks passed
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.

2 participants