Skip to content

[决策] readonly 剥离的 strict/reject 模式落在哪一层 —— B(WriteObservabilityOptions)推荐,A/C/D 各有代价(#4903 后续) #5126

Closed

Description

@claude

要拍板什么

readonly 剥离的 strict/reject 模式(供 cron/服务端插件在调用点选择「被剥离即响亮失败」而非静默丢列)落在哪一层。#4903(PR #5123)已把可发现性与文档修好,strict 半边因四个候选落点全部触碰 packages/spec/**(本车道冻结)而止步。

四个选项(完整两轴分析见 PR #5123 正文,此处摘要)

选项 落点 要害
A EngineUpdateOptionsSchema(可序列化 Zod 袋) 可跨 RPC/REST —— 但客户端可设置,在安全相邻路径上开新攻击面;拖动生成物
B(推荐) strictReadonlyWrites 挂 WriteObservabilityOptions(TS 契约,onFieldsDropped 所在) 进程内、客户端不可达、与既有先例同类;抛 ERR_READONLY_FIELD_REJECTED 带字段清单
C 部署级开关(env/构造配置) 全局改行为 —— REST 边界的伪造输入也从剥离变报错,兼容性变更;无法表达「只这一个 cron 要响」
D objectql 包内私加 ⛔ 实现而不声明 —— PD#12 反形,不建议

推荐 B:两轴同向 —— 唯一让 AI 写的 cron 在调用点拿到点名异常(而非绿调用 + 数周后发现 null 列)、又结构性不给客户端碰的方案。若你想覆盖 RPC/VDE 面,那是 A 的独立放宽,应单独定而非顺手带。

两个关联输入(#5123 报告的,同一次拍板可一并看)

  1. ExecutionContext 无 origin/channel 标记 —— isSystem 是唯一信任位,故剥离接缝无法区分伪造 REST body 与可信服务端代码;任何按来源分级的策略都以补这个标记为前提;
  2. onFieldsDropped 不跨 RPC/VDE 边界(契约已文档化)—— strict 决策应顺带说清远程调用方拿什么。

Blocked-by: objectstack-ai/objectstack#4903(PR #5123 合并后动手)
落点:packages/spec/src/contracts/data-engine.ts + objectql —— spec 车道或维护者授权例外。


Generated by Claude Code

Activity

  1. os-zhuang commented on Aug 4, 2026

    @os-zhuang
    Contributor

    维护者拍板:取 B

    strictReadonlyWrites 挂 WriteObservabilityOptions(TS 契约,onFieldsDropped 所在),被剥离时抛 ERR_READONLY_FIELD_REJECTED 并带字段清单。不取 A(可序列化 Zod 袋 —— 客户端可设置,在安全相邻路径上开新攻击面)、不取 C(部署级开关 —— 无法表达「只这一个 cron 要响」,且把 REST 边界的伪造输入一并变成报错)、不取 D(实现而不声明,PD#12 反形)。needs-user-decision 摘除。

    依据:B 是唯一让 AI 写的 cron 在调用点拿到点名异常(而不是绿调用 + 数周后发现 null 列)、同时结构性不给客户端碰的方案。若日后要覆盖 RPC/VDE 面,那是 A 的独立放宽,单独立单定,不顺手带进来。

    正文列的两个关联输入按此处理:ExecutionContext 的 origin/channel 标记是另一单的前提(任何按来源分级的策略都要它,但 B 不依赖它 —— B 靠的是「进程内可达 / 客户端不可达」这条结构边界);onFieldsDropped 不跨 RPC/VDE 的既有文档化事实,在 B 的实现里顺带在契约 TSDoc 上说清远程调用方拿到什么(即:拿不到,strict 是进程内语义)。

    路由:归 spec 车道(本车道硬禁区)

    落点 packages/spec/src/contracts/data-engine.ts + packages/objectql,跨 spec 与 engine。spec 半边(在 WriteObservabilityOptions 上声明 strictReadonlyWrites + ERROR_CODE_LEDGER 登记 ERR_READONLY_FIELD_REJECTED)是阻塞前置;声明落地后 objectql 的实施半边可由本车道接。Blocked-by: #4903(PR #5123)仍然有效,先确认它已合入再动工。

    急迫度:低 —— 今天的行为是静默剥离 + onFieldsDropped 可观测(#4903 已修好可发现性),strict 是补一条响亮出路,不是修一个正在漏的洞。spec 车道可排在 #5158 / #5271 / #5239 之后。


    Generated by Claude Code

  2. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    维护者裁定(2026-08-05,经 spec 车道 PM session_018fxLGQdatPbBUvCgiVxg6D 誊写):选 B。

    转入队列并即刻派发。


    Generated by Claude Code

  3. self-assigned this
    on Aug 5, 2026
  4. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    PM 认领(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-05)


    Generated by Claude Code

  5. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    验收通过(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-05)—— PR #5610,裁定 B 落地。

    落地暂缓等 #5604(main 全仓红)修复后合 main 重跑 → ready → auto-merge。


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions