Repository navigation
Description
#4465 和 #4481 一共在 DatasourceSchema 上处置了 6 个"声明了但没接上"的键。它们不是被闸门抓到的,是人一个个闭合调用图挖出来的。
原因很结构性:packages/spec/scripts/liveness/check-liveness.mts 的 GOVERNED 列表里没有 datasource。
const GOVERNED = ['object', 'field', 'flow', 'action', 'hook', 'permission', 'position',
'agent', 'tool', 'skill', 'dataset', 'page', 'view', 'report',
'dashboard', 'webhook', 'query'];packages/spec/liveness/ 下也没有 datasource.json。所以活性闸门从来没问过这个类型的任何一个属性"谁读它"。
手工挖出来的那 6 个
| 键 | 当时的状态 | 处置 |
|---|---|---|
datasource.config |
整个槽零校验;config: { hostname: … } 静默连 localhost |
#4410 → 按驱动契约校验 |
datasource.pool |
声明了、带进连接规格了,然后被硬编码 { min: 0, max: 5 } 覆盖 |
#4465 → 接上 |
datasource.schemaMode |
在记录→连接规格之间掉了,external 库被当 managed 构建(DDL 未设防) |
#4465 → 接上 |
datasource.ssl |
停在记录层,从没放上连接规格 —— TLS 配了等于没配 | #4465 → 接上 |
memory indexes / maxRecordsPerObject |
InMemoryDriverConfig 没有对应字段 |
#4465 → 删除 |
datasource.readReplicas |
没有驱动打开过副本连接 | #4481 → 删除 |
其中 schemaMode 和 ssl 是安全/正确性形状的:一个让 ObjectStack 对"绝不能跑 DDL"的外部库跑了 DDL 的路径,一个让 TLS 配置看起来生效实则没有。这类正是活性账本存在的理由,而它们在一个不受账本管辖的类型上躺了不知道多少个 release。
为什么"补一个 ledger 文件"不是全部工作
datasource 在 BUILTIN_METADATA_TYPE_SCHEMAS 里,所以 getMetadataTypeSchema('datasource') 应该能解析出来,加进 GOVERNED 是一行。真正的工作在后面:
--dump datasource出属性清单,然后逐条闭合调用图给出live/dead/experimental判定 + evidence +verifiedAt。这是主要成本,也是唯一有价值的部分 —— 批量填live等于把闸门变成橡皮图章- 注意
config是z.record,闸门的 children 下钻到此为止。per-driver 的形状(driver/*.zod.ts)不在 walk 范围内,账本表达不了"config.host是活的"。需要想清楚这一层怎么记,或者显式记成一条 note 说明边界在哪 - 别把 preview renderer 当证据。objectui 的
DatasourcePreview会回显pool/ssl/retryPolicy/healthCheck——liveness/README.md有专门一节讲这个,2026-06 那次仅凭 preview 定性的 13 个属性复核后错了 10 个。feat(spec)!: 退休 datasource.readReplicas —— 声明了、strict 了、刚被加了校验,但没有任何东西打开过副本连接 (#4468) #4481 刚踩过:readReplicas在 objectui 唯一的"消费者"就是一枚 pill authorWarn+ CLI 建议 lint 会随账本自动生效,判定错了会直接喷到作者脸上
顺带一个更大的问题
datasource 是不是唯一漏网的?GOVERNED 有 17 项,BUILTIN_METADATA_TYPE_SCHEMAS 有多少?两者的差集值得列一下 —— 如果还有别的注册类型不在名单里,那本 issue 应该升级成"把差集补齐 + 加一条元闸门(新注册的 metadata type 必须同时进 GOVERNED)",否则下一个类型还会以同样的方式漏掉。
建议先跑这一条,因为它决定本 issue 的形状:是补一个类型,还是补一个机制。
验收标准
datasource(以及差集里的其他类型)进入GOVERNED,liveness/datasource.json每个可授权属性都有判定 + evidence +verifiedAt- 每条
live的证据指向真正的 runtime reader,不是 form/preview renderer config这类z.record边界在账本里显式记录,而不是沉默略过liveness/README.md的 per-type 表和计数同步更新(用 README 里的 python 片段重算,别手改)- 如果差集不止一个类型:加一条闸门,让新注册的 metadata type 不进 GOVERNED 就失败
参考
- datasource.config 至今无人校验:驱动 configSchema 是声明但完全惰性的(ADR-0049 enforce-or-remove,#4001 收尾发现) #4410 / feat(spec,service-datasource): datasource.config 按驱动契约校验 (#4410) #4465 ——
datasource.config驱动契约校验,以及顺带接上的pool/schemaMode/ssl - feat(spec)!: 退休 datasource.readReplicas —— 声明了、strict 了、刚被加了校验,但没有任何东西打开过副本连接 (#4468) #4481 —— 移除
readReplicas packages/spec/liveness/README.md—— 判定方法论,尤其 "⚠️ An authoring/preview renderer is NOT a runtime consumer".claude/skills/spec-property-retirement- ADR-0049 enforce-or-remove / ADR-0078 no-silently-inert-metadata
未指派 —— 按 AGENTS.md 的约定,这是一条记录下来的 finding,谁开工谁认领。
Activity
feat(spec,cli): the liveness gate governs every registered metadata t…
feat(spec)!: remove the trigger-registry Connector cluster (objectsta…
chore(spec): 把 `api` 纳入 liveness 治理并播种台账;重生成三份参考文档 (#5271)
feat(spec): `api` 补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADAT…
spec(lint): honour the `datasource` runtime-create declaration at the…