You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e3aa111
Browse filesBrowse the repository at this point in the historyBrowse files
docs(spec): name only the OpenAPI document where the retired /docs viewer page was named (#25162)
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wg6zwDuV2XvoDkqC7bXgqnpc)_Fixes#25121
Clause-②: no
Metadata-protocol: none
## What changed
`main` no longer serves the OpenAPI document's HTML viewer page (`GET
{basePath}/docs`, retired by PR #25124, `1b3b65e64`). `registerRoutes`
gates `registerOpenApiEndpoints` on `api.enableOpenApi`, and that
registrar now mounts one route, `GET {basePath}/openapi.json`
(`packages/rest/src/discovery-routes.ts`, read at `origin/main`
`23540582f`). The spec text that still named the viewer now names the
OpenAPI document only:
| Site | Before | After |
|:---|:---|:---|
| `rest-server.zod.ts`, `enableOpenApi` TSDoc | `openapi.json` plus
"`GET {basePath}/docs` for a zero-dep Scalar-rendered HTML viewer" | the
one endpoint, `GET {basePath}/openapi.json` |
| `rest-server.zod.ts`, `enableOpenApi` describe | "Enable OpenAPI 3.1
spec & docs viewer endpoints" | "Enable the OpenAPI 3.1 document
endpoint (`GET BASEPATH/openapi.json`)" |
| `rest-server.zod.ts`, `documentation.enabled` tombstone prescription |
"…leaves the `/openapi.json` document and its `/docs` viewer unmounted."
| "…leaves the `/openapi.json` document unmounted." |
| `liveness/rest_api.json`, `enableOpenApi` evidence | "mounts both
`/openapi.json` and the `/docs` viewer" | "mounts `/openapi.json`, the
OpenAPI document"; `verifiedAt` restamped 2026-10-22 (call graph
re-closed against `origin/main`) |
| `scripts/lib/openapi-self-consistency.ts`, rule 1 comment and the
dangling-ref refusal | named "the Scalar viewer at GET /api/v1/docs" as
a consumer | names the document at `GET /api/v1/openapi.json` and client
generators |
| `migrations/entries/semantic/18.rest-api-config-dead-keys-retired.ts`,
`replacement` and `acceptanceCriteria` | "the OpenAPI document and the
docs viewer", "`GET /openapi.json` and `GET /docs` unmounted" | the
OpenAPI document only, "`GET /openapi.json` unmounted" |
Regenerated: `gen:schema` (no tracked change), `gen:docs` →
`content/docs/references/api/rest-server.mdx` (the two describe rows and
the prescription row). One `patch` changeset for `@objectstack/spec`:
`.changeset/25121-spec-openapi-viewer-prose.md`.
The `documentation.enabled` refusal is an accept-set no-op: same key
refused, same issue path, same opening sentence; only its last clause
changed. The two pins that read the prescription
(`packages/spec/src/api/rest-api-config-dead-keys-retirement.test.ts`
`DOCS_ENABLED_PRESCRIPTION` and
`packages/rest/src/rest-api-config-dead-keys-refused.test.ts`) match up
to "`api.enableOpenApi: false` is the switch", which the new text keeps,
so neither needed a flip. Both are green below.
## Tests (at `32bfe10cd`, the final head)
- `pnpm --filter @objectstack/spec test` (lock VERDICT command-exit 0):
Test Files 706 passed (706), Tests 21462 passed, 1 todo.
- `pnpm --filter @objectstack/spec typecheck` (lock VERDICT command-exit
0).
- `pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2
src/rest-api-config-dead-keys-refused.test.ts
src/rest-docs-viewer-retired.pin.test.ts` (lock VERDICT command-exit 0):
Test Files 2 passed, Tests 17 passed.
- `pnpm --filter @objectstack/spec check:generated`: exit 0, all 14
artifacts up to date (it was red on `check:docs` before `gen:docs`).
- No ablation: no tested behaviour changed (description, TSDoc, comment
and prescription text only).
## Gates
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `32bfe10cd` derived 111 commands; each
was run with its exit code recorded before any pipe. `--ran`
reconciliation: "111 derived famil(ies) accounted for — 110 run, 1
NOT-MEASURED (1 DERIVED from a recorded exit 3)".
- 110 exit 0. Five first exited 3 (prerequisite not met: the
lint/formula, client-react and objectql dists were unbuilt, and
`check:exported-any` / `check:generated` had read a spec dist while a
concurrent turbo build was rewriting it). They were re-run green after
the builds.
- NOT MEASURED: `pnpm check:dual-build-cjs-loads`, exit 3. It needs
every workspace package built, and this worktree built only the spec,
lint, formula, objectql and client-react closures. `Lint & Repo Gates`
runs it in CI.
- Local-only families: `check:skill-frame-freshness` exit 0.
`check:dev-prereqs` exit 1, NOT MEASURED: it reports "the workspace is
not built" (33 of 70 packages have no dist) and names no stale spec
dist. That is the box's state, not a finding.
- CI-owned families (the farm, Test Core, Build Core, Build Docs,
type-check lanes): this PR's check-runs.
## Acceptance notes
- Out of scope by the claim and untouched: `ApiTestingUiConfigSchema`
(`ApiDocumentationConfigSchema.ui`, `documentation.zod.ts`, viewer enum
including `'scalar'`) and `OpenApiGenerationConfigSchema.uiPath`
(`plugin-rest-api.zod.ts`, default `/api/docs`, echoed by
`REST_API_PLUGIN.md`). Measured at `origin/main` `23540582f`, `git grep
-w` outside `packages/spec`, the generated references and the changelogs
finds no reader of either. `ApiDocumentationConfig` appears once, in a
comment at `packages/runtime/src/http-dispatcher.ts:3061`. `uiPath`
appears once, as an unrelated local variable at
`packages/rest/src/ui-routes.ts:79`. `RestApiPluginConfig` in
`packages/rest` is its own interface (`rest-api-plugin.ts:94`), not the
spec schema. The seat files these as their own card.
- The changeset `.changeset/25077-rest-docs-viewer-attr-escape.md`
(already on `main`) describes a viewer fix to a page that has since been
retired. It is release-owned input, so it is not touched here.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01B2EeooonSXrANpkpgUSfFZ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
docs(spec): `api.enableOpenApi` and the `api.documentation.enabled` refusal name only the OpenAPI document; the retired docs viewer page is no longer described
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
The REST server no longer serves an HTML viewer page at `GET {basePath}/docs`; it serves the machine-readable OpenAPI document at `GET {basePath}/openapi.json`, gated by `api.enableOpenApi`. The spec text now says only that:
11
+
12
+
-**`RestApiConfigSchema.enableOpenApi`.** The description read "Enable OpenAPI 3.1 spec & docs viewer endpoints", and the TSDoc named a Scalar-rendered viewer at `GET {basePath}/docs`. Both now name the one endpoint the flag mounts, `GET {basePath}/openapi.json`.
13
+
-**The `api.documentation.enabled` refusal.** Its prescription said `api.enableOpenApi: false` leaves "the `/openapi.json` document and its `/docs` viewer unmounted". It now says the switch leaves the `/openapi.json` document unmounted. The key is refused exactly as before, at the same path, with the same opening sentence; only the closing words changed.
14
+
-**The `rest-api-config-dead-keys-retired` upgrade entry** (shown by `os migrate meta` and the upgrade guide) drops the viewer from its replacement and acceptance text the same way.
15
+
16
+
No schema accepts or refuses anything new, no default changes, and no export moves.
@@ -257,7 +257,7 @@ const result = BatchEndpointsConfigSchema.parse(data);
257
257
258
258
| Property | Type | Required | Description |
259
259
| :--- | :--- | :--- | :--- |
260
-
|**enabled**|`never`| optional |[REMOVED]`api.documentation.enabled` was removed in @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — nothing ever read it: whether the server publishes its OpenAPI document is decided by the sibling `api.enableOpenApi` at the mount, so `enabled: false` turned nothing off. Delete the key; `api.enableOpenApi: false` is the switch that leaves the `/openapi.json` document and its `/docs` viewer unmounted. |
260
+
|**enabled**|`never`| optional |[REMOVED]`api.documentation.enabled` was removed in @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — nothing ever read it: whether the server publishes its OpenAPI document is decided by the sibling `api.enableOpenApi` at the mount, so `enabled: false` turned nothing off. Delete the key; `api.enableOpenApi: false` is the switch that leaves the `/openapi.json` document unmounted. |
261
261
|**title**|`string`| optional | Title of the served OpenAPI document (`info.title`); unset keeps the bundled title |
262
262
|**description**|`string`| optional | Description of the served OpenAPI document (`info.description`); unset keeps the bundled description. Your app's own release number belongs here |
263
263
|**version**|`never`| optional |[REMOVED]`api.documentation.version` was removed in @objectstack/spec 17.5.0 (ADR-0049 enforce-or-remove) — nothing ever read it, and the served OpenAPI document's `info.version` has one source: the protocol version, i.e. the version of the `@objectstack/spec` package that generated the document, which no deployment configuration overrides. Delete the key. To publish your app's own release number, write it into `api.documentation.description`, which the served `info.description` carries. |
@@ -293,7 +293,7 @@ const result = BatchEndpointsConfigSchema.parse(data);
Copy file name to clipboardExpand all lines: packages/spec/liveness/rest_api.json
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -68,9 +68,9 @@
68
68
},
69
69
"enableOpenApi": {
70
70
"status": "live",
71
-
"verifiedAt": "2026-09-21",
71
+
"verifiedAt": "2026-10-22",
72
72
"evidenceScope": "in-repo",
73
-
"evidence": "packages/rest/src/rest-server.ts#registerRoutes (`if (this.config.api.enableOpenApi)` gates registerOpenApiEndpoints, which mounts both `/openapi.json` and the `/docs` viewer)",
73
+
"evidence": "packages/rest/src/rest-server.ts#registerRoutes (`if (this.config.api.enableOpenApi)` gates registerOpenApiEndpoints, which mounts `/openapi.json`, the OpenAPI document)",
74
74
"producer": "packages/rest/src/rest-server.ts#normalizeConfig (parses `config.api` through `parseDeclaredApiConfig` and lists the key into `this.config.api`, the object every consumer below reads; the parsed schema's own `.default()`s supply the value when the host omits the key)",
75
75
"note": "One consumer, and it is the mount. Worth reading beside `documentation.*` below: this flag decides WHETHER the OpenAPI document is served at all, and it is the only key on this block that the served document's existence depends on — nothing on this block decides what the document SAYS. REACHABILITY (#15543, standing reading): embedder-only. A RestServerConfig is the ARGUMENT a host passes when it constructs the server, and the one door is programmatic — createRestApiPlugin({ api }) (packages/rest/src/rest-api-plugin.ts). No shipped boot path opens it with a config of its own: packages/cli/src/commands/serve.ts forwards exactly two keys out of the stack's own top-level `api:` block (enableProjectScoping, projectResolution) and plugin-dev calls createRestApiPlugin() with no config at all, so a CLI-started deployment always gets the schema default for every key here. `live` answers who READS the key; reachability answers who can SET it, and the two never substitute for each other."
0 commit comments