Skip to content

feat(spec,metadata-protocol,metadata,objectql,service-automation): stored metadata replays the full conversion chain at rehydration (#3903) - #4317

Merged
os-zhuang merged 2 commits into
mainfrom
claude/spec-contract-metadata-rehydration-176275
Jul 31, 2026
Merged

feat(spec,metadata-protocol,metadata,objectql,service-automation): stored metadata replays the full conversion chain at rehydration (#3903)#4317
os-zhuang merged 2 commits into
mainfrom
claude/spec-contract-metadata-rehydration-176275

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #3903.

决定:选项 1(在存量读取路径上转换),并回答了 registry 吞异常的问题

#3903 列了三条路。选 1 的理由:#3855 已经证明不能依赖运营方主动跑迁移(选项 2 只帮跑了的人);选项 3 会把 PD #12 点名的债务(裸 ??、各消费端自行容错)固化为永久政策。选项 1 让转换层变成真正普适的契约机制,并给了 rule-validator.ts 那个"永远等不来退休"的 ?? 一个真实的退场。

数据静置(data at rest)的政策,一句话

退休(retiredFromLoadPath)是"创作面"的事件;存量行没有作者可教,所以存量读取路径重放完整链(含已退休条目)。 窗口与 tombstone 继续管创作面(normalizeStackInput 只跑 live-window、schema 照旧硬拒),saveMetaItem 的 422 网关保证新写入永远是 canonical——所以存量转换是一个只会收缩的集合。已写入 ADR-0087 附录与 PD #12

改了什么

  • spec:新原语 applyConversionsToStoredItem(type, item, options?)(conversions/stored.ts),把一条存量行按其元数据类型包进栈集合、以 includeRetired: true 重放全链。幂等、不抛、不校验。
  • metadata-protocol:接入 loadMetaFromDbgetMetaItems(active + drafts)、getMetaItem(active + draft)、getMetaItemLayeredduplicatePackage(复制即新写入,先转换再过网关——遗留行终于能被复制,且副本是 canonical)。通知有进程级去重,避免每次列表读取都刷日志。
  • metadata:DatabaseLoader 活行读取(load/loadMany)转换;history 保持原样(版本层记录"写下的是什么",checksum↔body 必须对应;SysMetadataRepository 同理不转换——转换发生在"行变成被服务的元数据"处,不在版本存储处)。
  • objectql:authored action/hook 直读表的两个缝隙转换(pre-17 存量 action 行的 execute 现在真的能以 target 派发);rule-validator 删除 requiredWhen ?? conditionalRequired——feat(spec)!: retire the last three deprecated authorable aliases (#3855) #3883 里我承诺"迁移后退休"、[P2] The spec contract stops at authored source — stored metadata is rehydrated unparsed, unconverted, and ungated #3903 里证明其实没有任何迁移机制,现在链在每个缝隙上跑,它可以退了。
  • service-automation:registerFlowincludeRetired。这一点刚好被 main 上新合入的 wait 声明了超时契约但完全没有实现:onTimeout 零读取者,timeoutMs 被当成定时时长用 —— showcase 自己在依赖它 #4158 现场验证:flow-node-wait-timeout-keys-removed 是 17 就 retired 的流转换、FlowSchema 同步 tombstone 了 timeoutMs/onTimeout——不带 includeRetired 的话,携带这些键的存量流会从"能跑"直接变成"注册失败"。通用元数据缝隙刻意跳过 flow 类型:流转换带 ADR-0078 开放命名空间冲突守卫,需要自动化引擎的活 executor 注册表(reservedNodeTypes),只有 registerFlow 有。

registry.ts 吞校验异常的"自己的答案"

维持注册、但不再是一句耸肩:

  • loadMetaFromDb 现在对转换后的行做 spec 校验(转换前校验必然对链上历史误报),返回 { loaded, errors, invalid },每条真实违约行以稳定标记 [metadata_spec_invalid] 告警并给出处方;
  • 仍然注册,这是写明的决定:启动期拒绝会把活表的数据入口一起拆掉,行在 Studio 里连列出、打开、修复都做不到——可用性优先于纯洁性。硬网关在有作者在场的地方:写入端 saveMetaItem 422 + 读取端 _diagnostics 徽章(同一校验函数,现在因为先转换而不再误报链上历史);
  • registerItem 的校验钩子在代码里明确注释为"诊断、非网关",日志同样带稳定标记。

测试

  • spec/conversions/stored.test.ts(8):retired 条目重放、嵌入 action、复数类型名、幂等、不可变、未知类型直通、冲突守卫透传。
  • metadata-protocol/protocol.stored-conversions.test.ts(6):直接把遗留行塞进 stub 引擎(正是绕过网关的静置数据),验证 getMetaItems/getMetaItem/loadMetaFromDb 的转换、_diagnostics 不再误报、flow 跳过、invalid 计数 + 照常注册。
  • rule-validator.test.ts:原"honors the conditionalRequired alias"改为两条——alias 不再被读(PD Add comprehensive test suite for Zod schema validation #12 钉死)、经存量链转换后规则照常执行。
  • 合并 main 后全量重跑:spec 7136+、objectql 1359、metadata-protocol 128、metadata 281、service-automation 482,全绿;check:generated 8/8(api-surface 已再生成)。

🤖 Generated with Claude Code

os-zhuang and others added 2 commits July 31, 2026 13:36
…ored metadata replays the full conversion chain at rehydration (#3903)

The spec contract stopped at authored source: sys_metadata rows were
rehydrated unparsed and unconverted, so the authored and stored contracts
silently diverged (option 1 of #3903, chosen because #3855 already concluded
operator-run migrations cannot be relied on, and out-of-scope-by-policy would
fossilize the accommodations PD #12 names as debt).

- spec: new `applyConversionsToStoredItem(type, item, options?)` — one
  primitive encoding the data-at-rest policy: the FULL chain replays,
  retiredFromLoadPath entries included, because retirement is an
  authoring-surface event and a row at rest has no author to teach.
- metadata-protocol: wired at loadMetaFromDb, getMetaItems (active+drafts),
  getMetaItem (active+draft), getMetaItemLayered, duplicatePackage. Flow rows
  are deliberately skipped (the flow conversions' open-namespace conflict
  guard needs the automation engine's executor registry).
- metadata: DatabaseLoader live-row reads convert; history stays verbatim
  (the version layer records what was written — checksums must keep pairing).
- objectql: authored-action/-hook table reads convert (a stored pre-17 action
  row's `execute` dispatches via `target` again); the rule-validator's
  `requiredWhen ?? conditionalRequired` fallback — kept in #3883 with a
  retirement promise that had no mechanism — is deleted, its job done by the
  chain at every seam.
- service-automation: registerFlow passes includeRetired, so stored flows
  keep canonicalizing after their conversions graduate out of the window.
- registry.ts swallow answered (#3903 closing note): loadMetaFromDb validates
  the CONVERTED row, returns {loaded, errors, invalid}, and warns with a
  stable [metadata_spec_invalid] marker; registration proceeds deliberately
  (refusal at boot unhooks live tables and makes the row unfixable in
  Studio) — the enforcing gates are saveMetaItem's 422 and _diagnostics on
  read, and the registerItem hook is now documented as the diagnostic it is.

Policy written down in the ADR-0087 addendum ("stored metadata replays the
chain") and PD #12.

Closes #3903.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@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 5:45am

Request Review

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling and removed size/l labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 5 package(s): @objectstack/metadata-protocol, @objectstack/metadata, @objectstack/objectql, @objectstack/service-automation, @objectstack/spec.

111 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/service-automation, @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 @objectstack/metadata-protocol, @objectstack/metadata, @objectstack/objectql, 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 packages/objectql, @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/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • 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 packages/metadata, @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/metadata, @objectstack/objectql, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • 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/objectql, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/metadata, @objectstack/objectql, @objectstack/service-automation, @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/objectql, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/metadata-service.mdx (via @objectstack/metadata)
  • 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 packages/objectql, @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/objectql, @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/objectql, @objectstack/service-automation, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/metadata, @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/objectql, @objectstack/service-automation, @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 tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] The spec contract stops at authored source — stored metadata is rehydrated unparsed, unconverted, and ungated

1 participant