Skip to content

fix(spec): 上一个 PR 里的保护信封检查是空的 —— 它跳过了 25 个类型里的 24 个(#4001) - #4519

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

fix(spec): 上一个 PR 里的保护信封检查是空的 —— 它跳过了 25 个类型里的 24 个(#4001)#4519
os-zhuang merged 1 commit into
mainfrom
claude/strict-schema-authz-surface-s8vnok

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

紧接 #4514。那个 PR 加的不变量测试断言了两件事:每个注册元数据类型不拒收加载器盖的 ADR-0010 信封(硬 422 那一类),以及不静默丢失它。

拒收那一半是有效的——它第一次运行就抓到了 hookdatasource

另一半是空的。

它怎么空的

它用一个通用探针 body 去 parse 每个 schema,再看 _packageId 有没有活下来。但一个 schema 如果有探针没提供的必填字段,就会因为无关原因解析失败,断言直接 early return:

if (!result.success) return;   // ← 25 个类型里 24 个走的是这条路

只有 field 真的被检查过。整个套件报绿。

这就是这场战役的主题——成功信号掩盖遗漏——出现在为了检测它而建的仪器里,而且就在账本刚刚记下闸门非递归扫描那同一课之后一个改动

一个会跳过的检查,和一个会通过的检查,在外部完全无法区分。

修法:结构式遍历,跳不过去

声明侧改成直接走 schema 结构——拆开 lazy / pipe / optional / default,展开 union——问「有没有哪个解析出的 object shape 声明了这个键」。

这个问题不需要构造合法实例,所以不存在「因无关原因失败」的早退路径。

两个护栏让它保持诚实:

护栏 防的是什么
遍历器解析不出的类型 = 硬失败 遍历器沉默的那一刻,正是测试会悄悄停止覆盖的那一刻
债务清单带反向钉(某项修好时测试变红) 防止清单活得比债务久,开始豁免不再需要豁免的类型

它接着找到了什么

不是 1 个,是 8 个未声明信封的注册类型:

actionbookfieldjobmappingpagetranslationvalidation

探针版本藏了其中 7 个。每一个今天都在往返中丢保护元数据,且在它的 schema 被收紧那天会变成硬 422。

本 PR 修掉 jobbook,清单剩 6 个。

一个开始重复的模式

这是同一个模式的第三次,出现在三个不同的仪器上:

仪器 它谎报的覆盖度 发现于
账本闸门 目录扫描不递归 → data/driver/ 九个站点隐形 #4412
严格性站点计数 strictObject( 不算站点 → 「解决了」和「删掉了」同数 #4514
信封探针 无关失败早退 → 24/25 静默跳过 本 PR

三个都是测量工具报告了自己并不具备的覆盖度。账本里现在写下了这条反复被重新推导出来的规则:

信一个绿色检查之前,先让它在一个你确知存在的东西上变红。

验证

  • @objectstack/spec282 文件 / 7141 用例通过tsc --noEmit 干净
  • 不变量测试从 51 项增到 77 项——差额就是此前被静默跳过的那些
  • 8 个生成物闸门 up-to-date(唯一的重新生成是 book / job 两张信封键表)
  • 15 个 check:* 闸门全绿

参考

🤖 Generated with Claude Code

https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY


Generated by Claude Code

…f 25 types (#4001)

The invariant test added one change ago asserted two things about every
registered metadata type: that it does not REJECT the ADR-0010 envelope its
loader stamps (the hard-422 case), and that it does not silently lose it.

The reject half worked — it found `hook` and `datasource` on its first run.

The other half did not. It probed each schema with one generic body and asked
whether `_packageId` survived. A type whose required fields that body did not
supply failed for unrelated reasons, and the assertion returned early. TWENTY-
FOUR of the twenty-five types took that early return. Only `field` was ever
really checked, and the suite reported green.

That is this campaign's own subject matter — a success signal covering an
omission — reproduced inside the instrument built to detect it, one change after
the ledger recorded the identical lesson about the strictness gate's
non-recursive directory walk. A check that skips is indistinguishable from a
check that passes.

The declaration side is now STRUCTURAL: it walks the schema, unwrapping
lazy/pipe/optional/default and expanding unions, and asks whether any resolved
object shape declares the key. That needs no valid instance, so it cannot skip.
Two guards keep it honest:

  - a type the walker cannot resolve is a hard FAILURE, not a pass. The walker
    going quiet is exactly when this test would otherwise stop covering
    something.
  - the debt list carries a reverse pin that fails when an entry is fixed, so
    the list cannot outlive the debt it tracks.

What it found: 8 registered types do not declare the envelope, not 1 — `action`,
`book`, `field`, `job`, `mapping`, `page`, `translation`, `validation`. Each
loses protection metadata on every round-trip today and becomes a hard 422 the
day its schema closes. `job` and `book` are closed here; 6 remain listed.

Three occurrences now of one pattern, in three different instruments: the ledger
gate's non-recursive walk, `strictObject(` not matching the site count, and this
early return. Every one was a measuring tool reporting coverage it did not have.
The ledger now states the rule it keeps re-deriving: before trusting a green
check, make it go red on something you know is there.

Verified: spec 282 files / 7141 tests, `tsc --noEmit` clean, all 8 generated
artifacts current (the only regeneration is the two envelope key tables), all
15 `check:*` gates green.

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 3:18pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:system tests tooling size/m 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:system size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants