Skip to content

feat(spec,cli): 活性闸门开始对注册表负责 —— 并治理 datasource(43 条判定,20 条无消费者)(#4487) - #4489

Merged
os-zhuang merged 1 commit into
mainfrom
claude/datasource-config-validation-i7wdmo
Aug 1, 2026
Merged

feat(spec,cli): 活性闸门开始对注册表负责 —— 并治理 datasource(43 条判定,20 条无消费者)(#4487)#4489
os-zhuang merged 1 commit into
mainfrom
claude/datasource-config-validation-i7wdmo

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4487

闸门自己有个盲区

check-liveness.mtsGOVERNED 是一份手工维护的名单,从来没有任何东西拿它和它声称覆盖的注册表对过

结果:它治理 25 个已注册 metadata type 中的 15 个,同时报告自己完整。剩下 10 个是可授权的 —— /api/v1/meta/types/:type 提供它们,Studio 能编辑它们 —— 但从来没有被问过"谁读这个属性"。所以那些类型上的死键对 CI 不可见,而它们的沉默被读作成功

一份治理 15/25 却自报完整的名单,比一份承认缺口的名单更糟。

datasource 在这个状态里待了它的整个生命周期。#4410 / #4465 / #4481 在它身上手工挖出 6 个死键,其中两个是安全形状的:

  • schemaMode 在记录→连接规格之间掉了,一个 ObjectStack 绝不能跑 DDL 的外部库被当作 managed 构建
  • ssl 停在记录层,一个带 CA 证书的 TLS 块配置了零,且和生效的那个长得一模一样

闸门对此一言不发,因为这个类型不在名单上。

改了什么

1. 闸门对注册表负责(持久的那一半)

每个已注册类型必须在 GOVERNED 里,或者PENDING_GOVERNANCE 里带一条理由和一个 issue 号。注册一个类型却忘了账本 → CI 失败,并把该写的条目告诉你。

反方向也会烂,所以也失败:一个已经治理完的类型如果还留在 PENDING_GOVERNANCE 里,就是在声称一笔不存在的债,让"还剩多少"变成谎话。和 orphan ledger row 同一种腐烂,方向相反。

这是个棘轮,不是可以随便加的白名单。注释里写明了:为了让刚注册的类型变绿而加一条,正是这张表要暴露的失败本身;没有 issue 号的条目和"从没看过"无法区分。

负证明(silence must not read as success,这条闸门自己也得守):临时从 PENDING_GOVERNANCE 删掉 seed,闸门以 exit 1 失败并打印该类型 + 补救指引;恢复后 exit 0。

2. datasource 治理完毕

liveness/datasource.json,43 条属性全部带证据分类。结果是所有被治理类型中最高的 dead 占比:43 中有 20 条没有 runtime 消费者。

死簇 为什么
capabilities.*(11) 引擎的下推判断走的是 runtime driver 自己的 supports.* 对象(autonumber / batchSchemaSync / queryDateGranularity)—— 另一套机制,词汇表和这个块零重叠having-filter.ts:13 说得很直白:"SQL pushdown can come later behind a driver capability flag"
healthCheck.*(3) 没有任何东西调度 datasource 探活。连接活性是按需通过 driver handle 的 ping() 检查的
retryPolicy.*(4) 没有 connect 或 query 路径重试
external.label / external.requirePermission 无读者。后者是安全形状的:它读起来像访问门,但不是

3. 一处更正 —— 这是这次审计值得做的理由

capabilities.readOnly 读起来像安全开关,实际不守任何东西。而有两处已发布的处方把作者指向它:

两处现在都指向 external.allowWrites: false —— ObjectQL 引擎真正检查的写入门(engine.ts:620)。照旧建议做的作者,相信自己把一个数据源标成了不可写,而并没有。

这正是我在同一个文件里为 belongsInConfig 写过的那段失败:"把一个犯了可恢复错误的作者,用平台的权威指向一个同样错误再次沉默的位置。" 我在隔壁一个字段上做了同样的事,而且是在一个全部意义就是安全的属性上。

v17 release notes 里还有一句配套的假声明 —— 说未注册的 capabilities 键会让引擎停止下推、改在内存里算 —— 一并更正。

4. 作者警告闭环

CLI 建议 lint 是账本驱动的,所以 os compile 现在会警告设置了那 20 条中任何一条的作者。这需要账本之外的一行:把 datasource 加进 TYPE_COLLECTIONS

值得记一笔的区别:覆盖率靠标 authorWarn 增长,但仅限于 lint 已经在走的类型内部。一个新治理的类型如果没登记 collection,账本正确却警告不到任何人 —— 这正是 lint 存在要防的形状。

三个坑,每个都差点造成错判

  1. 同名不同类型。 healthCheck 全仓 20 处命中,没有一处属于 datasource(插件健康监控、AI model registry、connector、StartupOrchestratorOptions)。retryPolicy 更险 —— 它在 hookjob确实被强制执行。分辨靠形状:hook.retryPolicybackoffMs,datasource 用 baseDelayMs/maxDelayMs/backoffMultiplier,没有代码同时读两种拼写。
  2. preview renderer 不算消费者。 objectui 的 DatasourcePreviewpool/ssl/retryPolicy/healthCheck 渲染成面板 —— 一条都没有被当作证据feat(spec)!: 退休 datasource.readReplicas —— 声明了、strict 了、刚被加了校验,但没有任何东西打开过副本连接 (#4468) #4481 是最新的教训:readReplicas 唯一的"消费者"是一枚 pill。
  3. z.record 是账本盲区。 datasource.config 是开放 record,walk 到此为止,per-driver 键由 data/driver/*.zod.ts 管。这条显式记进了 config 的 note,而不是默默跳过 —— 沉默的盲区和不存在的盲区在文件里长得一样。

一件我没有做的事

liveness/README.md 的 per-type 计数表有几行陈旧。我试着机械重算,产生了两处回归query 的 7 个 experimental 来自 describe marker 不是账本条目;webhook 行是手工标注的),及时发现并回滚了。

原因是有两种口径在打架:README 自带的 python 片段数账本 JSON,闸门的 --json 还解析 marker 并对 children 不同下钻。修它需要先决定这张表是哪个口径,那是一个决定,不该夹在这个 PR 里顺手做。所以我只加了 datasource 行,并把这个坑连同"我踩过"一起写进了 README 和 #4488

验证

check:liveness               PASS
check:empty-state            PASS
check:authorable-surface     PASS
check:docs                   PASS
check:api-surface            PASS
check:spec-changes           PASS
check:upgrade-guide          PASS
check:skill-refs             PASS
check:skill-docs             PASS
check:skill-examples         PASS
check:strictness-ledger      PASS
  • @objectstack/spec — 285 files / 7248 tests passed
  • @objectstack/cli — 67 files / 689 tests passed(新增 3 条 datasource lint pin test:死块会警告、capabilities.readOnly 的 hint 必须点名 allowWrites、只设活属性时保持沉默)
  • 闸门负证明:删一条 PENDING_GOVERNANCE → exit 1 且打印补救指引;恢复 → exit 0

闸门输出的新一行:

datasource  43 classified (live 23, dead 20)
coverage: 18 type(s) governed, 9 registered type(s) awaiting a ledger
  (app, book, doc, email_template, job, mapping, seed, translation, validation)
  — a worklist, not a merge gate.

后续

#4488 —— 剩余 9 个类型的 worklist,PENDING_GOVERNANCE 每条都指向它。里面写了 datasource 这次用的方法(**先找类型的"边界结构"**是效率最高的一步 —— ConnectableDatasource + DatasourceConnectionSpec 一次判掉了 20 条里的大部分)、上面三个坑、README 计数口径那件事,以及一条明确要求:不要为了绿而批量填 live,橡皮图章账本比没有账本更糟。

那 20 条死属性本身是 ADR-0049 的退休 worklist,不在本 PR 范围 —— 账本的职责是记录判定authorWarn 负责告诉作者;退休是每个簇各自的决定,像 #4481 那样单独走。


Generated by Claude Code

…ype (#4487)

`GOVERNED` was a hand-maintained list and nothing compared it against the
registry it claims to cover. It governed 15 of 25 registered metadata types
while reporting itself complete: a type in the other ten was authorable —
served by /api/v1/meta/types/:type, editable in Studio — and was never asked
who reads its properties, so an inert key on it was invisible to CI and its
silence read as success.

`datasource` was in that state for its entire life. #4410, #4465 and #4481
found six inert keys on it by hand, two security-shaped: `schemaMode` was
dropped between record and connection spec, so a database ObjectStack must
never run DDL against was constructed as `managed`; `ssl` stopped at the
record, so a TLS block with a CA certificate configured nothing while looking
identical to one that worked.

The gate is now answerable to the registry. Every registered type must be in
GOVERNED or in PENDING_GOVERNANCE with a reason and an issue; registering a
type and forgetting the ledger fails CI with the entry to write. The reverse
rots too and also fails — a PENDING_GOVERNANCE row for a type since governed
claims a debt that no longer exists.

`datasource` is now governed: 43 properties classified with evidence, and the
result is the highest dead ratio of any governed type — 20 of 43 have no
runtime consumer. `capabilities.*` (11): the engine gates pushdown on the
runtime driver's own `supports.*` object, a non-overlapping vocabulary.
`healthCheck.*` (3): nothing schedules a datasource probe. `retryPolicy.*`
(4): no connect or query path retries. Plus `external.label` and
`external.requirePermission`.

One correction ships with this, and it is why the audit was worth doing.
`capabilities.readOnly` reads as a safety switch and gates nothing — and two
shipped prescriptions pointed authors at it: the externalSettingsUnknownKeyError
guidance in datasource.zod.ts and the #4465 changeset's relocation table. Both
now name `external.allowWrites: false`, the write gate the engine checks. The
v17 release notes carried a matching false claim about `capabilities` gating
pushdown; corrected here too.

The CLI advisory lint picks the ledger up, so `os compile` warns an author who
sets any of the 20. That needed `datasource` in TYPE_COLLECTIONS: coverage grows
by marking entries authorWarn only WITHIN a type the lint already walks, and a
governed type whose collection is unregistered has a correct ledger that warns
nobody.

Nine types remain ungoverned and are now enumerated rather than implied (#4488).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WsgTqRF58HsQYKLsrZ5pQY
@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 10:08am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data 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 2 package(s): @objectstack/cli, @objectstack/spec.

113 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 packages/cli, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli, @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/cli, 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/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via packages/cli, @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/cli, @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/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli, 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/authentication.mdx (via @objectstack/cli)
  • 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/cli, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/cli, @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/cli, @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • 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/cli, @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/cli, @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.

@os-zhuang
os-zhuang merged commit 0f9faa2 into main Aug 1, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/datasource-config-validation-i7wdmo branch August 1, 2026 10:25
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

2 participants