fix(metadata-protocol): batchData upsert fork asks existence, not caller visibility (#5099) - #5187
Merged
Conversation
…ler visibility (#5099) The update-or-insert fork read findOne under the caller's context — the read RLS/sharing narrows — so an existing row outside the caller's scope took the insert arm: duplicate-key on a constrained store (an authorization/update scenario reported as a key collision), a second row on an unconstrained one. The fork now uses the same system-context existence probe as every other by-id face (#4620), and write authorization stays #1994's decision inside engine.update. The non-atomic blind-insert fallback is removed with it: with existence decided before the fork it could only mask a real update failure behind a duplicate-key error — the same masking ADR-0119 D4 forbade on the atomic arm. Proven red-first: 5 of 7 new cases fail on the old fork (insert called twice for an out-of-scope existing id; update failures masked). After: metadata-protocol 39 files / 346 tests, rest 608 tests, typecheck across 81 dependent tasks all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BotUP49pqhvqGY393n2HfU
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
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 #5099
维护者已拍板方案 1(存在性探针),裁定与实现约束记录在 #5099 的裁定评论。
问题
runBatchDataLoop的 upsert 分岔用调用者上下文的findOne判「这条记录在不在」——那是 RLS/sharing 会收窄的读(#3455)。于是一个确实存在、但在调用者读作用域之外的 id 走了 insert 分支:insert被调 2 次);同文件
probeRecord的注释(#4435)把「存在性 ≠ 可见性」写成承重点,#5088 刚把它落到 update / delete 写面——upsert 是全文件唯一反着读的分岔(#4620:一份口径,不是三份碰巧一致)。修法
probeRecord(系统上下文,只问存在性)。授权不前移:作用域外既有行走 update 分支后,由engine.update内 fix(security)[P0]: enforce RLS on by-id writes — close member-edits-others'-records hole (#1985) #1994 的前像检查裁决——行的失败答案是写策略自己的答案(掩蔽式部署下即与直接 by-id update 相同的 404),不是 duplicate-key。rls-by-id-write证明的可红性不受影响(探针不做授权判断)。runBatchDataLoop的 doc comment 同步改写(atomic 现在只改变一件事)。刻意不动:missing id 仍插入(#5088 的既有 pin
upsert is deliberately UNTOUCHED: a missing id still inserts原样通过);写仍带调用者上下文(只有探针是系统读,#3455 回归有 pin);atomic 响应形状不变。与 #5038 的边界
#5038(批量写按行语义,在飞)的文件面是
packages/objectql+service-automation,改的是 predicate(multi: true)写的 hook/flow 触发粒度;本 PR 只动packages/metadata-protocol/src/protocol.ts的 by-id upsert 分岔,两条路径的边界即 #4800 分诊所划。无共享文件。先证红再信绿
新增
protocol.upsert-existence.test.ts(7 例:作用域外既有 id、探针系统上下文、真实 update 失败不被掩蔽、missing id 仍插入、可见 id 正常更新、atomic causal 行、混合批次)。fake engine 带调用者作用域读 + #1994 式 by-id 写策略(作用域外掩蔽为 404)+ 主键唯一约束。只保留测试、不改
protocol.ts时:修复后:
@objectstack/metadata-protocol39 文件 / 346 用例全绿(含 batch-atomic 对 atomic 臂"真实错误存活、无 fallback"的既有 pin),@objectstack/rest608 用例全绿,turbo typecheck --filter=...@objectstack/metadata-protocol81 任务全过。备注
defaultMode: 'upsert')走独立的SeedLoaderService(externalId 键控),不经过本分岔,不受影响。engine.update既有的 fix(security)[P0]: enforce RLS on by-id writes — close member-edits-others'-records hole (#1985) #1994 面覆盖,本 PR 未触碰。🤖 Generated with Claude Code
https://claude.ai/code/session_01BotUP49pqhvqGY393n2HfU
Generated by Claude Code