Skip to content

fix(spec): 不再承诺根本不会跑的校验,并让严格性账本闸门看见嵌套目录(#4001) - #4412

Merged
os-zhuang merged 2 commits into
mainfrom
claude/strict-schema-authz-surface-s8vnok
Jul 31, 2026
Merged

fix(spec): 不再承诺根本不会跑的校验,并让严格性账本闸门看见嵌套目录(#4001)#4412
os-zhuang merged 2 commits into
mainfrom
claude/strict-schema-authz-surface-s8vnok

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

#4001 战役的两处修正。两处都是这场战役要消灭的那个缺陷本身——一个成功信号盖住了一处遗漏——只不过这次出现在战役自己的产物里。

起因是一次「#4001 到底做完了没有」的核查。结论是没有(长尾 ~416/500 站点仍是默认 strip,studio/ 27 站点 0 strict),但核查过程中发现了两处比长尾更该先修的东西。

1. config 的处方是假的 —— 而且有四份拷贝

#4207DatasourceSchema 收紧成 .strict() 时,把 config 留开。于是一个把连接细节写在顶层的作者,会收到这样的拒绝:

`host` is a driver connection detail — it belongs inside config … Move it to config: { host: … }; the driver's own configSchema validates it there.

没有任何东西在那里校验。 这句话在两个独立层面上都不成立:

  • DriverDefinitionSchema.configSchema 是个 z.record,而仓库里仅有的两个驱动定义都把它设成 {}driver/mongo.zod.ts 那行还带着「will be populated … at runtime」的注释,没有任何代码执行它)
  • 本仓没有任何读取点;四个驱动插件也都没有拿 schema parse 过自己的 config

所以这句话把一个在会报错的位置犯了可恢复错误的作者,以平台的口吻,指引到了一个同样的错误重新变静默的槽里:config: { hostname: … } 被静默丢弃,数据源连到 localhost —— 这就是 #4001 的原始 bug,逐字同构,只低了一层。一条错误的指令比没有指令更坏,对 AI 作者尤其如此,它判断「这样对不对」的唯一信号就是解析有没有抱怨。

同一句话在仓库里有 4 份拷贝,全部改掉:

位置 性质
datasource.zod.ts 模块注释 内部
datasource.zod.ts belongsInConfig 作者会看到的错误信息
driver/mongo.zod.ts 头部 内部(「used by the Platform to validate datasource.config」)
content/docs/releases/v17.mdx 用户会看到的发布说明

第 4 份是被本 PR 自己的 docs-drift 机器人找出来的 —— 它按包级启发式列了 107 篇文档,其中真正需要改的正好一篇,而那一篇恰好是读者真会看的那份。

处方改成指向 per-driver 的形状(PostgresConfigSchema / MongoConfigSchema / MemoryConfigSchema),不再声称任何执行力。没有改动任何可授权键 —— 只是错误信息与文档文字。真正的执行(对惰性 configSchema 做 enforce-or-remove)另立 #4410 追踪。

2. 账本闸门的覆盖扫描只有一层深

check:strictness-ledger#4232 建立)承诺:被分类目录下每一个有站点的 *.zod.ts 都必须带一行分类。它用非递归的目录列举实现这个承诺,于是 data/driver/ —— 三个 per-driver 配置文件、九个可授权站点 —— 对它完全不可见,而它照常打印 "no undeclared schema files"

这正是账本自己开头那句话的升级版:会漂移的地图比没有地图更坏,因为它会被人照着走一个漏报的闸门比没有闸门更坏,因为它把「我该分类一下」变成了「已经分类过了」。 没有闸门时读者还会保持怀疑;绿色的闸门会解除这份怀疑。

为什么单独加了测试

scripts/strictness-ledger.test.ts 钉住递归这件事,它和闸门不重复——实测:在账本行已经补齐之后,把扫描改回非递归,check:strictness-ledger 依然是绿的(一层深的扫描在「没有嵌套文件缺失」时确实找不到缺失)。闸门抓不住自己的回归。 这个测试可以,并且我先让它红、再让它绿地验证过。

按同样的道理,账本里也记下了这条:任何声称覆盖的检查,在信它之前得先证明它看得见它该看见的东西。

3. 顺带:给「等田野数据」加了决策点

账本的 Next steps 只剩一条,而且是无限期的等待(「等告警层跑一个 release」)。没有到期条件的等待,会安静地变成永久停摆,而这份文件会一直显示战役进行中。现在它由一个可回答的问题来解除,而不是日期,并列出三种结果各自的下一步 —— 其中要重点排查的那种是「零发现,因为根本没有任何东西在回报」,它和成功在表面上无法区分,正是这场战役自己的主题。

同时把 studio/(27 站点、0 strict、三个文件全是未验证的 (p))显式列为不依赖田野数据的备选起点。

验证

  • @objectstack/spec283 文件 / 7205 用例通过tsc --noEmit 干净
  • 下游消费包全绿lint / metadata / platform-objects / metadata-core / metadata-protocol —— turbo 17/17 任务成功,0 失败
  • 8 个生成物闸门全部 up-to-date(无需重新生成 —— 证实这些 JSDoc 改动没有让参考文档漂移,即 feat(spec): reject unknown keys on an action param instead of stripping them (#3405) #3746 踩过的那个坑没有复现)
  • 全部 check:* 闸门绿:docs / skill-refs / skill-docs / api-surface / spec-changes / upgrade-guide / authorable-surface / react-blocks / liveness / empty-state / variant-docs / strictness-ledger / exported-any / react-conformance / skill-examples
  • 闸门行为双向实证:在 data/driver/ 未申报时变红、补齐后变绿;植入一处分区合计漂移仍能抓到;把递归改回去后新测试变红而闸门仍绿(这就是新测试存在的理由)
  • 全仓确认:被改掉的旧错误信息文本没有任何测试或文档依赖,且假声明已无残留拷贝

参考

🤖 Generated with Claude Code

https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY

…ictness ledger see nested dirs (#4001)

Two corrections to the #4001 unknown-key campaign. Both are the same defect the
campaign exists to remove — a success signal covering an omission — found in the
campaign's own output.

1. The `config` prescription was false.

`DatasourceSchema` went strict in #4207 with `config` left open, and the
rejection for a misplaced connection key prescribed: "Move it to
`config: { host: … }`; the driver's own configSchema validates it there."

Nothing validates it there. `DriverDefinitionSchema.configSchema` is a
`z.record`; both bundled driver specs set it to `{}` (mongo's with a comment
promising runtime population that no code performs); and no consumer in this
repo reads it. So the message took an author who had made a recoverable mistake
at a place that now catches it and directed them, with the platform's authority,
at a slot where the same mistake is silent again — `config: { hostname: … }` is
stripped and the datasource connects on localhost, which is #4001's original bug
one level down.

The guidance now names the per-driver shape to write against
(`PostgresConfigSchema` / `MongoConfigSchema` / `MemoryConfigSchema`) and claims
nothing about enforcement. Same false claim removed from `driver/mongo.zod.ts`,
whose header advertised that the Platform validates `datasource.config` with it.
Enforcement — enforce-or-remove on an inert `configSchema` — is filed as #4410.

Error-message and documentation text only; no authorable key changed.

2. The ledger gate's coverage walk was one level deep.

`check:strictness-ledger` promises every sited `*.zod.ts` in a triaged directory
carries a classification row. It listed directories non-recursively, so
`data/driver/` — three per-driver config files, nine authorable sites — was
invisible to the check whose entire promise is "no undeclared surface", which
printed "no undeclared schema files" and was believed.

A gate that under-reports is worse than no gate: it converts "I should classify
this" into "it is already classified". The walk is now recursive, the three
files are classified, and the ledger records both findings.

`scripts/strictness-ledger.test.ts` pins the recursion, and is not redundant with
the gate: measured, with the rows now present, reverting to a non-recursive walk
leaves the gate GREEN — it cannot catch its own regression. The test can, and
was verified to go red before it went green.

Verified: spec 283 files / 7205 tests, `tsc --noEmit` clean, all 8 generated
artifacts current, and all 10 `check:*` gates green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 31, 2026 12:37pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests tooling size/m labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…laim (#4001)

Fourth and last copy, and the only user-facing one. The v17 notes told readers
that `config` and `readReplicas` stay open records because "the driver's own
`configSchema` validates them" — the same sentence corrected in
`datasource.zod.ts` (module comment + the `belongsInConfig` rejection) and
`driver/mongo.zod.ts`.

Found by this PR's own docs-drift advisory, which is worth recording: the bot
listed 107 docs on a package-level heuristic and the correction was real in
exactly one of them. Cheap to check, and it was the copy readers actually see.

Now states that nothing validates inside `config`, that the per-driver schemas
exist but parse nothing, and that a misspelling one level down is still silent —
with the pointer to #4410.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY
@os-zhuang
os-zhuang marked this pull request as ready for review July 31, 2026 12:52
@os-zhuang
os-zhuang merged commit b7ed26d into main Jul 31, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/strict-schema-authz-surface-s8vnok branch July 31, 2026 12:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:data size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants