Skip to content

feat(spec)!: validation 的六个变体各自按自己的键集收紧(#4001 批 3b) - #4527

Merged
os-zhuang merged 1 commit into
mainfrom
claude/strict-schema-authz-surface-s8vnok
Aug 1, 2026
Merged

feat(spec)!: validation 的六个变体各自按自己的键集收紧(#4001 批 3b)#4527
os-zhuang merged 1 commit into
mainfrom
claude/strict-schema-authz-surface-s8vnok

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

#4001 批 3 后半(清单)。批 3a = #4522,已合并。

validation 是这场战役一直往后推的那个注册类型:z.lazy() 判别联合,六个变体各自 .extend() 共享基类,其他类型用的「一次 strictObject 调用」在它身上不成立。

为什么不能只收基类

.extend() 会继承 strict,所以只收 BaseValidationSchema 也能正确拒绝未知键。

但错误映射闭包捕获的是它被构造时的那份键列表,对基类而言只有共享键。于是变体自己的键拼错——transtions 之于 transitionsjsonschema 之于 schema——会被拒绝,但给不出改名建议

那正是「可修的错误」和「令人困惑的错误」之间的差别,也正是这场战役坚持「拒绝必须带上修法」的全部理由。

联合按 type 判别,作者永远只落在一个变体上,所以那个变体的完整键集才是正确的候选集。基类现在是一个命名 shape,展开进六个 strictObject 调用,每个配自己词汇表的别名。

BaseValidationSchema 这个对象已删除——从来没有任何东西单独解析基类

保护信封

validation 是注册类型,加载器给它盖 _packageId / _provenancegetMetaItemLayeredsaveMetaItem 往返时带着它们——而 schema 表达不了,所以每次解析都被丢弃。

现在声明在共享 shape 里,六个变体一次继承。该类型从 kernel/metadata-type-schemas.test.ts 的债务清单划掉——那个清单带反向钉,修好了不删条目测试就红,所以删除是被强制的而不是可选的。

剩 5 个:action · field · mapping · page · translation

闸门又得学一次新写法

账本闸门的「声称 strict 的行必须真的 strict」检查只匹配字面的 .strict(),于是改用 strictObject 的文件读起来像不 strict,闸门把一个真话判成了谎话

和上一批站点计数撞到的是同一个盲点,原因也一样:写法一变,测量工具就得跟着学一次。两处现在都接受两种拼写。

这是本战役第五次同形的事:测量工具跟不上被测量的东西。

作者可见的影响

六个变体都没声明的键,现在被拒绝而不是静默丢弃——它本来就在被忽略,所以没有任何正在工作的行为改变

拒绝信息会点名它落在哪个变体上("this state-machine validation rule")、回显键、并从那个变体自己的键集里给出最近的建议。

验证

  • @objectstack/spec284 文件 / 7187 用例通过(对合并后的 main),tsc --noEmit 干净
  • 8 个生成物闸门 up-to-date(唯一的重新生成是六个变体的信封键表)
  • 15 个 check:* 闸门全绿
  • 直接实测四条:合法规则通过 ✓ / 未知键被拒 ✓ / 变体自己的键拼错拿到改名建议 ✓ / 信封被接受 ✓

参考

🤖 Generated with Claude Code

https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY


Generated by Claude Code

…wn key set (#4001)

`validation` was the registered metadata type this campaign kept deferring: a
`z.lazy()` discriminated union whose six variants each `.extend()` a shared
base, so the one-call `strictObject` conversion the other types took does not
apply to it.

WHY NOT JUST CLOSE THE BASE. `.extend()` inherits strictness, so closing
`BaseValidationSchema` alone would have rejected unknown keys correctly. But an
error map closes over the key list it was BUILT with, and for the base that is
only the shared keys — so a typo of a variant's own key (`transtions` for
`transitions`, `jsonschema` for `schema`) would have been rejected with no
rename offered. That is the difference between a fixable error and a confusing
one, and it is the whole reason the campaign insists rejections carry the fix.

The union discriminates on `type`, so an author is always on exactly one
variant and that variant's FULL key set is the right candidate list. The base is
now a named shape spread into six `strictObject` calls, each with the aliases
that fit its own vocabulary. No `BaseValidationSchema` object remains — nothing
ever parsed the base alone.

THE ENVELOPE. `validation` is registered, so the loader stamps `_packageId` /
`_provenance` on it and `getMetaItemLayered` → `saveMetaItem` round-trips a body
carrying them — and the schema could not represent them, so they were dropped on
every parse. Declared once in the shared shape, inherited by all six. The type
comes off the debt list in `kernel/metadata-type-schemas.test.ts`, which carries
a reverse pin, so removing the entry was forced rather than optional. Five
remain: action, field, mapping, page, translation.

AND THE GATE LEARNED THE IDIOM AGAIN. Its strictness-claim check matched only a
literal `.strict()`, so a file converted to `strictObject` read as NOT strict and
the gate called a true claim a lie. Same blind spot the site count had one batch
ago, for the same reason: a measuring tool has to learn the idiom whenever the
idiom changes. Both now accept either spelling.

Authoring impact: a key none of the variants declares is rejected instead of
silently discarded — it was already being ignored, so no working behavior
changes. The rejection names which variant it landed on ("this state-machine
validation rule"), echoes the key, and suggests from that variant's own set.

Verified: spec 283 files / 7159 tests, `tsc --noEmit` clean, all 8 generated
artifacts current (the only regeneration is the six variants' envelope tables),
all 15 `check:*` gates green. Probed directly: valid rule parses, unknown key
rejected, a variant-specific typo gets its rename, envelope accepted.

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

vercel Bot commented Aug 1, 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 Aug 1, 2026 4:47pm

Request Review

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

github-actions Bot commented Aug 1, 2026

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.

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