Uh oh!
There was an error while loading. Please reload this page.
docs(spec): ISharingService.canEdit 补上 modifyAllRecords 旁路分支 (#5125) - #5818
Merged
Conversation
…pass (#5125) `canEdit`'s contract doc listed ownership and an `edit`-level share and stopped there, while the implementation has carried a third branch since #4647: the `modifyAllRecords` super-user write bypass, probed through `ISecurityService.hasWriteBypass` after ownership and shares both fail (`packages/plugins/plugin-sharing/src/sharing-service.ts:398-400`, via `hasModifyAllBypass` at :341-351). The omission was worse than silence because `canDelete` sits four lines below naming the same bypass ("ownership (widened by write DEPTH) or the `modifyAllRecords` super-user bypass ONLY"), so the pair read as a deliberate exclusion on the update gate -- the exact opposite of the code. The wording now matches `canDelete`'s, and names the same permission the implementation actually checks (`bit: 'modify'` -> `op.modifyAllRecords`, `permission-evaluator.ts:superuserBypassSets`). Adds a parity pin over the interface's own JSDoc: the three write gates (`canEdit` / `canDelete` / `canManageShares`) must each name the bypass, `buildReadFilter` must not (the read path has no `hasWriteBypass` branch), and the member enumeration is asserted whole so a rename cannot empty it. Nothing type-checks a doc comment, and prose is what drifted here. Comment + test only: no schema, type, export or behaviour change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01559M8FVm6W6vDLABL3jvdW
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 110 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
baozhoutao
marked this pull request as ready for review
August 6, 2026 06:40
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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#5125
前提复核(先证伪,再动手)
对
origin/main@5ab0842逐条核过 issue 的两个前提,都成立:(a) 实现确实有第三条
modifyAllRecords写旁路。packages/plugins/plugin-sharing/src/sharing-service.ts:canEdit在 366-401 行,分三步:1) ownership(write DEPTH 放宽,matchesOwnerScope)→ 2)WRITE_ACCESS_LEVELS的 share 行 → 3) 398-400 行return this.hasModifyAllBypass(object, context);hasModifyAllBypass在 341-351 行,走 late-bound 的probe.hasWriteBypass(object, context),并且 fail CLOSED(无 security service / probe 抛错 →false)。(b) 契约文档确实还没这一条。 改前
packages/spec/src/contracts/sharing-service.ts里modifyAllRecords只出现 2 次(canDelete、canManageShares),canEdit的 doc comment 只写到 ownership + share 为止。权限名逐层确认过,没有分叉(任务书要求不能盲抄
canDelete的措辞):ISecurityService.hasWriteBypass的契约就写明是modifyAllRecords(packages/spec/src/contracts/security-service.ts:220-237);实现packages/plugins/plugin-security/src/security-plugin.ts:676-692调permissionEvaluator.hasSuperuserWriteBypass;再往下permission-evaluator.ts:296-311的superuserBypassSets在bit === 'modify'分支上读的正是op.modifyAllRecords。所以 EDIT 路径和canDelete是同一个 bit、同一个谓词,措辞可以直接对齐。改动
一句话级的 doc comment 修正,措辞与
canDelete对齐(the modifyAllRecords super-user bypass),另补两句说明这条旁路与canDelete/canManageShares是同一个ISecurityService.hasWriteBypass谓词、放在最后问、fail closed —— 这三点都是实现里已有的事实,不是新约定。外加一条文档对偶 pin(
packages/spec/src/contracts/sharing-service.test.ts):三道写门(canEdit/canDelete/canManageShares)的 JSDoc 必须各自点名modifyAllRecords。没有任何东西会对 doc comment 做类型检查,而这次漂移的恰恰是 prose,所以用 TS AST 读接口成员的 leading trivia 来钉。两道反空转保护:成员枚举整体断言(改名不能把断言掏空),外加buildReadFilter必须不含该词作为判别性负例 —— 读路径确实没有hasWriteBypass分支(View/Modify All Data 持有者读到全部行,是因为 security 层把 read DEPTH 解析成org而在 sharing 之前短路,buildReadFilter202 行if (readScope === 'org') return null;),所以在那里写上写旁路本身就会是新的漂移。生成物投影:没有
contracts/这一目录不产任何生成物,证据三条:packages/spec/scripts/build-docs.ts:106只收*.zod.ts(if (!entry.name.endsWith('.zod.ts')) continue;),而packages/spec/src/contracts/下一个.zod.ts都没有;content/docs/references/contracts/里只有meta.json,内容是"pages": [];check:docs跑起来自己也这么说 ——Skipping clean of contracts/ — no JSON schemas found in .../json-schema/contracts;api-surface.json的./contracts条目只记导出名与种类("ISharingService (interface)"),不含任何文档正文;本 PR 也没有增删任何导出,所以check:api-surface结构上不可能动。跑过的门:⚠️ 两者都会顺手重写
check:docs✅(240 generated files in sync with packages/spec)、check:authorable-surface✅。packages/spec/authorable-surface.base.json(已知 #5358),已git checkout --还原,PR 里没有这个文件 —— 本 PR 只含上述两个文件。Changeset:选
skip-changesetpackages/spec发布的files是dist+src/**/*.zod.ts,本文件是普通.ts,源码不随包走;上面已证没有生成物投影;导出面、类型、schema、运行时行为全部零变化。按pr-automation.ymlchangeset 门自己的处方,这属于"releases nothing → 打skip-changeset标签(PREFERRED)"。同形先例:.changeset/auth-database-hooks-middleware-claim-corrected.md(同样是已发布包里的 comment-only 更正,结论 "Comments only — no runtime behaviour changes, nothing released")。诚实起见记一句:更正后的文字仍会经dist/*.d.ts到达 consumer 的 IDE 悬浮提示 —— 但那不改变本 PR 不发布任何东西这一事实,所以走标签而不是 changeset。标签已由我在建 PR 后立即打上。验证
反向验证(方向是事先预判的:红)。 把
canEdit的 doc comment 还原成改前那段,新 pin 应该转红、两条既有断言应该保持绿 —— 实测正是如此:还原修正后重跑回到 3 passed。
越界发现(已另开 issue,未在本 PR 修)
canEdit()answers the access question forupdate/deleteoperations",而 ADR-0111 D3 早已把 delete 拆成故意更窄的canDelete(),与它下面 20 行的方法文档直接矛盾。同一类漂移,但任务书把本 PR 的改动面明确限定为canEdit的 doc comment,故只记录不顺手改。Generated by Claude Code