Blocked-by: #14366 — the api block's consumption seam is still validate-only and is about to move. #14369 left RestApiConfigSchema out of the ledger for exactly that reason: a census taken now would record a half that is changing. ⛔ Do not enrol these keys before that seam settles.
Observation from the liveness-ledger work on #14369, which enrolled four of the five RestServerConfig sub-objects and deliberately left RestApiConfigSchema (api) out. While measuring the four it enrolled, the same census was run across the api block, and two of its keys came out the same way as the ten on that card.
What was measured
On origin/main @ 2514d49f3, packages/rest/src non-test sources, every read site outside NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded:
Read by the runtime — api.version, api.basePath, api.apiPath (getApiBasePath), api.enableCrud, api.enableMetadata, api.enableUi, api.enableBatch, api.enableDiscovery, api.enableOpenApi, api.enableSearch, api.enableProjectScoping, api.projectResolution.
Normalized and never read (0 sites each) — two declared containers:
| key |
declared as |
api.documentation |
object: enabled / title / description / version / termsOfService / contact{name,url,email} / license{name,url} |
api.responseFormat |
object: envelope / includeMetadata / includePagination |
normalizeConfig copies both straight through into this.config.api, and nothing reads either back. Re-confirmed by triage at origin/main 4d0d944: responseFormat occurs at exactly two sites in packages/rest/src — the type declaration (rest-server.ts:738) and the copy-through (:3555) — and includeMetadata / includePagination return 0 files each.
So api.responseFormat.envelope: false does not unwrap a single response, and api.documentation.title: 'Acme API' does not retitle the served OpenAPI document — that document is the pre-generated @objectstack/spec contract enriched at request time with the live server URL and the registered objects, and it never consults this config.
⚠️ Ledger placement — the name is already taken
packages/spec/liveness/api.json exists, and it is a different api: its own header says ApiEndpointSchema (packages/spec/src/api/endpoint.zod.ts), the registered api metadata type, with consumers in the matcher, executor, policy chain and mapping layer. It has nothing to do with RestApiConfigSchema.
⛔ So "put the verdicts in the api ledger" resolves to the wrong file. A new rest_api ledger is needed, as this card says — and whoever creates it should note in its _note why it is not api.json, or the next reader repeats the mistake.
⭐ This is the same shape as #14676's userMessage collision, graded this round: one spelling, two unrelated meanings, inside packages/spec.
Not prejudged
Declared-but-unenforced is the ADR-0049 class. ⭐ The two keys differ in a way that should survive into the verdicts: documentation is customer-facing metadata an OpenAPI document plausibly should carry, so enforce is a genuine candidate and is real work in the document builder; responseFormat describes an envelope the REST layer already produces unconditionally, so its enforce route would mean making the envelope configurable — a larger claim. ⛔ Do not give them one shared verdict by default.
Related: #14369 (the ten sibling keys, ledger landed) · #14691 (the enforce-or-remove door for those, pm:queue) · #14366 (the api block's consumption seam — the blocker) · #11637 (the api block's validate-only parse).
Generated by Claude Code
Blocked-by: #14366 — the
apiblock's consumption seam is still validate-only and is about to move. #14369 leftRestApiConfigSchemaout of the ledger for exactly that reason: a census taken now would record a half that is changing. ⛔ Do not enrol these keys before that seam settles.Observation from the liveness-ledger work on #14369, which enrolled four of the five
RestServerConfigsub-objects and deliberately leftRestApiConfigSchema(api) out. While measuring the four it enrolled, the same census was run across theapiblock, and two of its keys came out the same way as the ten on that card.What was measured
On
origin/main@2514d49f3,packages/rest/srcnon-test sources, every read site outsideNormalizedRestServerConfig's type declaration (rest-server.tslines 723-786) andnormalizeConfigitself (3518-3616), comments excluded:Read by the runtime —
api.version,api.basePath,api.apiPath(getApiBasePath),api.enableCrud,api.enableMetadata,api.enableUi,api.enableBatch,api.enableDiscovery,api.enableOpenApi,api.enableSearch,api.enableProjectScoping,api.projectResolution.Normalized and never read (0 sites each) — two declared containers:
api.documentationenabled/title/description/version/termsOfService/contact{name,url,email}/license{name,url}api.responseFormatenvelope/includeMetadata/includePaginationnormalizeConfigcopies both straight through intothis.config.api, and nothing reads either back. Re-confirmed by triage atorigin/main4d0d944:responseFormatoccurs at exactly two sites inpackages/rest/src— the type declaration (rest-server.ts:738) and the copy-through (:3555) — andincludeMetadata/includePaginationreturn 0 files each.So
api.responseFormat.envelope: falsedoes not unwrap a single response, andapi.documentation.title: 'Acme API'does not retitle the served OpenAPI document — that document is the pre-generated@objectstack/speccontract enriched at request time with the live server URL and the registered objects, and it never consults this config.packages/spec/liveness/api.jsonexists, and it is a differentapi: its own header saysApiEndpointSchema (packages/spec/src/api/endpoint.zod.ts), the registeredapimetadata type, with consumers in the matcher, executor, policy chain and mapping layer. It has nothing to do withRestApiConfigSchema.⛔ So "put the verdicts in the api ledger" resolves to the wrong file. A new
rest_apiledger is needed, as this card says — and whoever creates it should note in its_notewhy it is notapi.json, or the next reader repeats the mistake.⭐ This is the same shape as #14676's
userMessagecollision, graded this round: one spelling, two unrelated meanings, insidepackages/spec.Not prejudged
Declared-but-unenforced is the ADR-0049 class. ⭐ The two keys differ in a way that should survive into the verdicts:
documentationis customer-facing metadata an OpenAPI document plausibly should carry, so enforce is a genuine candidate and is real work in the document builder;responseFormatdescribes an envelope the REST layer already produces unconditionally, so its enforce route would mean making the envelope configurable — a larger claim. ⛔ Do not give them one shared verdict by default.Related: #14369 (the ten sibling keys, ledger landed) · #14691 (the enforce-or-remove door for those,
pm:queue) · #14366 (theapiblock's consumption seam — the blocker) · #11637 (theapiblock's validate-only parse).Generated by Claude Code