feat(objectql)!: 媒体值形态 strict 按部署生效 —— #3438 中标记真正覆盖的那一半 - #3681
Merged
Conversation
…file migration verified (#3438) #3438 scheduled the strict flip for "a later minor once telemetry is quiet" — our telemetry, deciding for their deployments. #3617 built the mechanism that replaces that: a deployment's own migration flag. This lands the half that flag actually covers. A malformed media value now rejects with `invalid_type` instead of warning, but only where `os migrate files-to-references --apply` has run and passed its self-check. The legacy forms this rejects — inline `{url, name, …}` blobs, bare URLs — are exactly what that migration converts, so a verified deployment has been shown to hold none, while an unmigrated one is untouched rather than having every media update start failing on upgrade. ## Only media, deliberately #3438 packaged three things as one flip, and the flag covers one of them. It asserts "this deployment's FILE values are migrated and reconciled". It says nothing about whether a `lookup` id or a `location` payload is well formed, and nothing at all about D2's action parameters. Gating those on it would be borrowing evidence for a fact it does not cover — an authority answering a question it was not asked, which is the same shape as the read-resolver defect #3617 fixed one layer down. Reference and structured-JSON classes keep their own warn-first rollout until something can vouch for them. `OS_DATA_VALUE_SHAPE_STRICT_ENABLED` is unchanged (still opts every class in, still forces media strict on an unmigrated deployment). New escape hatch `OS_ALLOW_LAX_MEDIA_VALUES=1` re-opens media on a verified deployment; when both are set the lenient one wins, because a warning nobody reads costs less than an app that stops writing. ## Cost The fact lives in the database while the validator is synchronous and per-write, so the engine reads it once and memoizes — and stays dormant unless the written object declares a media field, mirroring the rule the storage module already states. One query per process for apps that store files, zero for those that do not. Every way of not knowing (no storage service, no row, unreadable table, malformed row) answers "not verified": a deployment whose evidence cannot be read keeps writing rather than starting to reject. Verified end-to-end on showcase + SQLite against one database: the same write was accepted before the migration, rejected with `invalid_type` after it, and accepted again under OS_ALLOW_LAX_MEDIA_VALUES. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9uWWyKq6pNPQthwCXL8ma
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 28 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
6 tasks
…tion-gating-764pf2
os-zhuang
marked this pull request as ready for review
July 27, 2026 14:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
承接 #3617 落下的机制,做 #3438 里标记真正覆盖的那一半。前置 PR #3638 已合并。
变更
媒体字段(
file/image/avatar/video/audio)的值形态校验,在本部署跑过os migrate files-to-references --apply且自检通过之后,从告警变为invalid_type拒绝。没迁移的部署完全不受影响。理由是证据对得上:这里会被拒的遗留形态——inline
{url, name, …}blob、裸 URL——正是那个迁移负责转换的东西。跑过并通过的部署已经被证明没有残留;没跑过的部署如果跟着版本号一起翻,升级瞬间每个 media 字段的 update 都会开始失败。为什么只做媒体这一半
#3438 把三件事打包成一次翻转,而标记只覆盖其中一件。它断言的是「本部署的文件字段值已迁移并对过账」——对
lookup的 id、location的载荷是否规范什么都没说,对 D2 的动作参数更是毫无关系。把它们挂上去就是拿一个事实去给另一个不相干的事实背书,和 #3617 修掉的读解析器缺陷是同一个形状:让一个权威去回答没有问它的问题。adr-0104-file-references标记后两行不是被机制卡住——机制已经在跑了;它们卡在「什么才算是这个部署的
location值健全的证据」这个尚未有人回答的问题上。已在 #3438 留言说明。环境变量
OS_DATA_VALUE_SHAPE_STRICT_ENABLED语义未变(仍是全类别 opt-in,也仍能在未迁移的部署上强制 media 严格),所以不需要改名或兼容层——#3438 当初预期要改名,是因为假设了全体翻转。新增逃生阀
OS_ALLOW_LAX_MEDIA_VALUES=1(按 Prime Directive #9 的OS_ALLOW_*形式),在已验证的部署上重新放宽。两个都设时宽松的一方胜出:没人看的告警,代价小于停止写入的应用。代价
事实存在数据库里,而校验器是同步且逐次写入的,所以 engine 读一次并 memoize——并且除非写入对象真的声明了 media 字段,否则连这一次都不读(沿用
file-reference-lifecycle.ts已写明的休眠原则)。存文件的应用每进程一次查询,不存文件的应用零次。实现过程中这一点是被测试逼出来的:我最初无条件读标记,4 个既有测试因为多出一次查询而失败——那不是测试太严,是我真的给每个 update 都加了一次无谓查询。
所有「不知道」的情形(没有存储服务、没有行、表读不了、行格式坏)一律答「未验证」:读不到证据的部署继续写入,而不是开始拒绝。
验证
invalid_type拒绝 → 加OS_ALLOW_LAX_MEDIA_VALUES再次放行。pnpm test132/132 绿;spec 十道产物门、ESLint、example/downstream typecheck 本地全过。文档
cli.mdx:新增「标记开启了什么」小节,并写明运行中的 server 需重启才生效。🤖 Generated with Claude Code
https://claude.ai/code/session_01V9uWWyKq6pNPQthwCXL8ma
Generated by Claude Code