Skip to content

fix(docs): restore api-reference URL continuity and fix translated SDK bodies - #6617

Merged
waleedlatif1 merged 1 commit into
stagingfrom
fix/docs-api-reference-continuity
Aug 12, 2026
Merged

fix(docs): restore api-reference URL continuity and fix translated SDK bodies#6617
waleedlatif1 merged 1 commit into
stagingfrom
fix/docs-api-reference-continuity

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

Swapping the docs from the single v1 apps/docs/openapi.json to the seven code-first v2 specs changed the set of generated operation pages. Page identity is derived, not authored — fumadocs-openapi mounts every operation at <baseDir>/<slugify(tag)>/<operationId>.mdx — so renaming an operationId or retiring an operation silently changes a public URL. Two things shipped unguarded:

  • 32 published operation pages 404 with no redirect. Recomputing both slug sets the way fumadocs does gives 52 slugs from the deleted v1 spec and 128 from the seven v2 specs; exactly 32 v1 slugs have no v2 equivalent. Every one was a live, sitemap-listed page.
  • Ten translated snippets return a deterministic 400. The de/es/fr/ja/zh api-reference/typescript.mdx and python.mdx streaming examples were repointed at POST /api/v2/workflows/{id}/execute but still POST message at the root of the body. ExecuteWorkflowRequest is additionalProperties: false with input nested under input, so a root message is rejected outright. The English pages were already correct; the translations were not updated with them.

This adds the 32 redirect rules, fixes the ten snippets to match the English page and the v2 contract, and adds a test that pins the map against the specs.

Why the spec swap itself is not reversible

bun run check:openapi cross-checks the seven generated specs against the runtime contracts — 128 operations, 130 contracts, 225 examples validated against the published JSON Schema. The specs are generated from the v2 contracts, so restoring the v1 operation pages would mean hand-maintaining a spec CI no longer derives from anything. Redirects are the only continuity mechanism available.

308 vs 307

permanent: true (308) is cached indefinitely by browsers and is effectively unrecallable, so it is reserved for a true 1:1 successor — the same operation, renamed.

21 are 308. Each is the same operation at the versioned successor path with a renamed operationId, checked operation-by-operation against both specs. The one that looks wrong is tables/updateRowstables/updateTableRows, where the method flips PUTPATCH. It is still 1:1: v1 PUT /rows and v2 PATCH /rows take the identical workspaceId / filter / data / limit predicate body. v1's other row-batch endpoint, PATCH /rows (batchUpdateRows, an array of {rowId, data}), has no v2 successor and is handled below.

11 are 307, because each is a semantic approximation rather than a rename:

Source Why not permanent
files/uploadFilefiles/createFile v1 took multipart up to 100MB; v2 takes inline UTF-8/base64 and defers larger payloads to an upload session
human-in-the-loop/*workflow-runs/* the tag is retired — pause state is a field on the run resource, not its own endpoint family
logs/getLogDetails, logs/getExecutionDetailslogs/getLog two v1 identifiers collapse onto one v2 runId
tables/batchUpdateRowstables/updateTableRows v1 updated a batch by row id; v2 has only the predicate form
usage/getUsageLimitsbilling/getBillingStatus v2 billing status carries plan, credit allowance and storage quota, but not rate limits
workflows/getJobStatusworkflow-runs/getWorkflowRunV2 no v2 successor at all; the v2 queue receipt's statusUrl points at the run endpoint, the closest poll target

The test is the durability guarantee

The map is only correct relative to the specs, and nothing else in the repo reads docs URLs — a spec regeneration can invalidate it in two directions with no build error, no type error, and no other failing check:

  • a source can start shadowing a page that now exists (the redirect wins, hiding a real page);
  • a destination can stop resolving (the redirect lands on a 404 — worse than the 404 it replaces).

scripts/openapi/docs-redirects.test.ts recomputes the slug set from OPENAPI_SPEC_FILES the way fumadocs does and pins both directions against the same set, plus a guard that every /api-reference/ rule is a literal path — a :param would make the slug checks vacuous. All three assertions were verified to genuinely fail when broken: a destination pointing at a non-existent slug, a source shadowing a generated page, and a source shadowing a hand-authored page (/api-reference/getting-started) each turn the suite red. It runs in CI via check:openapicheck:audits.

Its HTTP_METHODS mirrors fumadocs-openapi's methodKeys, which is narrower than the OpenAPI method set — options and trace produce no page, so they must not count as resolvable destinations.

No locale-prefixed sources: generated pages mount only under baseDir: 'en/api-reference/(generated)' and hideLocale: 'default-locale' strips the en prefix, so a /de/api-reference/… rule would be dead.

Why redirects.ts is a separate module

This is the one change here that is a refactor rather than a fix, so the reasoning, explicitly — I tested both halves before extracting rather than assuming:

The test cannot import next.config.ts. createMDX() runs at module scope and bundles source.config.ts against process.cwd(). Importing the config from the root Vitest project fails with The entry point "source.config.ts" cannot be marked as external and the run exits 1 — via both a static and a dynamic import. Note the failure is asynchronous, so the suite prints "passed" and then exits non-zero; it is only visible in the exit code.

The whole table moved, not just the new block, because Next applies the first matching rule. Splitting one ordered list across two modules and concatenating them makes match order an emergent property of two files.

The 143 pre-existing rule lines moved verbatim — a diff of the old block against the new one is empty except for one deliberate line, disclosed here rather than buried: /execution/form pointed at /deployment/form, which is itself a redirect source, so that URL served 308 → 308 → page. It now points at the final destination. Same endpoint for the user, one fewer round trip, and it stops being a permanently-cached 404 if the second rule is ever removed. No other rule in the table now redirects to a literal redirect source.

Net: next.config.ts drops from 175 to 32 lines and holds configuration rather than data.

Type of Change

  • Bug fix

Testing

  • bun run check:openapi green (31 tests, 3 files) — includes the new suite.
  • Re-proved red three ways: broken destination, source shadowing a generated page, source shadowing a hand-authored page. Each fails the specific assertion; restoring returns a clean tree.
  • Independently recomputed the v1 and v2 slug sets from the specs: 32 retired slugs, 32 rules, zero uncovered, zero shadowing a live v2 page, zero broken destinations.
  • Verified each 308's source and destination resolve to the same operation in the two specs, and each 307's does not.
  • bun run type-check in apps/docs green; biome clean.

Question for the owner

All 82 /api/v1 route files still exist on staging, so v1 remains a live public API that now ships with zero reference documentation, while the v2 surface that replaced it in the docs sits behind an off-by-default flag. Is that the intended end state or transitional? This PR restores URL continuity either way, but the answer changes whether the 21 permanent redirects should be permanent, and whether v1 warrants its own reference section rather than a redirect into v2.

Follow-ups, not this PR

Deliberately out of scope — same files, different defect (SDK signature drift from the v2 migration, not request-body shape), and roughly 10× the size:

  • The five translated api-reference/python.mdx pages each use input_data= as the execute_workflow kwarg in 10 places; the shipped kwarg is input. 50 samples that raise TypeError before a request is made. English uses input_data only as a local variable name, correctly.
  • The five translated api-reference/typescript.mdx pages each use a merged executeWorkflow('id', { input, stream, async }) single-object form in 13 places; the shipped signature is executeWorkflow(workflowId, input, options). de/es/fr/ja also check 'taskId' in result where English checks 'async' in result.
  • No translation-sync mechanism exists to fix this at the tool level. apps/docs/i18n.json declares lingo.dev, but i18n.lock has not moved since feat(i18n): change lockfile #3216, nothing in .github/workflows/ references it, and ci.yml paths-ignores apps/docs/content/**. Hand-editing is the established path.
  • The ja and zh SDK pages still document the 0.1.x API.
  • Five orphaned locale sdks/*.mdx pages remain whose English copy was deleted earlier — there is no content/docs/en/sdks/.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…K bodies

Two docs-only defects introduced by #5273 (`263e3ca67e`), which re-founded the
public API reference on the v2 surface.

1. Ten translated SDK snippets produce a deterministic 400.

The streaming example in the five translated `api-reference/typescript.mdx` and
`python.mdx` pages was repointed from `/api/workflows/{id}/execute` to
`/api/v2/workflows/{id}/execute` and nothing else was changed — fr/ja/zh
typescript.mdx are literally one-line diffs. `message` stayed at the body root.
That was correct against v1, whose route treats the whole non-control body as
workflow input, but `v2ExecuteWorkflowBodySchema` ends in `.strict()` and the
route parses before executing, so every copied snippet returns
`400 Unrecognized key: "message"`. The same commit fixed the English bodies to
`input: { … }`, so this is an oversight, not a decision. The ten fences now
match `en/api-reference/typescript.mdx:959` and `python.mdx:681`.

Not relaxing `.strict()`: it is deliberate house style across the v2 contract
and is what makes a typo'd option fail loudly instead of silently.

2. Thirty-two published operation pages 404 with no redirect.

Replacing the single v1 `openapi.json` with seven v2-only specs changes page
identity, because fumadocs derives every generated page as
`slugify(tag)/operationId` from the specs at build time. Re-deriving both sets
gives 52 old slugs and 128 new ones: 32 disappear and 20 keep their URL while
silently retargeting v1 -> v2 (`knowledge-bases/updateKnowledgeBase` also flips
PUT -> PATCH). All 52 are in the live sitemap — parsing `<loc>` from
docs.sim.ai/sitemap.xml gives 458 URLs of which 56 are `/api-reference/`: the
four static pages plus all 52 generated ones by name, including every one of
the 32 that die. They are 200 today under an allow-all robots.txt.

The spec swap itself is deliberate and CI-enforced (`check-openapi-specs.ts`
requires every published operation under `/api/v2/`), so restoring the v1
operations is not an option. The missing piece is the redirect map, in a file
that already carried 56 such rules from earlier doc moves.

`permanent: true` (308) is used only for a true 1:1 successor — same operation,
renamed. A 308 is cached indefinitely and effectively unrecallable, so anything
that collapses two pages onto one, changes the identifier model, or lands on a
merely adjacent operation is `permanent: false` (307). That splits 21/11.

Four destinations differ from the mapping proposed in review, each on evidence
from the specs rather than from the operation names:

- `workflows/getJobStatus` is not destination-less. The v2 queued-execution
  receipt (`QueuedWorkflowRun`) returns `statusUrl`
  `/api/v2/workflows/{id}/runs/{runId}`, so `workflow-runs/getWorkflowRunV2` is
  the successor poll target — far better than a generic landing page.
- The three HITL read operations go to `getWorkflowRunV2`, not to the resume
  page: `WorkflowRunStatus` carries a `paused` object with `contextId`,
  `pausedAt`, and `pauseKind`. Pointing a GET doc at a POST doc would be wrong.
- `human-in-the-loop/listPausedExecutions` goes to `listWorkflowRunsV2`, whose
  `status` filter includes `paused`.
- `tables/batchUpdateRows` is 307, not 308. v2 `updateTableRows` is "Update Rows
  by Filter" — the successor of v1 `updateRows` (PUT, predicate-based), which
  keeps its 308. v2 has no by-id batch update at all, so batchUpdateRows lands
  on a genuinely different operation.

3. A guard, so the map cannot rot silently.

`scripts/openapi/docs-redirects.test.ts` recomputes the generated slug set the
way fumadocs does and asserts no `/api-reference/` source shadows a live page
and every destination resolves. Nothing else in the repo reads docs URLs, so a
future spec regeneration would otherwise break the map with no signal. It needs
no wiring: `check-openapi.ts` already runs this vitest config.

The redirect array moves to `apps/docs/lib/redirects.ts` because the guard
cannot import `next.config.ts` — `createMDX()` runs the fumadocs-mdx generator
at import time, which made vitest emit an unhandled build error and warn about
false positives. The 56 pre-existing rules are byte-identical to before,
verified programmatically; `next.config.ts` keeps the same public shape and
Next's own `checkCustomRoutes` accepts all 88 rules.

Open question for the owner, larger than the redirects: all 82 `/api/v1`
route files survive on staging, so a live public API now ships with zero
reference docs, while the documented `/api/v2` surface returns 404 for any
caller outside the off-by-default `v2-api` flag cohort. Is that the intended
end state or transitional?
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 12, 2026 8:52am

Request Review

@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Docs-only, but introduces many public URL redirects including permanent 308s that browsers cache indefinitely if a mapping is wrong. No runtime, auth, or data-path changes.

Overview
Restores continuity for 32 retired v1 /api-reference/ operation pages that 404'd after the docs moved to the seven code-first v2 OpenAPI specs, and fixes broken streaming examples in translated SDK docs.

Redirects: Moves the full docs redirect table into apps/docs/lib/redirects.ts (so tests can import it without loading next.config.ts) and adds 32 /api-reference/ rules—21 permanent (308) for true operationId renames, 11 temporary (307) for approximate successors. Also points /execution/form at its final destination instead of chaining through another redirect.

SDK snippets: Updates de/es/fr/ja/zh Python and TypeScript streaming examples to nest message under input, matching the v2 ExecuteWorkflowRequest contract (English was already correct).

Guardrail: Adds scripts/openapi/docs-redirects.test.ts to assert api-reference redirect sources never shadow live pages and destinations always resolve against the generated specs.

Reviewed by Cursor Bugbot for commit c19e849. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR restores continuity for retired API-reference URLs and corrects translated workflow-execution request examples.

  • Extracts the ordered docs redirect table into an importable module and adds 32 v1-to-v2 API-reference redirects.
  • Adds tests ensuring API-reference redirect sources do not shadow current pages and destinations resolve against generated or static pages.
  • Nests translated streaming-example messages under the v2 request body's input field.

Confidence Score: 5/5

The PR appears safe to merge with no actionable changed-code defects identified.

The translated examples now match the v2 request shape, the redirect table remains ordered when extracted, and the added checks cover source shadowing and destination resolution without an established mismatch from actual docs generation.

Important Files Changed

Filename Overview
apps/docs/lib/redirects.ts Extracts the existing ordered redirect table and adds literal API-reference continuity mappings with permanent redirects reserved for claimed one-to-one successors.
apps/docs/next.config.ts Replaces the inline redirect array with the imported DOCS_REDIRECTS table without changing the surrounding Next configuration.
scripts/openapi/docs-redirects.test.ts Derives resolvable API-reference slugs from the configured specs and static pages, then checks redirect literals, source shadowing, and destination validity.
apps/docs/content/docs/de/api-reference/python.mdx Corrects the translated Python streaming request body by nesting workflow input under input.
apps/docs/content/docs/de/api-reference/typescript.mdx Corrects the translated TypeScript streaming request body by nesting workflow input under input.
apps/docs/content/docs/es/api-reference/python.mdx Corrects the translated Python streaming request body by nesting workflow input under input.
apps/docs/content/docs/es/api-reference/typescript.mdx Corrects the translated TypeScript streaming request body by nesting workflow input under input.
apps/docs/content/docs/fr/api-reference/python.mdx Corrects the translated Python streaming request body by nesting workflow input under input.
apps/docs/content/docs/fr/api-reference/typescript.mdx Corrects the translated TypeScript streaming request body by nesting workflow input under input.
apps/docs/content/docs/ja/api-reference/python.mdx Corrects the translated Python streaming request body by nesting workflow input under input.
apps/docs/content/docs/ja/api-reference/typescript.mdx Corrects the translated TypeScript streaming request body by nesting workflow input under input.
apps/docs/content/docs/zh/api-reference/python.mdx Corrects the translated Python streaming request body by nesting workflow input under input.
apps/docs/content/docs/zh/api-reference/typescript.mdx Corrects the translated TypeScript streaming request body by nesting workflow input under input.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  OldURL[Retired API-reference URL] --> Redirects[DOCS_REDIRECTS]
  Redirects --> CurrentPage[Current generated API page]
  Specs[Seven v2 OpenAPI specs] --> GeneratedSlugs[Generated slug set]
  StaticPages[Hand-authored API pages] --> ResolvableSlugs[Resolvable slug set]
  GeneratedSlugs --> ResolvableSlugs
  ResolvableSlugs --> Tests[Redirect continuity tests]
  Redirects --> Tests
Loading

Reviews (1): Last reviewed commit: "fix(docs): restore api-reference URL con..." | Re-trigger Greptile

@waleedlatif1
waleedlatif1 merged commit 47f1430 into staging Aug 12, 2026
23 of 24 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/docs-api-reference-continuity branch August 12, 2026 08:50
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