You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 40cf544
Browse filesBrowse the repository at this point in the historyBrowse files
test(plugin-sharing): pin the membership recompute invariant; changeset and docs
Real-engine pins: a new holder gains the rule's grants, a removed holder
loses them with read and edit refused, moves and window changes follow the
holding, an unrelated position and other holders are untouched, an
organization's rule is pinned to its own rows, a bulk import stays
user-scoped. holdsPosition is pinned equal to the expansion.
Claude-Session: https://claude.ai/code/session_01KqkTQNLcxVc588eZpJmp1r
Co-authored-by: Claude <noreply@anthropic.com>
fix(plugin-sharing): position- and team-recipient sharing rules are re-evaluated for the affected user when the membership behind the recipient changes
6
+
7
+
Clause-②: no
8
+
9
+
A sharing rule's grants are materialised per user. When a position assignment (`sys_user_position`), a membership role (`sys_member.role`, the position transition source) or a team membership (`sys_team_member`) is inserted, deleted, or updated in a column the recipient expansion reads (the user, the position or team, the organization, the validity window), every sharing rule whose recipient the row names is now re-evaluated for the user the row names, before the write returns. A new holder gains the rule's grants and a former holder loses them. Other users' grants, and rules naming other recipients, are not touched.
10
+
11
+
The re-evaluation is scoped to that one user and to the rules naming the recipient: an indexed holder check, that user's grants of the rule, and the rule's criteria read only when the rule reaches the user. A bulk assignment import therefore costs one user-scoped pass per row and never a whole-rule pass. An organization's rule is re-evaluated only for rows of its own organization; a platform-global rule for every row.
12
+
13
+
`SharingRuleService` gains `reconcileRuleForUser(rule, userId)`, the user-scoped pass these hooks run. No spec key, endpoint or configuration changes.
Copy file name to clipboardExpand all lines: content/docs/permissions/permissions-matrix.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -173,7 +173,7 @@ Sharing rules extend access beyond ownership and the depth axis. The declarative
173
173
</Callout>
174
174
175
175
<Callouttype="info">
176
-
**Beyond declarative rules:** Two other sharing mechanisms exist but are **not** `SharingRule` types. **Manual sharing** is a runtime grant — `sys_record_share` rows created with `source: 'manual'` (see `packages/plugins/plugin-sharing/src/sharing-service.ts`). **Matrix / territory-shaped access** is served today by multi-position assignment anchored on business units, plus pre-resolved membership sets: a registered `rls-membership-resolver` (ADR-0105 D11) stages e.g. `territory_account_ids` into `ExecutionContext.rlsMembership`, and a policy references it as `account_id IN (current_user.territory_account_ids)`. The aspirational `TerritorySchema` was removed in ADR-0105 D11 — it had no runtime object, stack field or resolver; a generalized dimension-security module will arrive with its own ADR. Criteria rules are re-evaluated on record insert/update via internal sharing rule hooks, on every write to the rule itself, and once per boot — so deactivating or deleting a rule withdraws the grants it materialized (see [Sharing Rules](/docs/permissions/sharing-rules#switching-a-rule-off-withdraws-the-access-it-granted)).
176
+
**Beyond declarative rules:** Two other sharing mechanisms exist but are **not** `SharingRule` types. **Manual sharing** is a runtime grant — `sys_record_share` rows created with `source: 'manual'` (see `packages/plugins/plugin-sharing/src/sharing-service.ts`). **Matrix / territory-shaped access** is served today by multi-position assignment anchored on business units, plus pre-resolved membership sets: a registered `rls-membership-resolver` (ADR-0105 D11) stages e.g. `territory_account_ids` into `ExecutionContext.rlsMembership`, and a policy references it as `account_id IN (current_user.territory_account_ids)`. The aspirational `TerritorySchema` was removed in ADR-0105 D11 — it had no runtime object, stack field or resolver; a generalized dimension-security module will arrive with its own ADR. Criteria rules are re-evaluated on record insert/update via internal sharing rule hooks, on every write to the rule itself, when the business-unit graph or the position or team membership behind a rule's recipient changes, and once per boot — so deactivating or deleting a rule withdraws the grants it materialized (see [Sharing Rules](/docs/permissions/sharing-rules#switching-a-rule-off-withdraws-the-access-it-granted)).
|**Thewritethatdeactivatesoreditstherule**|Thatrule's grants, immediately — deactivating with `active: false` (or `POST {basePath}/sharing/rules` with the same name) revokes them before the call returns |
221
221
|**Thenextinsert/updateofamatchingrecord**|Thatrecord's grants for every rule on the object — an inactive rule desires nothing, so its rows are revoked |
|**A`sys_user_position`, `sys_member`or`sys_team_member`write**|Thegrantsofruleswhoserecipientisthepositionorteamtherownames (`sys_member.role`isthepositiontransitionsource), re-evaluatedfortheusertherownames — inserts, deletes, andupdatestotheuser, therecipient, theorganizationorthevaliditywindow. Anewholdergainstherule's grants and a former holder loses them **before the write returns**; other users'grantsandrulesnamingotherrecipientsarenottouched|
0 commit comments