Repository navigation
Commit 14e7239
feat(spec)!: retire the docs-viewer keys — ApiDocumentationConfig.ui and the REST API plugin's openApi.uiPath / uiFramework (ADR-0049) (#25180)
Fixes #25159
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Dispatched by the `domain:spec` seat 1 PM (claim `6333051310`), executed
through the `spec-property-retirement` kit. Ruling executed: triage
route A, record `6332269878` (retire with tombstones and an ADR-0087
entry, no staged window), following the maintainer's 「C 下线页面」 on #25104
(`6317642533`).
## What changed
Three keys declared an HTML API documentation viewer that nothing ever
served. Each is now a `retiredKey()` tombstone: a `tsc` error at the
authoring site and a parse error at the key's path whose message is the
prescription.
| Key (authored as) | Def key | Was |
|:--|:--|:--|
| `ApiDocumentationConfig.ui` | `api/ApiDocumentationConfig:ui` |
`ApiTestingUiConfigSchema.optional()`, "Testing UI configuration" |
| `RestApiPluginConfig.openApi.uiPath` |
`api/OpenApiGenerationConfig:uiPath` |
`z.string().default('/api/docs')`, "URL path to serve documentation UI"
|
| `RestApiPluginConfig.openApi.uiFramework` |
`api/OpenApiGenerationConfig:uiFramework` |
`z.enum(['swagger-ui','redoc','rapidoc','elements']).default('swagger-ui')`
|
The orphan value defs `api/ApiTestingUiConfig` and
`api/ApiTestingUiType` leave whole, with their exports
`ApiTestingUiConfigSchema`, `ApiTestingUiConfig`,
`ApiTestingUiConfigParsed` and `ApiTestingUiType` (kit §4, "orphan value
schema").
Each prescription names the mechanism that is live: the OpenAPI document
is served at `GET /api/v1/openapi.json` under the REST server's default
`api.basePath` and `api.version` (the path follows both) while
`api.enableOpenApi` is on. Example, `uiPath`:
"`RestApiPluginConfig.openApi.uiPath` was removed in @objectstack/spec
18.1.0 (ADR-0049 enforce-or-remove) — nothing ever read it: no
documentation viewer was ever served at its path, the `/api/docs`
default included, and the platform serves no HTML API documentation
viewer at all, only the machine-readable OpenAPI document. Delete the
key. The OpenAPI document is served at …"
### `uiFramework`: an in-place addition, not named on the card
`uiFramework` sits one line below `uiPath` on the same schema and
selects the viewer `uiPath` would have served. All four in-place
conditions hold: ① same defect class (a viewer declaration with no
viewer); ② mechanical, with the shape fixed by `uiPath` beside it; ③ the
file is inside this claim's surface; ④ same gates, no new verification
surface. Evidence: zero identifier hits outside `packages/spec` here and
in objectui at its pin (readings below). Leaving it would keep the
declaration the ruling removed: a framework choice for a viewer the
platform does not serve, with a `swagger-ui` default materialised on
every parse. It is a third narrowed key, so the maintainer report for
this round should list it.
## Hypotheses, as measured
- **H1 (no reader): holds.** At `origin/main` `b93c750c7`, `git grep -nE
"ApiTestingUi|uiPath|documentation\.ui"` outside `packages/spec`,
`content/docs/references` and `CHANGELOG.md` finds 2 hits, both
`packages/rest/src/ui-routes.ts:79,85`: a local `uiPath` variable for
the unrelated `/ui/view` route. `uiFramework`, `enableTryItOut` and
`OpenApiGenerationConfig` find 0 each. Controls on the same instrument:
`enableOpenApi` 16 and `generateOpenApi` 8. objectui at the pinned
`.objectui-sha` `56cf4d8e89`: 0 for
`ApiTestingUi|uiPath|uiFramework|documentation\.ui|ApiDocumentationConfig|OpenApiGenerationConfig|enableTryItOut`,
against controls `@objectstack/spec/api` 103 and `openapi\.json` 12. So
no objectui follow-up is owed. Inside `packages/spec`, nothing parses
`ApiDocumentationConfigSchema`, `OpenApiGenerationConfigSchema` or
`RestApiPluginConfigSchema` outside their own unit tests. The only
importer is the `api` barrel.
- **H2 (which def): holds.** `uiPath` is on
`OpenApiGenerationConfigSchema` (`api/OpenApiGenerationConfig:uiPath`),
which `RestApiPluginConfigSchema.openApi` embeds, so an author writes
`RestApiPluginConfig.openApi.uiPath`. The pin asserts the refusal at
both doors, the second located at `openApi.uiPath`.
- **H3 (orphans): holds.** `ApiTestingUiConfigSchema` /
`ApiTestingUiType` have no consumer besides `ui`. In this tree the only
other references were their own unit tests and the ADR-0122 isomorphic
pin line. They leave whole, so `api-surface/` moves.
- **H4 (served path): refined.** The card's "`/openapi.json`" is
incomplete. `registerRoutes` calls
`registerOpenApiEndpoints(getApiBasePath())` while `api.enableOpenApi`
is on, and `getApiBasePath()` = `apiPath ?? basePath/version`, so the
route is `GET /api/v1/openapi.json` by default
(`packages/rest/src/openapi-endpoints-read-decorations.test.ts:221`
reads that route). The prescription spells the default path and says it
follows `api.basePath` / `api.version`.
- **H5 (family entry): own family.** New D3 entry
`api-docs-viewer-keys-retired`. It is not folded into
`rest-api-config-dead-keys-retired` (PR #25162), for three reasons.
Those keys sit on `RestApiConfigSchema`, the REST server's construction
argument, and were dead in the `rest_api` liveness census. These sit on
two other schemas and retire because the viewer was taken offline.
Different surface, different ruling. That landed entry is not edited.
- **H6 (sibling estimate): re-measured, holds.** The H1 readings above
were re-taken on this branch's base, not inherited.
## Kit surfaces
- **Schema**: three tombstones with retirement records in
`documentation.zod.ts` / `plugin-rest-api.zod.ts`, and the module and
`@example` docblocks no longer show a viewer.
- **Orphan defs**: both deleted. The `json-schema.manifest/` ratchet
fired first, as the kit predicts for a whole-def removal, and the two
manifest keys are removed deliberately.
- **ADR-0087**: `RETIRED_KEYS_BY_MAJOR[18]` gets 3 entry files and
`RETIRED_DEFS_BY_MAJOR[18]` gets 2. There is one D3 semantic entry, plus
its `STEP18_RATIONALE` fragment (`order: 108`, inserted at its id's sort
position). **No D2 conversion**: neither config is a stack collection
member or a `sys_metadata` row, so no conversion seam would ever see
one. This is the `kernel/Manifest:loading` disposition, the same one the
`handlerStatus` and `rest-api-config` retirements on these files took.
The defaults on `uiPath` / `uiFramework` leave no residue window,
because nothing parses this config into a stored or built artifact. The
old defaults are refused like any other value.
- **Liveness ledger**: n/a. No ledger walks
`ApiDocumentationConfigSchema` or `OpenApiGenerationConfigSchema`:
neither is a registry type nor in `SPEC_ONLY_SCHEMAS`. So there is no
row to keep `dead`.
- **Generated**: `authorable-surface/api.json` has 3 `[RETIRED]` rows
and the 12 `api/ApiTestingUiConfig:*` rows deleted. Gate (a) printed
them, and check (c) accepted the deletion because the whole def leaves.
Also regenerated: `authorable-defaults/api.json` (10 default rows),
`json-schema.manifest/api.json` (2 defs), `api-surface/api.json` (5
exports), `export-origins/` and `declaration-map/`, the
strictness-ledger counts, and the reference pages `api/documentation`,
`api/plugin-rest-api` and `references/index` (1544 to 1542 schemas). All
of these came from `check:generated --fix`.
- **Forms / i18n / CLI advisory lint / examples / published skills /
hand-written docs**: none teach either key (grep, 0 hits).
- **`REST_API_PLUGIN.md`**: the example drops `uiPath` / `uiFramework`,
the "Multiple UI frameworks" feature bullet is gone, and a paragraph
names the document path.
- **Spec Shape Gate registry**: not owed. Its `$comment` ties an entry
to a downstream objectui card, and objectui has zero readers.
- **Changeset**: `.changeset/25159-api-docs-viewer-keys-retired.md`,
`@objectstack/spec` `minor`, with both declaration lines, the ADR-0087
marker (`registered api-docs-viewer-keys-retired`), the BREAKING banner,
FROM → TO and the one-line fix.
## Tests
- New pin `packages/spec/src/api/docs-viewer-keys-retirement.test.ts`
(22 cases, in the `repo` vitest project because it reads outside the
package):
- `code` `invalid_type`, `path` and the prescription at each door, for
every former value including the old defaults;
- the `tsc` channel, with three `@ts-expect-error` checks (the file is
in `tsconfig.test.json`'s program; `--listFilesOnly` finds it);
- live controls;
- zero holders for the 4 retired names, plus survivors;
- the ADR-0087 registration;
- a tree-scoped absence walk with two legs: references to retired names,
and structural authorings of `uiPath` / `uiFramework` / a viewer `ui`
block.
- Radius: the five roots already declared for `@objectstack/spec` in
`scripts/cross-package-test-inputs.mjs` and `turbo.json`. One structural
exclusion, `authorable-surface.base.json`: the published-surface anchor,
which only `gen:authorable-surface-base` writes.
`check:cross-package-test-inputs` is green with the pin added to
`vitest.repo-tests.json`.
- Edited: `documentation.test.ts` and `plugin-rest-api.test.ts` no
longer author the retired keys. `type-alias-convention.pin.test.ts`
drops `Iso_api_documentation__ApiTestingUiType`, and its count goes from
789 to 788, with the history line added.
- **Reverse verification** (committed first, run under
`scripts/ablation-replace.mjs`): `uiPath: retiredKey(...)` was put back
to `z.string().default('/api/docs')`. Predicted direction red; observed
red, 6 failed / 16 passed of 22. Restored blob `f365b815fca0` equals
HEAD and `git diff HEAD` is empty.
- **Walk probe**: an untracked `examples/app-crm/zz-probe-25159.yaml`
authoring `uiPath`, plus a `content/docs/zz-probe-25159.md` fence
importing `ApiTestingUiConfigSchema`. Both legs fired (`...yaml:3
authors a retired docs-viewer key`, `... references {
ApiTestingUiConfigSchema }`). The probes were deleted afterwards and the
tree was clean.
### Readings at head `21ed122c3`
The head is this branch merged with `origin/main` `ab488d9b7`, which
moved no `packages/spec` path.
- `pnpm --filter @objectstack/spec test` (vitest `local` project): Test
Files 706 passed (706), Tests 21456 passed and 1 todo (21457).
- The `repo`-project files this diff touches or reads
(`docs-viewer-keys-retirement`, `scripts/step18-rationale-merge`,
`shared/retired-key-migrate-sentence`,
`api/rest-api-config-dead-keys-retirement`): Test Files 4 passed (4),
Tests 69 passed (69). The rest of `test:repo` is CI's.
- `pnpm --filter @objectstack/spec typecheck`: exit 0, test layer
included (`check:test-typecheck` OK, no new debt).
- `pnpm --filter @objectstack/spec check:generated`: exit 0.
- Gates from `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`, no paths: 113 derived, 113 run, all exit 0.
`--ran` reports "113 derived famil(ies) accounted for, 113 run, 0
NOT-MEASURED".
- Eleven first refused with exit 3. Six were spec gates over a `dist`
older than my last test-file edits; four needed `@objectstack/lint` /
`@objectstack/objectql` / every package built
(`check:dual-build-cjs-loads`); one, the teardown self-test, needed a
pinned commit the shallow clone lacked. A fresh `check:generated` also
reported the same stale `dist` (exit 1).
- All twelve were re-run green after the spec build, the lint and
objectql closure builds, a turbo build (77/77, 75 cached), and a depth-1
fetch of `621a48760`.
- Outside the derivation: `pnpm check:dev-prereqs` exit 0; `node
scripts/check-platform-checklist.mjs --changed-from origin/main` exit 0
(0 anchored files in the change set).
- Dogfood battery, once on this head, `pnpm --filter
@objectstack/dogfood test` under the verify lock, no shard: `VERDICT
command-exit 0`, Test Files 287 passed and 3 skipped (290), Tests 2395
passed and 18 skipped (2413).
- Consumer reading, direction downstream (`...@objectstack/spec`):
measured by the tree-scoped pin and the grep with controls above, not by
rebuilding the consumer closure (kit §4). Zero readers outside
`packages/spec`.
## Acceptance notes
- `OpenApiGenerationConfigSchema` and `RestApiPluginConfigSchema` as a
whole, and every other key of `ApiDocumentationConfigSchema`, are parsed
by nothing outside their own unit tests in this tree. The REST plugin's
real config is the separate `RestApiPluginConfig` interface in
`packages/rest`, which carries `api?: RestServerConfig`. Example:
`openApi.outputPath` defaults to `/api/docs/openapi.json`, while the
document is served at `GET {basePath}/openapi.json`. This is a dormant,
zero-pull declaration, out of this card's scope. It is noted here and
not filed: no named producer and no measured public-door reach.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01T1Y1g92DfSEz93iuCisju4)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 02ad31a commit 14e7239
26 files changed
Lines changed: 979 additions & 346 deletions
File tree
- .changeset
- content/docs/references
- api
- docs/audits/2026-07-unknown-key-strictness-ledger.counts
- packages/spec
- api-surface
- authorable-defaults
- authorable-surface
- declaration-map
- export-origins
- json-schema.manifest
- src
- api
- migrations
- entries
- retired-defs
- retired-keys
- semantic
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
12 | | - | |
| 11 | + | |
13 | 12 | | |
14 | 13 | | |
15 | 14 | | |
16 | | - | |
| 15 | + | |
17 | 16 | | |
18 | 17 | | |
19 | 18 | | |
20 | 19 | | |
21 | 20 | | |
22 | | - | |
| 21 | + | |
23 | 22 | | |
24 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
25 | 28 | | |
26 | 29 | | |
27 | 30 | | |
| |||
30 | 33 | | |
31 | 34 | | |
32 | 35 | | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | 36 | | |
39 | 37 | | |
40 | 38 | | |
| |||
45 | 43 | | |
46 | 44 | | |
47 | 45 | | |
48 | | - | |
49 | | - | |
| 46 | + | |
| 47 | + | |
50 | 48 | | |
51 | 49 | | |
52 | 50 | | |
| |||
90 | 88 | | |
91 | 89 | | |
92 | 90 | | |
93 | | - | |
| 91 | + | |
94 | 92 | | |
95 | 93 | | |
96 | 94 | | |
| |||
111 | 109 | | |
112 | 110 | | |
113 | 111 | | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | 112 | | |
132 | 113 | | |
133 | 114 | | |
| |||
218 | 199 | | |
219 | 200 | | |
220 | 201 | | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
233 | | - | |
234 | | - | |
235 | | - | |
236 | | - | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
269 | | - | |
270 | | - | |
271 | | - | |
272 | 202 | | |
273 | 203 | | |
274 | 204 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
107 | | - | |
108 | | - | |
| 107 | + | |
| 108 | + | |
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
| |||
279 | 279 | | |
280 | 280 | | |
281 | 281 | | |
282 | | - | |
283 | | - | |
| 282 | + | |
| 283 | + | |
284 | 284 | | |
285 | 285 | | |
286 | 286 | | |
| |||
0 commit comments