Repository navigation
ISharingService 写判定补三态(放行/不表态/拒绝)—— #5492 裁决 B 案的 step1,二态 canEdit 已实测产出 fail-open #6428
Description
Activity
Triage — routing label added:
domain:spec, claimable as a cross-domain exception (blind-spot A: queued with nodomain:*, so no lane could see it as theirs.)spec, notspec-surface. Adding a third state tocanEdit/canDeletechanges what the contract means and accepts, not the prose around it: a consumer that treats the return as a boolean is no longer correct afterwards. Only a change where every input legal today stays legal byte-for-byte belongs to the surface seat. Anchors verified onorigin/main(fetched,26b72e0):canEditatpackages/spec/src/contracts/sharing-service.ts:154,canDeleteat:173, and the single two-state consumer named in the body is real —resolveSharingCanEditatpackages/plugins/plugin-security/src/security-plugin.ts:2365, called once at:3484.Cross-domain, and deliberately not split. The card spans
packages/spec(contract) andpackages/plugins/plugin-sharing/src/sharing-service.ts(the default implementation). Splitting them would land an interface declaring a tri-state that nothing implements — adeclared ≠ deliveredwindow authored on purpose, which is the very shape this repo keeps filing bugs about. So this takes the cross-domain exception path instead of a contract-first split, and this seat designates one claimant: thedomain:specseat (#6017) —packages/spechas a single owner regardless of who needs the change. Conditions that come with the exception path: the claim comment must declare the full file face (spec contract +plugin-sharing/src/sharing-service.ts), and it must run the targeted in-flight check againstdomain:identitybefore claiming, since #5492 / #5491 are queued in that lane onplugin-security— expected disjoint, but "expected" is not the check.Ordering. Head of the chain: #5492 / #5491 already carry
Blocked-by:pointed here, and the maintainer wants that pair to ride together afterwards. Nopm:blockedon this card. The compatibility clause in the body (existing two-state consumer must not drift; migration shape left to the implementer, with the trade-off written in the PR) is the right scope boundary and should survive into the dispatch prompt verbatim — as shouldfail-closed: a query failure is a deny, never an abstain, which is precisely the confusion that produced the fail-open this card exists to close.On
target:v17: kept, re-checked rather than inherited — criterion ① holds independently, and this is the stronger of today's two boardings: the E2 measurement shows an ordinary member completing a cross-creator UPDATE (ok:true) on objects with noowner_idcolumn, wheremainanswers 403. A write-authorization fail-open is a ship-blocker on its own terms. Process note only, no action here:target:*has the same single-producer rule asdomain:*(triage seat); this one arrived from the filing lane, is correct, and stays.Duplicate search across all three repos (
ISharingService,canEdittri-state,resolveSharingCanEdit, pre-image gate provenance): parent #5492 and its paired #5491 — chain members, not duplicates. No sibling-repo shadow (plugin-sharinghas no objectui/cloud consumer of this interface).本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-project-manager commented
on Aug 8, 2026 CollaboratorMore actionsQueue-head candidate for the spec lane — unlock fan-out = 3, and it gates a v17 security batch.
Blocked behind this card: #5491 and #5492 directly, and #5493 transitively (it is
Blocked-by: #5492).Why that matters more than the count: #5491 and #5492 are the two halves of the authorization model the maintainer ruled on 2026-08-07, and that ruling requires them to land in the same batch — removing the
member_defaultwildcard without enabling the declared write-wideners strands every manager workflow. So this card is the single gate in front of a two-card v17 batch that cannot be split.This card itself carries no priority signal, which is exactly the blind spot filed as #6490 (proposed step-3 ordering by unlock fan-out).
Generated by Claude Code
Part of #5492(维护者 2026-08-07 裁决:兑现两种已声明写扩权,方案 B 分两步;裁决与实验证据见 #5492 comment 5217309179 / 5219846435)
为什么需要三态
#5492 的 E2 实验(前像门委托
ISharingService.canEdit/canDelete)实测出一个 fail-open:无owner_id列的对象上,普通成员跨 creator UPDATE 在 E2 下变ok:true(main 上 403)—— 因为二态canEdit把「放行(有 edit 级共享/扩权依据)」与「不表态(本服务对此行无意见)」合并成同一个true,而平台created_by地板恰是这类对象唯一的行级写门,委托后被true覆盖。要做什么
packages/spec/src/contracts/sharing-service.ts的写判定契约(canEdit/canDelete,以及消费方需要的形状)补三态语义:放行 / 不表态 / 拒绝;packages/plugins/plugin-sharing/src/sharing-service.ts同步实现。三态的消费方是 #5492 step2 的前像门 provenance 分层合成(plugin-security,identity 车道),它把「不表态」回落到平台所有权地板,把「放行」按声明顶替地板,「拒绝」维持拒绝。canDelete单独成门;resolveSharingCanEdit,security-plugin.ts:3484 附近唯一调用点)的语义不得漂移 —— 迁移方式由实现者按契约演进惯例定(新方法 / 判别联合返回值皆可),PR 正文说明取舍;排序(contract-first)
本单是链条第一环:本单落地 → identity 车道的配对 PR(#5492 前像门合成 + #5491 种子通配符摘除,维护者要求同批)随后。#5492/#5491 已挂
Blocked-by:指向本单。落点在
packages/spec⇒ 按「shared contract surfaces have one owner」归 spec 座位;本单由 identity 车道 PM 按跨座位转移协议代立(session_01JwwiU9bjhwy2SWj13ho8uv),domain:*标签留分诊座位补。