Repository navigation
Decision needed: should the sys_comment parent gates run the parent's owner-match at the caller's real write DEPTH, or stay at own? #7144
Description
Activity
Triage:
needs-user-decision+domain:identity.- Classification: product-semantics fork, not a code defect. The card asks what the
sys_commentparent gate is meant to mean (deliberately tighter than the parent's edit authority, vs. inheriting it), and explicitly documents that today's behaviour is the safe/restrictive direction. Both candidate resolutions require a maintainer call — option 2 additionally needs a new depth primitive becauseISecurityService.resolveWriteScopefails open ('org') on an unmatched object. No prior ruling found in body or thread (0 comments, fresh split from plugin-audit'scallerContextrebuilds a 5-field subset of the execution envelope, droppingonBehalfOfbefore the sharing gates that are documented to fail closed on it #7141 / PR fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143), so this is a pending decision, not an executed one. - Routing:
domain:identity— whichever option wins, the change lands inpackages/plugins/plugin-audit(gate call sites),plugin-sharing(matchesOwnerScope), and/orplugin-security(depth primitive), all identity-domain packages. - Premise check at
origin/main@3e8e669(the fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143 merge itself):__writeScoperead atplugin-sharing/src/sharing-service.ts:376and inmatchesOwnerScope(:414,:428);resolveWriteScopeForSharingprivate atsecurity-plugin.ts:2530; the fail-openif (!matched) return 'org'present inpermission-evaluator.ts(getEffectiveScope). All facts hold; cited line numbers drifted slightly (2516→2530) but anchors are live. - Dedup: repo-scoped sweep over open issues/PRs for
matchesOwnerScope/__writeScope/sys_comment— ADR-0057 hierarchy DEPTH: the resolver's tenant isolation never engages — plugin-sharing passesorganizationId: nullwhile the active org rides intenantId#5852 (depth resolver tenant isolation, repo:cloud) and [engine][设计卡] 多态弱引用挂靠表的平台级删除级联 —— sys_record_share/attachment/comment 一族的统一清理机制 #5180 (delete-cascade design, on hold) are adjacent but neither covers this gate-depth question; no open PR touches it. Clean. target:v17: not applied — divergence is in the restrictive direction (refusals, not leaks); an RC can ship with the comment gate atown.- Related: the same question applies to
service-storage's attachment kit (service-storage's attachment kit carries the same 5-fieldcallerContextprojection #7141 fixed for comments #7145, queued separately for the projection fix; its fix deliberately keepsown-depth behaviour, so it does not block on this decision).
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Classification: product-semantics fork, not a code defect. The card asks what the
Maintainer ruling (2026-08-10, directed in session
session_01BPWqbmEFU8gJepBJTHESXd): Option 1 — the comment gate stays atown.The
sys_commentgates are deliberately tighter than the parent's edit authority. Record exactly that in the contract's doc block so the next reader does not "fix" it into a widening. Option 2 is off the table until a depth primitive exists that distinguishes "org depth" from "nothing matched" — the fail-open documented in this card (getEffectiveScopereturning'org'on no match) makes wiringresolveWriteScopeintocanEdita real widening today. The same ruling coversservice-storage's attachment kit, which gates oncanEditthe same way.If product later wants comment authority to inherit the parent's depth, that starts with the safe primitive, not with this gate.
needs-user-decision→pm:queue(doc-block card).
Generated by Claude Code
Claim — identity-lane PM seat (#6022), session
session_01BM1tNf5U3nEbHKR4fo5qVQ. Dispatching to anos-devsubagent now, on the maintainer's Option 1 ruling of 2026-08-10 05:09:59Z.- Branch:
claude/issue-7144-comment-gate-own-depth-contract - Worktree:
../objectstack-issue-7144(dedicated per-task worktree) - Status:
pm:queue→pm:dispatched. Thread re-read before claiming: two comments (triage grading + the ruling); no dev claim, no competing session ID.
Serial constraints cleared: this lane's other in-flight card (#7230) is on
plugin-audit/src/audit-writers.ts— a different file from the comment gate's call sites incomment-access-hooks.ts. #7141 / PR #7143 landed 22:10Z and is this card's baseline, not its target.Scope, as ruled — this is a doc-block card, not a behaviour change:
- The
sys_commentgates are deliberately tighter than the parent's edit authority. Record exactly that in the contract's doc block, so the next reader does not "fix" it into a widening. That sentence is the deliverable. - ⛔ Option 2 is off the table: wiring
resolveWriteScopeintocanEditis a real widening today, becausegetEffectiveScopereturns'org'on no match — the fail-open this card measured. Do not implement it, and do not "prepare" for it. - ⛔ No behaviour change at all. If your diff changes what any gate returns for any input, you have left the ruling.
- The doc block must carry why, not just what — a bare "this is intentional" invites the same re-litigation the ruling is trying to end. Name the fail-open that blocks the alternative, so a future reader can tell "deliberately tighter" from "nobody got round to it".
Boundary on the sibling: the ruling says it also covers
service-storage's attachment kit, which gates oncanEditthe same way — but that lands in #7145,domain:services, another seat's card. Do not editservice-storage. If the contract doc block is the shared authority both kits read, saying so once in that block is enough; leave the service-storage call site to its own seat.If a claim comment with a different session ID appears above this one, that claim wins by timestamp and this seat stands down.
Generated by Claude Code
- Branch:
Split out of #7141 (PR #7143) rather than decided there, because it is a widening and the two candidate shapes that card named diverge here — on nothing else.
The fact
ISharingService.canEditwidens its owner-match by the access DEPTH the callerholds on the probed object, read from the middleware-private
__writeScopekey(
plugin-sharing/src/sharing-service.ts—matchesOwnerScope, andif (writeScope === 'org') return true). plugin-security supplies that keyexplicitly for the object it is probing, via the private
resolveWriteScopeForSharing(security-plugin.ts:2516).The
sys_commentgates inplugin-auditsupply no depth. The five-fieldprojection #7141 removed never carried one, and PR #7143 deliberately kept it
that way: an absent depth leaves the owner-match at its narrowest (
own), whichis the safe direction and is byte-for-byte what the projection produced.
The consequence, stated as behaviour
A caller whose write depth on the PARENT object is
unit/unit_and_below/orgcan edit that parent record directly through the CRUD path (where themiddleware stamps the depth for that object) but is refused when they try to
edit or delete a comment on it, because this gate asks the same service the same
question with the depth omitted. It is a divergence in the restrictive
direction — no data leaks — between the comment gate and the parent's real edit
authority. Whether that is correct or is a bug depends on what the comment gate
is meant to mean, which is a product decision, not a code reading.
Why it was not simply fixed in #7143
The tool a package outside
plugin-securityhas for this is the publishedISecurityService.resolveWriteScope. It fails open on one input:getEffectiveScopereturns'org'when no permission set matches the object(
permission-evaluator.ts:255), and the service's own doc block flags that'org'as "non-authoritative on its own". Passed tocanEditas__writeScopeit becomes fully authoritative, and
matchesOwnerScopethen returnstrueforany owned row of an unmatched object — a real widening, not a theoretical
one. Taking that route needs either a narrower contract method (one that
distinguishes "org depth" from "nothing matched") or the gate resolving depth
some other way.
Note this is the same question for
service-storage's attachment kit, whichgates on
canEditthe same way.What a decision would look like
own(today, and fix(plugin-audit): forward the caller's execution envelope to the sys_comment sharing gates (#7141) #7143's behaviour) — the comment gate isdeliberately tighter than the parent's edit authority. Then say so in the
contract's doc block, so the next reader does not "fix" it.
edit authority. Needs a depth primitive that does not fail open on an
unmatched object before it can be wired.
Related: #7141, PR #7143, #6523, #6206, ADR-0057 D1, ADR-0111 D1.