Skip to content

Commit 175d789

Browse files
os-zhuangclaude
andauthored
refactor(spec)!: 退役 HttpServerConfigSchema —— 九个键零 reader 且没有任何作者面入口 (#4938) (#5293)
* refactor(spec)!: 退役 `HttpServerConfigSchema` —— 九个键零 reader 且没有任何作者面入口 (#4938) `system/http-server.zod.ts` 的 `HttpServerConfigSchema` 声明九个键 (`port` / `host` / `cors` / `requestTimeout` / `bodyLimit` / `compression` / `security` / `static` / `trustProxy`),`authorable-surface.json` 全部在册、 `content/docs/references/` 全部渲染成协议文档。两头都是空的: 1. **零 runtime reader** —— 三个仓(objectstack / cloud / objectui)里没有任何 包用它解析过文档或读过它的键;spec 之外唯一的命中是 `shared/http.zod.ts` 里指回来的 "Used by:" 注释。 2. **零作者面入口** —— 比普通的「写得下去、不生效」更彻底。`stack.zod.ts` 没有 `server:` 键,`config-schema.json` 里零命中,也没有 settings manifest 承载它,所以文档承诺的这套配置连**写下去**都做不到。 按 ADR-0049 enforce-or-remove 与 2026-08-04 裁决,退役这个不可达面。 退役形态是**容器,不是整个文件**:`RouteHandlerMetadata`(`packages/rest` 消费)与 `MiddlewareType` / `MiddlewareConfig`(`packages/runtime` 消费) 留下;`shared/http.zod.ts` 的 `CorsConfigSchema` / `RateLimitConfigSchema` / `StaticMountSchema` 各自另有 live consumer,也未被孤立。 **不打 `retiredKey()` tombstone**(playbook 路线 3,#4834 / PR #4878 同形): tombstone 是给「写下这个键的人」的话,而唯一能写 server 键的面是 #5006 的 `StackServerConfigSchema`,它是 `strictObject`,七个键早已按名拒绝并各带处方 —— 本 PR 把那些处方从「no runtime reads it」刷新为指明退役与替代。**不注册 D2 conversion**:没有任何作者源需要改写。代码消费者的通道是 `api-surface.json` (−3)接 release-time 的 `spec-changes.json` diff,加上 changeset。 `cors` 按裁决登记为 `server:` 窄形状的**首个逐键准入候选**(嵌入是真场景), 届时按 #4910 范式键与执行器一并到位,不以死键形态占导出面。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB * chore(spec): 与 main 同步后整体重生成生成物(#5289 落地后) `git merge origin/main` 零冲突,但 os-regen 驱动在生成物上不做文本合并, 所以按流程把 8 条 os-regen 路径整体 checkout 回 origin/main,再全量重跑 生成器(gen:schema / gen:api-surface / gen:spec-changes / gen:upgrade-guide / gen:docs / gen:skill-refs / gen:skill-docs / gen:strictness-ledger),两侧条目 逐条断言仍在。 - 兄弟侧 #5289:6 条 `ui/Theme` / `ui/Typography` 的 `[RETIRED]` 标记在册; `ui/Animation` / `ui/ZIndex` 两个 def 仍不在 manifest; `theme-inert-token-scales-removed` 的 D2 条目与 D3 链步完好,并已到达 `spec-changes.json` 与 protocol-upgrade-guide。 - 本侧 #4938:manifest −1 / authorable −9 / api-surface −3 仍生效; 两处「有意删除」在新基线 f8cfbb4 上按 #2978 与 #4650 路径 3 重新自证。 - strictness ledger 整体重跑(未手改数字):`system/` 368 → 366,triaged 总数 476 由 #5289 带入,非本 PR 改动。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5aae790 commit 175d789

14 files changed

Lines changed: 288 additions & 181 deletions
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
"@objectstack/spec": major
3+
---
4+
5+
refactor(spec)!: retire `HttpServerConfigSchema` — nine documented keys with zero readers AND no way to write them (#4938)
6+
7+
`system/http-server.zod.ts` declared `HttpServerConfigSchema` with nine keys —
8+
`port`, `host`, `cors`, `requestTimeout`, `bodyLimit`, `compression`,
9+
`security`, `static`, `trustProxy`. `authorable-surface.json` listed all nine
10+
and `content/docs/references/` rendered them as protocol documentation. Both
11+
halves of the contract were empty:
12+
13+
- **Zero runtime readers.** No package in any repo (objectstack / cloud /
14+
objectui) ever parsed a document with this schema or read a key off it. The
15+
only non-spec mentions were "Used by:" comments in `shared/http.zod.ts`
16+
pointing back at it.
17+
- **Zero authoring entry** — worse than the ordinary declared-but-unread
18+
defect. `stack.zod.ts` had no `server:` key, `config-schema.json` had no
19+
`HttpServerConfig`, and no settings manifest carried it, so the configuration
20+
the docs promised could not even be written down, let alone take effect.
21+
22+
What actually decides these things is three *other* shapes: the CLI `serve`
23+
arguments, the Hono adapter's `ObjectStackHonoOptions`, and
24+
`DispatcherPluginConfig.securityHeaders`. `HttpServerConfigSchema` was
25+
unacquainted with all three. Per ADR-0049 enforce-or-remove, and the 2026-08-04
26+
ruling on #4938, the unreachable face is removed.
27+
28+
FROM → TO, per retired key:
29+
30+
| removed | what to do instead |
31+
|---|---|
32+
| `HttpServerConfig.port` / `.host` | the deployment owns the socket — `objectstack serve -p <port>` / `PORT` |
33+
| `HttpServerConfig.static` | the transport plugin's `staticMounts` |
34+
| `HttpServerConfig.cors` | the transport adapter — `OS_CORS_ORIGIN` / `OS_CORS_CREDENTIALS` / `OS_CORS_MAX_AGE` |
35+
| `HttpServerConfig.security.helmet` | the dispatcher plugin's `securityHeaders` (on by default) |
36+
| `HttpServerConfig.security.rateLimit` | `defineStack({ server: { security: { rateLimit } } })` — LIVE since #5006 |
37+
| `HttpServerConfig.trustProxy` | `defineStack({ server: { trustProxy } })` — LIVE since #5006 |
38+
| `HttpServerConfig.requestTimeout` / `.bodyLimit` / `.compression` | nothing consumes them; they return with an executor or not at all |
39+
40+
Two of the nine were **activated** rather than lost: #5006 mounted
41+
`security.rateLimit` and `trustProxy` on the deliberately narrow
42+
`StackServerConfigSchema`, which grows one key at a time, each arriving with its
43+
consumer. `cors` is registered as the FIRST per-key admission candidate for that
44+
shape — embedding (`example-embed-objectql`) is a real scenario — and will
45+
arrive the #4910 way, key and executor together, rather than sitting on the
46+
export surface as a dead declaration in the meantime.
47+
48+
The retirement kit:
49+
50+
- **No `retiredKey()` tombstone, deliberately** — route 3 of the retirement
51+
playbook ("nothing parses it"), the shape #4834 / PR #4878 used for the kernel
52+
plugin-runtime family. A tombstone is a message to whoever writes the key, and
53+
the only surface on which anyone can write a server key is
54+
`StackServerConfigSchema`; it is `strictObject` and already rejects all seven
55+
by name. Those prescriptions were refreshed from "not authorable — no runtime
56+
reads it" to name the retirement and its replacement.
57+
- **No ADR-0087 D2 conversion**, for the same reason: there is no author source
58+
to rewrite, because the shape was never reachable from an authoring surface.
59+
The channel for code consumers is `api-surface.json` (which lost all three
60+
`HttpServerConfig*` entries) feeding the release-time `spec-changes.json`
61+
diff, plus this changeset.
62+
- Baselines updated deliberately: `json-schema.manifest.json` (−1, the #2978
63+
ratchet fired first and demanded it), `authorable-surface.json` (−9, allowed
64+
by the #4650 gate's path 3 "def no longer emitted by this build"),
65+
`api-surface.json` (−3). Reference docs and the strictness-ledger counts
66+
regenerated.
67+
- **The container, not the file.** `RouteHandlerMetadata` (consumed by
68+
`packages/rest`) and `MiddlewareType` / `MiddlewareConfig` (consumed by
69+
`packages/runtime`) stay, as do `CorsConfigSchema`, `RateLimitConfigSchema`
70+
and `StaticMountSchema` in `shared/http.zod.ts` — each has live consumers
71+
outside the retired shape, so none of them was orphaned by it.
72+
73+
No runtime behaviour changes — that impossibility is the reason for the removal.

‎content/docs/getting-started/quick-reference.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ Runtime environment, logging, jobs, caching, and observability.
8888
| **[Change Management](/docs/references/system/change-management)** | `change-management.zod.ts` | ChangeRequest, RollbackPlan | Change tracking |
8989
| **[Collaboration](/docs/references/system/collaboration)** | `collaboration.zod.ts` | Collaboration | Real-time collab |
9090
| **[Encryption](/docs/references/system/encryption)** | `encryption.zod.ts` | Encryption | Encryption & keys |
91-
| **[HTTP Server](/docs/references/system/http-server)** | `http-server.zod.ts` | HttpServerConfig, MiddlewareConfig | HTTP server config |
91+
| **[HTTP Server](/docs/references/system/http-server)** | `http-server.zod.ts` | RouteHandlerMetadata, MiddlewareConfig | Route + middleware metadata |
9292
| **[Job](/docs/references/system/job)** | `job.zod.ts` | Job, JobSchedule | Background job queue |
9393
| **[Logging](/docs/references/system/logging)** | `logging.zod.ts` | LoggingConfig | Structured logging |
9494
| **[Message Queue](/docs/references/system/message-queue)** | `message-queue.zod.ts` | MessageQueueConfig, TopicConfig | Message queuing |

‎content/docs/references/system/http-server.mdx‎

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ description: Http Server protocol schemas
77

88
HTTP Server Protocol
99

10-
Defines the runtime HTTP server configuration and capabilities.
11-
12-
Provides abstractions for HTTP server implementations (Express, Fastify, Hono, etc.)
10+
Route-registration metadata, middleware declaration and the server-side lifecycle/status vocabulary for HTTP server implementations (Express, Fastify, Hono, etc.)
1311

1412
Architecture alignment:
1513

@@ -26,32 +24,13 @@ Architecture alignment:
2624
## TypeScript Usage
2725

2826
```typescript
29-
import { HttpServerConfigSchema, MiddlewareConfigSchema, MiddlewareType, RouteHandlerMetadataSchema, ServerCapabilitiesSchema, ServerEventSchema, ServerEventType, ServerStatusSchema } from '@objectstack/spec/system';
30-
import type { HttpServerConfig, MiddlewareConfig, MiddlewareType, RouteHandlerMetadata, ServerCapabilities, ServerEvent, ServerEventType, ServerStatus } from '@objectstack/spec/system';
27+
import { MiddlewareConfigSchema, MiddlewareType, RouteHandlerMetadataSchema, ServerCapabilitiesSchema, ServerEventSchema, ServerEventType, ServerStatusSchema } from '@objectstack/spec/system';
28+
import type { MiddlewareConfig, MiddlewareType, RouteHandlerMetadata, ServerCapabilities, ServerEvent, ServerEventType, ServerStatus } from '@objectstack/spec/system';
3129

3230
// Validate data
33-
const result = HttpServerConfigSchema.parse(data);
31+
const result = MiddlewareConfigSchema.parse(data);
3432
```
3533

36-
---
37-
38-
## HttpServerConfig
39-
40-
### Properties
41-
42-
| Property | Type | Required | Description |
43-
| :--- | :--- | :--- | :--- |
44-
| **port** | `integer` | ✅ | Port number to listen on |
45-
| **host** | `string` | ✅ | Host address to bind to |
46-
| **cors** | `{ enabled: boolean; origins: string \| string[]; methods?: Enum<'GET' \| 'POST' \| 'PUT' \| 'DELETE' \| 'PATCH' \| 'HEAD' \| 'OPTIONS'>[]; credentials: boolean; … }` | optional | CORS configuration |
47-
| **requestTimeout** | `integer` | ✅ | Request timeout in milliseconds |
48-
| **bodyLimit** | `string` | ✅ | Maximum request body size |
49-
| **compression** | `boolean` | ✅ | Enable response compression |
50-
| **security** | `{ helmet: boolean; rateLimit?: object }` | optional | Security configuration |
51-
| **static** | `{ path: string; directory: string; cacheControl?: string }[]` | optional | Static file serving configuration |
52-
| **trustProxy** | `boolean` | ✅ | Trust X-Forwarded-* headers |
53-
54-
5534
---
5635

5736
## MiddlewareConfig

‎content/docs/references/system/stack-server.mdx‎

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ description: Stack Server protocol schemas
99

1010
## Why this is NOT `HttpServerConfigSchema`
1111

12-
`[system/http-server.zod.ts](/docs/references/system/http-server)` declares nine keys (`port`, `host`, `cors`,
12+
`[system/http-server.zod.ts](/docs/references/system/http-server)` used to declare nine keys (`port`, `host`,
1313

14-
`requestTimeout`, `bodyLimit`, `compression`, `security`, `static`,
14+
`cors`, `requestTimeout`, `bodyLimit`, `compression`, `security`, `static`,
1515

1616
`trustProxy`). #4938 measured them: **none had a runtime reader and none was
1717

@@ -37,11 +37,29 @@ consumer. Today that is exactly two:
3737

3838
| `trustProxy` | the same limiter's IP resolution — see below |
3939

40-
The other seven `HttpServerConfigSchema` keys stay unreachable, and their
40+
The other seven `HttpServerConfigSchema` keys were RETIRED with the shape
4141

42-
enforce-or-remove fate is tracked by #4938. Adding one here without an
42+
that carried them (#4938, ADR-0049 enforce-or-remove): unreachable *and*
4343

44-
executor re-opens the hole this narrowness exists to close.
44+
unread, they were the cleanest remove candidate in the ledger, and their
45+
46+
prescriptions now live in the `guidance` maps below — the only place an
47+
48+
author can write a server key is also the only place that has to answer for
49+
50+
one. Adding one here without an executor re-opens the hole this narrowness
51+
52+
exists to close.
53+
54+
`cors` is the registered exception-in-waiting: the 2026-08-04 ruling named it
55+
56+
the FIRST per-key admission candidate for this shape, because embedding
57+
58+
(`example-embed-objectql`) is a real scenario with real pull. When that work
59+
60+
is scheduled it arrives the #4910 way — key and executor in one change — not
61+
62+
by un-retiring a declaration.
4563

4664
## What `server:` is NOT for
4765

‎docs/audits/2026-07-unknown-key-strictness-ledger.counts.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,4 @@ directory rather than per file.
280280
| `kernel/` | 319 |
281281
| `qa/` | 6 |
282282
| `shared/` | 25 |
283-
| `system/` | 368 |
283+
| `system/` | 366 |

‎packages/spec/api-surface.json‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -944,9 +944,6 @@
944944
"HistogramBucketConfigSchema (const)",
945945
"HttpDestinationConfig (type)",
946946
"HttpDestinationConfigSchema (const)",
947-
"HttpServerConfig (type)",
948-
"HttpServerConfigInput (type)",
949-
"HttpServerConfigSchema (const)",
950947
"ISettingsCapability (interface)",
951948
"ISettingsClient (interface)",
952949
"Incident (type)",

‎packages/spec/authorable-surface.json‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5911,15 +5911,6 @@
59115911
"system/HttpDestinationConfig:retry",
59125912
"system/HttpDestinationConfig:timeout",
59135913
"system/HttpDestinationConfig:url",
5914-
"system/HttpServerConfig:bodyLimit",
5915-
"system/HttpServerConfig:compression",
5916-
"system/HttpServerConfig:cors",
5917-
"system/HttpServerConfig:host",
5918-
"system/HttpServerConfig:port",
5919-
"system/HttpServerConfig:requestTimeout",
5920-
"system/HttpServerConfig:security",
5921-
"system/HttpServerConfig:static",
5922-
"system/HttpServerConfig:trustProxy",
59235914
"system/Incident:affectedDataClassifications",
59245915
"system/Incident:affectedSystems",
59255916
"system/Incident:category",

‎packages/spec/json-schema.manifest.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,6 @@
12571257
"system/GCounter",
12581258
"system/HistogramBucketConfig",
12591259
"system/HttpDestinationConfig",
1260-
"system/HttpServerConfig",
12611260
"system/Incident",
12621261
"system/IncidentCategory",
12631262
"system/IncidentNotificationMatrix",

‎packages/spec/src/shared/http.zod.ts‎

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@ export type HttpRequest = z.infer<typeof HttpRequestSchema>;
6363
*
6464
* Used by:
6565
* - api/router.zod.ts (RouterConfigSchema)
66-
* - system/http-server.zod.ts (HttpServerConfigSchema)
67-
*
66+
*
67+
* (`system/http-server.zod.ts` embedded this as `HttpServerConfig.cors` until
68+
* #4938 retired that shape. CORS is owned by the transport adapter and
69+
* configured by OS_CORS_ORIGIN / OS_CORS_CREDENTIALS / OS_CORS_MAX_AGE; this
70+
* schema is the registered first candidate for a future `server.cors` key,
71+
* which arrives WITH its executor or not at all.)
72+
*
6873
* @example
6974
* {
7075
* "enabled": true,
@@ -115,8 +120,13 @@ export type CorsConfig = z.infer<typeof CorsConfigSchema>;
115120
*
116121
* Used by:
117122
* - api/endpoint.zod.ts (ApiEndpointSchema)
118-
* - system/http-server.zod.ts (HttpServerConfigSchema)
119-
*
123+
* - system/stack-server.zod.ts (ServerRateLimitConfigSchema — this shape reused
124+
* verbatim and closed against unknown keys; the LIVE inbound token bucket)
125+
*
126+
* (`system/http-server.zod.ts` embedded this as `HttpServerConfig.security
127+
* .rateLimit` until #4938 retired that shape; the budget itself was not lost —
128+
* #5006 activated it on the narrow `server:` block.)
129+
*
120130
* @example
121131
* {
122132
* "enabled": true,
@@ -152,9 +162,12 @@ export type RateLimitConfig = z.infer<typeof RateLimitConfigSchema>;
152162
* Configuration for serving static files
153163
*
154164
* Used by:
155-
* - api/router.zod.ts (RouterConfigSchema)
156-
* - system/http-server.zod.ts (HttpServerConfigSchema)
157-
*
165+
* - api/router.zod.ts (RouterConfigSchema — `staticMounts`)
166+
*
167+
* (`system/http-server.zod.ts` embedded this as `HttpServerConfig.static` until
168+
* #4938 retired that shape. Static mounts are configured on the transport
169+
* plugin's `staticMounts`.)
170+
*
158171
* @example
159172
* {
160173
* "path": "/static",

‎packages/spec/src/stack.zod.ts‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -364,12 +364,13 @@ export const ObjectStackDefinitionSchema = lazySchema(() => z.object({
364364
*
365365
* DELIBERATELY NARROW (#4910): it carries only keys an executor consumes —
366366
* today `security.rateLimit` (the inbound token bucket that answers 429) and
367-
* `trustProxy` (how that limiter identifies a caller). It is NOT the nine-key
368-
* `HttpServerConfigSchema`: seven of those keys have no reader and no
369-
* authoring surface, and mounting them here would make dead keys writable
370-
* (their enforce-or-remove fate is #4938). Port/host stay a deployment
371-
* concern owned by `objectstack serve -p`; see the schema file for the
372-
* precedence rule and the rest of the rationale.
367+
* `trustProxy` (how that limiter identifies a caller). It is NOT the former
368+
* nine-key `HttpServerConfigSchema`: seven of those keys had no reader and no
369+
* authoring surface, and mounting them here would have made dead keys
370+
* writable — so they were retired with their container instead (#4938,
371+
* ADR-0049). Port/host stay a deployment concern owned by
372+
* `objectstack serve -p`; see the schema file for the precedence rule, the
373+
* per-key prescriptions and the rest of the rationale.
373374
*/
374375
server: StackServerConfigSchema.optional()
375376
.describe('Server-level runtime config consumed by objectstack serve/dev (inbound rate limit, proxy trust)'),

0 commit comments

Comments
 (0)