Skip to content

fix(#4560): defaultValue 运行时令牌不再下发为列 DEFAULT - #4598

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-4560-ddl-runtime-token-default
Aug 2, 2026
Merged

fix(#4560): defaultValue 运行时令牌不再下发为列 DEFAULT#4598
os-zhuang merged 1 commit into
mainfrom
claude/issue-4560-ddl-runtime-token-default

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #4560

根因:两侧各认识一半的令牌

Field.user({ defaultValue: 'current_user' })引擎在插入时解析;没有登录用户时(system/anonymous 写入:种子重放、包安装、启动期供给)applyFieldDefaults 刻意不落值,而不是盖一个假 owner。

SQL 的 DDL 从来不知道这个令牌。createColumn 把任意非对象 defaultValue 原样交给 col.defaultTo(dv),于是列被建成 DEFAULT 'current_user'数据库覆盖了引擎的决定:每一次省略该字段的插入,都往 lookup('sys_user') 列里写进字面串 current_user —— 一个不是任何用户 id 的值。?expand 解析到空;用在 owner/审批人字段上就是一条静默的错误归属。

这条只能被 #4551 的悬空引用巡检事后发现:#4441 的引用完整性校验只看调用方给出的值,而这里调用方和引擎都什么都没给。

紧邻的上一个分支里 'NOW()' 早就被特判成驱动原生默认值,理由完全相同 —— current_user 是同一个约定家族的成员,只是在 DDL 能看见的地方从来没有登记过。

修法:令牌词汇表只声明一次

新增 packages/spec/src/data/default-value-tokens.tsDEFAULT_VALUE_TOKENS 加四个判定式(isRuntimeDefaultToken / isNowDefaultToken / isCurrentUserDefaultToken / isAppResolvedDefaultToken)。引擎的插入时解析与驱动的 DDL 读同一份集合 —— 这才是缺陷本身。把令牌写在 spec 里也意味着明天新增一个令牌会自动被排除在字面列 DEFAULT 之外,而不是像这次一样把自己的拼写漏进数据库。

依赖方向是干净的:spec 是叶子包,objectqldriver-sql 都已经依赖它,没有引入任何新的边。

列默认值的发出收敛到一个方法(applyDeclaredColumnDefault,建列与 SQLite 重建共用):

defaultValue 列 DEFAULT
'NOW()' 驱动原生规范默认值(不变)
其他运行时令牌 不发出(引擎在应用层负责)
Expression 信封 { dialect, source } 不发出(不变)
真正的字面量 原样发出(不变)

既有表:走既有的 schema-drift 迁移路

已建的列带着错误的 DEFAULT,所以修正走 #2186 的托管漂移检测,而不是另起一条专用迁移:

  • 新的 default_mismatch 发现 + drop_column_default 操作,归类 safe(语句不会失败,也不触碰任何行);
  • 开发态 autoMigrate: 'safe' 的启动会自动 reconcile(showcase 下次启动即修正),其余环境按既定礼节由 os migrate apply 施加,并带可执行的告警文案;
  • Postgres/MySQL 用 ALTER COLUMN … DROP DEFAULT;SQLite 不能就地改默认值,走既有的整表重建 —— 重建现在从 metadata 重新物化每一列的默认值,所以同表的 defaultValue: 'NOW()' 兄弟列不会被重建顺手抹掉(这是重建路径原本就有的隐患,本 PR 必须先堵住它才敢用)。

判定只认令牌自身的拼写(physicalDefaultIsToken 会剥掉方言的引号与 ::type 转型),一个 DBA 手工设的真实字面默认值不会被误伤。

已写入的错误行不改写。 这是 #4551 的既定哲学 —— 只报告,不改写 —— 那两行继续对悬空引用巡检可见,由运维依据报告决定处置。

测试

  • packages/plugins/driver-sql/src/sql-driver-runtime-token-default.test.ts(11 例):current_user 列建出来没有任何数据库默认值、无用户上下文的插入落 NULL 而不是字面串、'NOW()' 行为不变、漂移被报为 safe/drop_column_defaultautoMigrate=safe 的启动修正后续插入、既有错误行保持不变、重建不误伤兄弟默认值、真实字面默认值不被误判。其中一例遍历 spec 的 DEFAULT_VALUE_TOKENS 本身,所以 DDL 若退回硬编码单个名字会在下一个令牌加入时立刻失败。
  • 反向验证:临时删掉 applyDeclaredColumnDefault 里的令牌排除分支,上述 3 条立刻复现字面 DEFAULT(3 failed | 8 passed),恢复后 11 例全绿。
  • packages/objectql/src/engine-default-value-tokens.test.ts(4 例):引擎侧契约 —— 有用户时盖 id、system 写入保持 unset、显式 null 视作未提供、近似拼写仍是字面量(不是别名)。
  • packages/spec/src/data/default-value-tokens.test.ts(5 例):家族完整、NOW() 大小写/空白容忍、current_user 精确匹配、两类令牌的归属划分。

全量:driver-sql 634 passed / 38 skipped、objectql 1600 passed、spec 7273 passed、driver-sqlite-wasm 214 passed、service-datasource 197 passed、CLI schema-migrate.integration 2 passed;三个包 typecheck 全绿;packages/speccheck:api-surface(已 gen:api-surface 重生成并提交)/ check:generated / check:authorable-surface / check:dual-source-exports / check:exported-any / check:spec-changes 全过。

顺带发现(未在本 PR 修)

盘点令牌家族时实测到同一条裂缝的镜像:'NOW()' 只有 SQL 驱动的 formatInput 兜底认识,引擎不认识 —— 在 memory/mongodb 数据源上,Field.datetime({ defaultValue: 'NOW()' }) 会让引擎填入字面串 'NOW()',随后被引擎自己的写入校验以 ValidationError: must be a valid datetime (ISO-8601) 拒绝。已另立 #4597(未认领),其中的修法涉及「省略 datetime 字段时值由谁产生」的分工,属契约级选择,不在本 PR 自决。

🤖 Generated with Claude Code


Generated by Claude Code

The SQL DDL passed any non-object `defaultValue` through to
`col.defaultTo(dv)`, so `Field.user({ defaultValue: 'current_user' })`
was created as `DEFAULT 'current_user'` and the DATABASE stamped the
literal token into every insert the engine had deliberately left unset
(system/anonymous writes) — a non-id in a `lookup('sys_user')` column,
found by #4551's dangling-reference audit.

Declare the token family once in `@objectstack/spec/data`
(`DEFAULT_VALUE_TOKENS` + predicates) so the engine's insert-time
resolution and the driver's DDL read one set: `'NOW()'` keeps its
driver-native default, every other token emits none, literals and
Expression envelopes are unchanged. Column-default emission is now a
single `applyDeclaredColumnDefault` shared by createColumn and the
SQLite table rebuild.

Existing databases are corrected through the managed schema-drift path:
a `default_mismatch` finding with a `safe` `drop_column_default` op
(ALTER … DROP DEFAULT on pg/mysql, table rebuild on SQLite, which now
re-materializes sibling defaults from metadata). Rows already holding
the bogus value are NOT rewritten — #4551's report-never-rewrite rule.

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

vercel Bot commented Aug 2, 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 2, 2026 9:37am

Request Review

@github-actions github-actions Bot added the size/l label Aug 2, 2026
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

112 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 @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/driver-sql, @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/glossary.mdx (via @objectstack/driver-sql)
  • 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/objectql, @objectstack/driver-sql, @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/anatomy.mdx (via @objectstack/driver-sql)
  • 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/objectql, @objectstack/driver-sql, @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/driver-sql, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/driver-sql, @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 packages/objectql, @objectstack/driver-sql, @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/driver-sql, @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.

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests tooling labels Aug 2, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 2, 2026 09:38
@os-zhuang
os-zhuang enabled auto-merge August 2, 2026 09:38
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit a52e2ef Aug 2, 2026
22 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-4560-ddl-runtime-token-default branch August 2, 2026 09:59
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/l tests tooling

Projects

None yet

2 participants