Skip to content

feat(migrate): os migrate value-shapes —— 引用/结构化 JSON 值形态的按部署门禁(#3438 第 2 项) - #4235

Merged
os-zhuang merged 4 commits into
mainfrom
claude/d1-d2-strict-default-flip-vbly5z
Jul 30, 2026
Merged

feat(migrate): os migrate value-shapes —— 引用/结构化 JSON 值形态的按部署门禁(#3438 第 2 项)#4235
os-zhuang merged 4 commits into
mainfrom
claude/d1-d2-strict-default-flip-vbly5z

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

ADR-0104 D1 的第二个证据门禁(#3438 第 2 项)

媒体类已由 #3681 按部署翻转;本 PR 给引用(lookup/master_detail/user/tree)与结构化 JSON(location/address/composite/repeater/record/vector建立它们自己的门禁,而不是去借文件迁移那个标记——后者断言的是「文件值已迁移、归属已对账」,对 lookup id 或 location 载荷是否规范什么都没说

os migrate value-shapes           # 扫描:只报告,不写任何东西
os migrate value-shapes --apply   # 扫描 + 零违规时记录部署标记

刻意没有回填

姊妹迁移会转换遗留文件值,因为是平台收窄了那个存储形态、因此欠这笔转换。而畸形的 location 是应用数据,正确值只有作者知道。所以本命令只报告并给出处方(点名对象、字段、类型、条数、样本 record id、parse issue),由运维修完重跑。

由此得到一个漂亮的简化:没有可转换的东西,--apply 唯一的写入就是标记行,于是 #3617 的不变量平凡成立——dry run 什么都不改,且「这次运行是否改变了本部署的姿态」从不取决于它发现了什么。

反漂移:扫描器与校验器共用同一个谓词

valueShapeViolation / isScannableValueShapeFieldrecord-validator 导出、被扫描器 import。两份「什么算畸形」的实现只要差一个子句,部署就会通过扫描却仍被拒写——那等于标记在断言一个校验器不认的事实,正是 ADR 上一层禁止的「借来的证据」。有一个测试直接钉住这条属性:同一个值必须既被扫描器计数、又被 strict 写入路径拒绝。

分层:扫描器不写标记

scanValueShapes 是只读的(它接受的 engine 类型根本没有写入面)。标记的读者用 spec 契约,只有写者依赖 platform-objects——这是 sys-migration.object.ts 自己写下的设计意图。让引擎去写标记会反转依赖方向,所以组合放在 CLI 命令里。

其他

  • OS_ALLOW_LAX_VALUE_SHAPES 逃生阀,优先级与媒体半边一致:opt-out > 全类 opt-in > 标记。矛盾配置落在安全侧(错误地宽松只是没人看的告警,错误地严格是能工作的应用停止写入)。
  • 引擎两个标记的读取重构成一个按 id 参数化的 helper,"所有不知道的方式都答 false" 只写一遍。
  • 截断或有对象读不出来的扫描,即使零违规也不开门——「我们读到的那部分里没有」不是标记所断言的命题。

#4215 的相遇(合并 main 后)

本 PR 开着的时候,#4215#3438 第 3 项(新库从空创建时记账两个标记)落到了 main 上,并顺带在 migration.zod.ts 里声明了 VALUE_SHAPES_MIGRATION_ID——两边同名常量,这是本次唯一的冲突,解法是留一份声明加 main 的 CREATION_ATTESTED_MIGRATION_IDS。已核对 #4215engine.ts 的改动(getSchemaSyncStats 聚合)在合并后完整保留。

合并暴露出文档三处不自洽,一并修掉(见 13606e0):

  • 新小节插进了 files-to-references 小节中间,把它的收尾段和「写入规则」callout 劈到了新小节后面——挪回各自命令名下。
  • 那句「其他值类不受影响,lookup/location 保持 warn-first」现在有了自己的门禁,改为指向它。
  • v17 发布说明由 feat(migrate): 从空创建的数据库在创建时刻自我认证数据迁移 — ADR-0104 fresh-datastore attestation (#3438) #4215 写下「attests both flags」,但第二个标记及其命令在发布说明里从未出现过;升级清单里「OS_DATA_VALUE_SHAPE_STRICT_ENABLED 会打开一些背后没有迁移的值类」也不再成立。补上命令、分开标记的理由,以及自己的升级清单条目。
  • 「从空创建」那节的逃生阀只提了 OS_ALLOW_LAX_MEDIA_VALUES,补上本 PR 引入的 OS_ALLOW_LAX_VALUE_SHAPES

验证(合并 main 之后重跑)

套件 结果
@objectstack/objectql 1277 passed
@objectstack/spec 7163 passed
@objectstack/cli 622 passed
@objectstack/service-storage 256 passed
@objectstack/platform-objects 246 passed
@objectstack/driver-memory 265 passed
spec check:generated(8 项生成物) 全 PASS
check-release-notes / check-doc-authoring PASS
ESLint(全部改动 TS 文件) 干净
docs 站点构建 PASS

全量构建 71 包通过。(objectql +5 / spec −4 相对合并前,来自 #4215 新增测试与 #4233 退休 plugin 生命周期钩子。)

一个顺带发现(另开 issue,未在本 PR 扩大范围)

sys_migration 目前只由 service-storage 注册——这在只有存储一个消费者时说得通,现在有了第二个与存储无关的消费者。实际部署路径没问题(os serve 会自动装配 storage),但这层耦合应当解开:账本是平台基础设施,不该由一个可选服务持有。已在 data-migration-plugins.ts 注释中记录。

关联

#3438 三项:第 1 项已合并(698cbc2),第 3 项由 #4215 合并,本 PR 是第 2 项——合入后 #3438 全部完成。

🤖 Generated with Claude Code

https://claude.ai/code/session_016zgA8CQMJeJbFEjnbib1Uv

…r reference and structured-JSON value shapes (#3438)

ADR-0104 D1's second evidence gate. Media value shapes already enforce once a
deployment verifies its file migration (#3681); the reference and
structured-JSON classes now get a gate of their own rather than borrowing that
one — the file flag attests that file values were migrated and reconciled and
says nothing about whether a `lookup` id or a `location` payload is well
formed.

- spec: `VALUE_SHAPES_MIGRATION_ID` beside its file sibling.
- objectql: `scanValueShapes` walks every stored value of the covered classes
  against the write path's own predicate — `valueShapeViolation` /
  `isScannableValueShapeField` are exported from record-validator and imported
  by the scan, so the two cannot drift into disagreeing about "malformed".
  A test pins that property directly.
- objectql: `validateRecord` gains `valueShapeStrict` beside
  `mediaValueShapeStrict`, and the engine reads the second flag through the
  same memoized seam. The two flag reads are refactored into one
  id-parameterised helper so "every way of not knowing answers false" is
  written once.
- cli: `os migrate value-shapes`, dry-run by default. No backfill — a
  malformed `location` is application data whose correct value only its author
  knows, so the run reports and prescribes. With nothing to convert,
  `--apply`'s only write is the flag row, which preserves #3617's invariant
  trivially.
- New escape hatch `OS_ALLOW_LAX_VALUE_SHAPES`, same precedence as its media
  sibling: opt-out beats all-class opt-in beats the flag.

The scanner deliberately does NOT record the flag: readers of a migration flag
use the spec contract and only writers depend on platform-objects, so having
the engine write one would invert the layering. The CLI composes the two.

A truncated or partially-unreadable scan fails the gate even at zero
violations — "none in the part we read" is not the claim the flag makes.

Verified: objectql 1272, spec 7167, cli 621, service-storage 252 green; all
ten spec artifact gates pass (api-surface regenerated for the new exports);
ESLint clean on every changed file.

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

vercel Bot commented Jul 30, 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 30, 2026 6:39pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/cli, @objectstack/objectql, @objectstack/spec.

114 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 packages/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 @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/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • 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/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/objectql, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli, @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/cli, @objectstack/objectql, @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/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 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/cli, @objectstack/objectql, @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/objectql, @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.

claude added 3 commits July 30, 2026 17:05
The docs-drift check on the command's own PR flagged content/docs/deployment/cli.mdx,
and that one was a real gap rather than package-level noise: the file documents
`os migrate files-to-references` in full, so shipping a second gated data
migration without an entry would have left it discoverable only by reading the
source.

Covers the deliberate asymmetry (this run converts nothing — a malformed
`location` is application data whose correct value only its author knows), the
truncation rule (a partial scan cannot open the gate), and why the flag is
separate from the file migration's rather than reusing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgA8CQMJeJbFEjnbib1Uv
…efault-flip-vbly5z

# Conflicts:
#	packages/spec/src/system/migration.zod.ts
…otes

#4215 landed #3438's third item (a store created from empty attests both
flags) while this branch was open, so the merged docs claimed "both flags"
without the second one ever being named.

- cli.mdx: the file migration's closing paragraph and writing-rules callout
  had been split off from their own section by the new one inserted above
  them; move them back so each command's rules sit under that command, and
  point the "other value classes keep warning" sentence at the gate that now
  exists for them.
- cli.mdx: the created-from-empty section offers an escape hatch per class,
  so it names both — the media one and the one this branch adds.
- v17.mdx: document `os migrate value-shapes` and why its flag is separate,
  and give the upgrade checklist its own bullet. The old wording told readers
  OS_DATA_VALUE_SHAPE_STRICT_ENABLED opts in "classes with no migration behind
  them", which stopped being true here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016zgA8CQMJeJbFEjnbib1Uv
@os-zhuang
os-zhuang marked this pull request as ready for review July 30, 2026 19:20
@os-zhuang
os-zhuang merged commit 3aef718 into main Jul 30, 2026
26 of 27 checks passed
@os-zhuang
os-zhuang deleted the claude/d1-d2-strict-default-flip-vbly5z branch July 30, 2026 19:21
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/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants