docs(core): fieldRules 模块头收窄 readonly fail-open 的「与服务端一致」断言 (#3828) - #3887
Merged
Conversation
模块头把客户端 readonly fail-open 写成「matching the server, which logs and allows the change through」。这句在写下时为真,但自 objectstack#4889 起对**未 绑定根**这一类已不成立:`readonlyWhen` 因为引用了本次写入没有绑定的 scope 根 (`parent.status == 'paid'` 而手里没有 master-detail 头)而 fault 时,服务端是 fail-CLOSED —— `isReadonlyWhenLocked` 记日志后 `return true`(LOCKED), `stripReadonlyWhenFields` / `...Multi` 随即把该 key 从 UPDATE payload 中删除。 客户端这一侧本身没错(fallback: false,字段仍可编辑),错的是「一致」这半句: 两端在这一类上方向相反,而注释把它描述成同向。 收窄后的正文点明三件事:两端在多数 fault 一致、未绑定根一类相反;相反是按 framework 的 ADR-0057 D10(server enforces, client is courtesy)刻意为之,客 户端不猜「锁死」;以及调用方后果 —— 表单可编辑、保存报成功、值静默不落库,排 障要往服务端锁死的方向查(服务端 `treating the field as LOCKED` 警告 +写响应 的 `droppedFields`),而不是查客户端谓词。 `requiredWhen` 半句复核后仍准确(objectstack#4977 绑了 `parent` scope 但刻意 保留 fail-open 语义,两端都跳过),字段级 `visibleWhen` 服务端根本不评估,两处 均不动。下文引用的 "log and allow" 服务端消息标注为 GENERIC-fault 消息,以免 两段之后把刚收窄的结论又抹平。 零行为改动:纯 docblock,代码一行未动;`packages/core/src/evaluator` 测试前后 均 289 passed / 9 files;changeset 空 frontmatter 声明不发布(照 #3749 先例)。 Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Collaborator
Author
|
✅ 验收(PM,session 实物核验:头 裁定要点:
转 ready 并挂 auto-merge。越界 #3888(同一陈旧断言在本仓 ADR-0036 的第二份副本 —— 更权威位置)归分诊席。 Generated by Claude Code |
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.
Fixes #3828
改了什么
只有一处:
packages/core/src/evaluator/fieldRules.ts的模块头注释。零行为改动 —— 代码一行未动,packages/core/src/evaluator的测试前后都是 289 passed / 9 files(用例数逐个一致)。改前(
fieldRules.ts:23-27@47f607854):按分诊裁定的方向 1 收窄:多数 fault 两端一致 fail-open;未绑定根那一类服务端自 objectstack#4889 起是 fail-CLOSED,两端方向相反;相反是刻意的,按 ADR-0057 D10 以服务端为准;并写明调用方后果。
为什么这句话必须改
客户端这一侧本身没错 ——
resolveFieldRuleState给readonlyWhen传fallback: false(fieldRules.ts:196),字段仍可编辑,这是 ADR-0057 D10「server enforces, client is courtesy」下的合理选择。错的只是「一致」这半句。服务端侧证据(objectstack
origin/main@fec784863,packages/objectql/src/validation/rule-validator.ts):readonlyWhen未绑定根 → 记日志treating the field as LOCKED:599-603return true(= LOCKED):604failed to evaluate — change allowed through+return false:606-607isReadonlyWhenLocked定义:580stripReadonlyWhenFields定义 /delete掉该 key:522/:537stripReadonlyWhenFieldsMulti):741/:772,说明见:723-728:99-109:567-569requiredWhen两端仍都 fail-open(objectstack#4977 只绑 scope、不改语义):117-141、:1416-1430于是真实链路和注释描述的正好相反:注释让人建立「客户端可编辑 + 服务端放行 = 值会落库」的模型,而实际是「客户端可编辑 + 服务端锁死丢弃 = 表单能改、保存报成功、值静默不落库」。新正文因此额外写了一段排障方向:往服务端锁死那边查(服务端的
treating the field as LOCKED警告,加写响应的droppedFields—— 后者证据 objectstackpackages/client/src/index.ts:335,349),而不是查客户端谓词。两处需要评审留意的判断
docs/adr/0057-erp-authorization-core-business-units-and-scope-depth.md:422,PS-2 实现注记:516-526把 client-side gate 与 server-side teeth 讲得最清楚);而本仓的docs/adr/0057-console-ai-chat-one-conversation-docked.md是完全无关的文档。本仓读者按裸编号翻会翻到错的那份,所以新注释写成 "the framework's ADR-0057 D10 …(framework numbering; this repo's own ADR-0057 is an unrelated document)"。log and allowconvention",引用的是服务端通用 fault 的消息(rule-validator.ts:606)—— 这句本身准确,但不加限定就会把上一段刚收窄的结论在两段之后抹平,使 docblock 自相矛盾。因此只加了「for the faults where the two ends DO agree」+ 标注它是 GENERIC-fault 消息。仍在 issue 划定的文件面(同一个模块头)内,但确实超出「只改那一句」的字面范围,故在此显式说明。requiredWhen半句与可见性半句按分诊结论未动(前者 objectstack#4977 两端都 fail-open,后者服务端根本不评估字段级visibleWhen)。验证
289 passed (9 files),改后289 passed (9 files)。新注释里引用的每个符号与单号都给了上表的 file:line。pnpm exec vitest run packages/core/src/evaluator --maxWorkers=2:前后各一次,均Test Files 9 passed (9) / Tests 289 passed (289)。pnpm exec turbo run type-check --concurrency=2(全仓):78 successful, 78 total。node scripts/check-control-bytes.mjs:OK (scanned 3778 tracked text file(s));改动两文件grep -naP控制字节零命中。packages/core/src/**在check-changeset-presence.mjs的守护面内,注释-only 故按 docs(app-shell): 两个 AppContent 路由测试的头注释仍把 sys-datasources / sys-objects 枚举为「在发 legacy 别名」的生产端 —— #3660 / #3739 之后已陈旧 #3749 / PR docs(app-shell): 两个 AppContent 路由测试的生产端叙述改写为「历史 + 现状」两段 (#3749) #3860 先例走空 frontmatter 声明不发布;三个 changeset 门禁(presence / no-major / fixed)均绿。Generated by Claude Code