Skip to content

D1 非媒体类型的按部署扫描门禁 + D2 动作参数 17.0 默认严格 —— 证据来源与载体已定于 ADR-0104 2026-07-30 附录(修订版) #3438

Closed

Description

@os-zhuang

背景

ADR-0104 的 D1(#3429)和 D2(#3432)都已合并。两者的新校验按 ADR 的 R1/R2/R3 纪律都以 warn-first 落地——违规仅告警放行,通过环境开关才转严格,目的是不让历史上静默错配的数据/调用在升级瞬间硬失败:

阶段 新校验 开关(opt-in 严格) 位置
D1 记录写入时,此前完全不校验的类型(单值 lookup/master_detail/user/tree、file 系、location/address/composite/repeater/record/vector)的值形状 OS_DATA_VALUE_SHAPE_STRICT_ENABLED=1 packages/objectql/src/validation/record-validator.ts
D2 动作派发时(REST + MCP)声明参数的 required / 值形状 / 未知键 OS_ACTION_PARAMS_STRICT_ENABLED=1 packages/runtime/src/http-dispatcher.ts

ADR-0104 明确写了这是过渡态:「The flip to strict-by-default rides a later minor once telemetry is quiet.」本 issue 跟踪这次翻转。

目标

在 warn-first 的告警在生产/dogfood 静默一段(确认没有正当调用被误伤)后,把两个开关翻成默认严格:

  • D1:record-validator.ts 的 VALUE_SHAPE_STRICT() 默认返回 true;违规从 console.warn 变为 400 VALIDATION_FAILED(invalid_type)。保留一个关闭逃生阀(如 OS_DATA_VALUE_SHAPE_STRICT_ENABLED=0 / OS_ALLOW_LAX_VALUE_SHAPE),便于个别环境临时回退。
  • D2:http-dispatcher.ts 的 actionParamsStrict() 默认返回 true;REST 违规 400、MCP 抛错。同样保留关闭逃生阀。
  • 环境变量按 Prime Directive [WIP] Create a new release version #9 收敛命名(翻转后主开关语义从 _ENABLED(opt-in)变成 opt-out,考虑用 OS_ALLOW_* / OS_SKIP_* 形式,并用 readEnvWithDeprecation 兼容一版旧名)。
  • 现有 warn-first 测试补上「默认即严格」的对偶用例(D1 的 record-validator.test.ts、D2 的 dogfood action-params-contract.dogfood.test.ts 目前显式 set 开关才测严格路径——翻转后默认路径即严格)。
  • changeset 标注为行为破坏:过去静默放行的畸形值/参数包升级后会 400。发版说明列清两类。
  • 翻转前先跑一遍存量体检:对代表性租户/showcase 采集 warn-first 告警,确认没有需要先修的正当用法(ADR-0104 R1)。

前置条件 / 触发时机

  • warn-first 已在生产观测「足够久且安静」(具体窗口由维护者定;建议至少覆盖一个发版周期)。
  • 两次翻转各走一个后续 minor(不必同一版),互不依赖,可分别评估节奏。

关联

🤖 Generated with Claude Code

Activity

  1. changed the title [-]tracking: 翻转 ADR-0104 值形状/参数强校验为默认严格(D1 + D2 warn-first → error)[/-] [+]翻转 D1/D2 值形态校验的 strict 默认值 —— ⚠️ 需按部署生效,不能按版本号全体翻转(见 #3617)[/+] on Jul 27, 2026
  2. os-zhuang commented on Jul 27, 2026

    @os-zhuang
    ContributorAuthor

    这条 issue 需要拆成三条 —— 只有一条现在能做

    #3617 落地后(#3638 已合并),我在实现本 issue 的过程中发现:这里打包的三件事,证据来源并不相同,不能一起翻。

    部署级标记 adr-0104-file-references 断言的事实是:本部署的文件字段值已迁移,且所有权账目已对过。

    它对 lookup 的 id、location 的载荷是否规范什么都没说;对 D2 的动作参数更是毫无关系。把后两者也挂在这个标记上,就是拿一个事实去给另一个不相干的事实背书——和 #3617 修掉的读解析器缺陷是同一个形状:让一个权威去回答没有问它的问题。

    # 范围 证据来源 状态
    1 D1 媒体类型(file/image/avatar/video/audio) adr-0104-file-references 标记 ✅ #3681 已实现,按部署翻转
    2 D1 引用 + 结构化 JSON(lookup/user/location/address/repeater/vector…) 尚无 ⏸ 待决定
    3 D2 动作参数 与任何数据迁移无关 ⏸ 待决定

    第 1 条能做,是因为证据对得上:会被拒绝的遗留形态(inline {url, name, …} blob、裸 URL)正是那个迁移负责转换的东西,所以跑过并通过的部署已被证明没有残留。

    第 2、3 条卡在哪

    不是卡在机制上——按部署生效的门禁已经建好并在跑。卡在一个尚未有人回答的问题:

    什么才算是「这个部署的 location / lookup 值是健全的」的证据?

    可能的路子(未决,列出来供讨论):

    • 各自的自检迁移。 比照 file-as-reference:写一个扫描器统计违规值,零违规才记标记。诚实但成本不低,而且这些类型没有"回填"可做——只能报告,让作者自己修。
    • 接受按版本翻转。 这些类型的违规不像 media 那样源于一次平台侧的存储形态收窄,更多是作者写错。可以论证"该拒就拒"。但那正是本 issue 标题警告的做法,需要明确认账。
    • 只在 build/validate 时拒绝,运行时永远只告警。 与 ADR-0104「enforcement-point 原则」一致:真正防住 AI 作者的是构建期硬拒,运行期的 warn-first 本来就只为保护存量数据。

    第 3 条(D2 动作参数)独立于上述所有讨论,可以单独评估。

    环境变量:不需要改名了

    本 issue 原来预期要把 OS_DATA_VALUE_SHAPE_STRICT_ENABLED 从 _ENABLED(opt-in)改名成 opt-out 形式,因为假设了全体翻转。按部署生效之后,这个变量的语义完全没变(仍是全类别 opt-in,也仍能在未迁移的部署上强制 media 严格),所以不需要改名,也不需要 readEnvWithDeprecation 兼容层。#3681 只新增了逃生阀 OS_ALLOW_LAX_MEDIA_VALUES。

    建议:本 issue 保留为第 2、3 条的跟踪项(标题可改为「D1 非媒体类型 + D2 动作参数的 strict 翻转:先确定证据来源」),第 1 条由 #3681 关闭。


    Generated by Claude Code

  3. os-zhuang commented on Jul 30, 2026

    @os-zhuang
    ContributorAuthor

    证据来源已定(#4188 合并),但本 issue 不能关

    ADR-0104 新增 2026-07-30 附录,回答了上一条评论里悬着的那个问题——「什么才算证据」。结论是两块的答案不同,因为两个事实的认识论触及范围不同:

    # 范围 证据 载体 状态
    1 D1 媒体类型 adr-0104-file-references 标记 按部署 ✅ #3681 已实现
    2 D1 引用 + 结构化 JSON 可以存在 → os migrate value-shapes 扫描 + adr-0104-value-shapes 标记 按部署,17.0 车次 ⬜ 未实现
    3 D2 动作参数 不可能存在 → 声明过的大版本 + 已服完的 warn 窗口 18.0 车次 ⬜ 未实现

    第 2 条能建门禁,是因为存量数据可枚举——全量扫描就是完备证据,与 file-as-reference 的对账同级。第 3 条建不了,是因为调用方不可枚举(每月才跑的集成、无人记得的 cron、每次现构造调用的 AI agent):任何「静默 N 天」标记都在断言它不可能拥有的完备性,那正是 #3617 清除掉的「无处安放的门禁」错误在下一层的复现。所以 D2 明确认账为按版本翻转——但在 warn 窗口之后的大版本(18.0),配 OS_ALLOW_LAX_ACTION_PARAMS 逃生阀。

    顺带修掉一个还没人提过的缺口:新建空库在创建时刻直接记两个标记。否则 ≥17 新生的部署永远从 lax 起步,warn 体制永不消亡。「此处不存在遗留值」在创建时刻是被观察到的事实,不是按版本推断,与 GC 门禁同一纪律。

    为什么保持打开

    附录只落地了决定,三件实现工作一件都没做:

    1. os migrate value-shapes 命令 + 引擎门禁接线 + 新库创建时记账(17.0 车次)
    2. 17.0 发版说明补 D2 的 18.0 预告段——没有这段,18.0 的翻转就是没预告过的破坏
    3. 18.0 车次:actionParamsStrict() 默认 true + OS_ALLOW_LAX_ACTION_PARAMS + dogfood 对偶用例翻转

    第 2 项是本次 v17 发版窗口里唯一有时限的:它必须和 17.0 一起出门,否则第 3 项在 18.0 就失去了立足的前提。

    标题已按上一条评论的建议改写(原标题的「不能按版本号全体翻转」现在只对第 2 条成立,对第 3 条恰好相反,留着会误导读者)。


    Generated by Claude Code

  4. changed the title [-]翻转 D1/D2 值形态校验的 strict 默认值 —— ⚠️ 需按部署生效,不能按版本号全体翻转(见 #3617)[/-] [+]D1 非媒体类型的按部署扫描门禁(17.0)+ D2 动作参数的默认严格(18.0)—— 证据来源已定于 ADR-0104 2026-07-30 附录[/+] on Jul 30, 2026
  5. changed the title [-]D1 非媒体类型的按部署扫描门禁(17.0)+ D2 动作参数的默认严格(18.0)—— 证据来源已定于 ADR-0104 2026-07-30 附录[/-] [+]D1 非媒体类型的按部署扫描门禁 + D2 动作参数 17.0 默认严格 —— 证据来源与载体已定于 ADR-0104 2026-07-30 附录(修订版)[/+] on Jul 30, 2026
  6. os-zhuang commented on Jul 30, 2026

    @os-zhuang
    ContributorAuthor

    附录修订已合并(#4199 → ea0cb39)——上一条评论中 D2 的载体作废

    维护者对 #4188 的评审意见成立(16→17 反正要升级,摊销到一次仪式),修订后的结论:

    # 范围 门禁 载体
    1 D1 媒体类型 adr-0104-file-references 标记 按部署(#3681 已实现)
    2 D1 引用 + 结构化 JSON os migrate value-shapes 扫描 + adr-0104-value-shapes 标记 按部署,命令随 17.0 发;os migrate meta 与 boot 日志接入升级路径
    3 D2 动作参数 18.0 → 17.0 默认严格(版本翻转,明确认账) 17.0;OS_ACTION_PARAMS_STRICT_ENABLED(仅存在于 RC,从未上 latest)在 GA 前直接删除,唯一开关变为逃生阀 OS_ALLOW_LAX_ACTION_PARAMS

    D1/D2 分道的判据在附录里:D2 坏的是调用方(响亮 400、落在能修的人手上、R3 危险半边已被 ACTION_PARAM_BUILTIN_KEYS 关闭),D1 坏的是记录(read-modify-write 回写多年前的畸形值,且部分脏数据源于我们自己曾导出的假 LocationCoordinatesSchema——照文档写的 app 不该被版本翻转惩罚)。

    更新后的工作项(全部在 17.0 GA 之前,changeset pre exit 是硬截止)

    1. D2 翻转实现:actionParamsStrict() 默认 true、删 OS_ACTION_PARAMS_STRICT_ENABLED、加 OS_ALLOW_LAX_ACTION_PARAMS、dogfood 对偶翻转、breaking changeset + v17 发版说明段。⚠️ 必须赶在 GA 前——一旦 opt-in 变量随 GA 上了 latest,「直接删除不背弃用债」的窗口就关了。
    2. os migrate value-shapes:CLI 命令 + 扫描器(复用 files-to-references 的行走机械与 sys_migration 记账)+ 引擎门禁接线 + OS_ALLOW_LAX_VALUE_SHAPES + 升级路径接线(os migrate meta 尾部提示、boot 日志行)。
    3. 新建空库创建时记账两个标记(可并入第 2 项)。

    Generated by Claude Code

  7. self-assigned this
    on Jul 31, 2026
  8. os-zhuang commented on Jul 31, 2026

    @os-zhuang
    ContributorAuthor

    收尾:三个工作项全部落地,关闭本 issue

    上一条评论(附录修订后)列出的三个工作项均已合并:

    # 工作项 落地 PR
    1 D2 翻转:actionParamsStrict() 默认 true、删 OS_ACTION_PARAMS_STRICT_ENABLED、加 OS_ALLOW_LAX_ACTION_PARAMS、dogfood 对偶翻转、breaking changeset + v17 发版说明段 #4213
    2 os migrate value-shapes:CLI 命令 + 扫描器 + 引擎门禁 + OS_ALLOW_LAX_VALUE_SHAPES #4235;升级路径接线(os migrate meta 尾部提示、boot 日志行)在 #4253;接线缺陷修正(已迁移/新建部署不再看到开门广告)在 #4284
    3 新建空库创建时记账两个标记(fresh-datastore attestation) #4215

    另有 #4299 把 ADR-0104 附录中广告位条款的表述修订为与实际落地一致。

    原正文的勾选框反映的是最初「按版本全体翻转」的方案,已被本线程两次附录(ea0cb39 修订版为准)取代,不再逐项勾选。最终格局:

    • D1 媒体类型:按部署门禁(adr-0104-file-references),feat(objectql)!: 媒体值形态 strict 按部署生效 —— #3438 中标记真正覆盖的那一半 #3681 已实现。
    • D1 引用 + 结构化 JSON:按部署门禁(os migrate value-shapes 扫描 + adr-0104-value-shapes 标记),随 17.0 发布;升级路径会点名未关闭的门禁。
    • D2 动作参数:17.0 默认严格(版本翻转,明确认账),逃生阀 OS_ALLOW_LAX_ACTION_PARAMS。
    • 新建空库在创建时刻直接记两个标记,warn 体制不会在新生部署上延续。

    全部工作赶在 17.0 GA(changeset pre exit)之前,opt-in 变量从未上 latest。关闭为 completed。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions