From 99521a51ca76ed61b47e71f0e1341576546c374b Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Aug 2026 07:45:00 +0000 Subject: [PATCH] fix(service-messaging): correct sys_notification_subscription index comment to name sys_member/sys_team_member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The (topic, principal) unique-index comment claimed role:x/team:x resolve against sys_permission_set/sys_position (citing #8461/#8556, which scoped those objects' OWN uniqueness — an unrelated precedent, not evidence about what this selector resolves against). RecipientResolver.resolveRole/ .resolveTeam (the sole reader of this selector) actually read sys_member and sys_team_member — pinned by recipient-resolver.test.ts. The comment's own worked example (role:sales_manager) was not even a reachable sys_member.role value (closed vocabulary: owner/admin/delegated_admin/ member); sales_manager is sys_position's example name, a different object this selector does not read. Searched docs/adr/ and the cited #8461/#8556 threads for evidence the comment recorded RULED/intended semantics before touching it (per the card's stop-condition) — found none; both PRs are about the general per-organization index-scoping pattern for other objects, and ADR-0090 D3 independently confirms sys_member.role as the sole permitted "role" spelling platform-wide, consistent with the resolver. Comment-only: no schema field, index declaration, or behavior changed. The tenancy argument stays load-bearing (both sys_member and sys_team_member are tenant-scoped), and the example moved to the reachable role:admin. Fixes #9722 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PnJHU45vPJj5UQrxe946Bx --- .../notification-subscription.object.ts | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/services/service-messaging/src/objects/notification-subscription.object.ts b/packages/services/service-messaging/src/objects/notification-subscription.object.ts index cdb14c53b8..642d31030b 100644 --- a/packages/services/service-messaging/src/objects/notification-subscription.object.ts +++ b/packages/services/service-messaging/src/objects/notification-subscription.object.ts @@ -72,13 +72,24 @@ export const NotificationSubscription = ObjectSchema.create({ // org_yi (billing.invoice, user:u1) 201 / org_yi's own GET on the // colliding pair 0 rows. // - // ⚠️ `principal` names are per-organization: `role:x` and `team:x` - // resolve against `sys_permission_set` / `sys_position` rows that - // #8461 and #8556 already scoped per organization, so `role:sales_manager` - // denoted a DIFFERENT principal in each organization while colliding on - // one installation-wide key. And a user who belongs to two - // organizations could not subscribe to the same topic in both — the - // symptom #8323 measured on `sys_user_preference`. + // ⚠️ [#9722, correcting this note] `principal` names are per-organization: + // `role:x` resolves against `sys_member` (tenant-scoped org-membership + // rows — the org-administration tier that is the sole ADR-0090 D3 + // "role" exception) and `team:x` against `sys_team_member` (tenant-scoped + // via its `team_id` lookup into `sys_team`, itself per-organization) — + // per `RecipientResolver.resolveRole` / `.resolveTeam` + // (`recipient-resolver.ts`, the sole reader of this selector). NOT + // `sys_permission_set` / `sys_position` as an earlier version of this + // note claimed — this selector has no `permission_set:` or + // `position:` spelling at all; `sys_position` names business roles + // like `sales_manager` elsewhere on the platform, unrelated to + // `role:`/`team:` here. So `role:admin` denotes a DIFFERENT set of + // members in each organization (`sys_member.role` is the closed + // owner/admin/delegated_admin/member vocabulary — see + // `BUILTIN_MEMBERSHIP_ROLE_OPTIONS`) while colliding on one + // installation-wide key. And a user who belongs to two organizations + // could not subscribe to the same topic in both — the symptom #8323 + // measured on `sys_user_preference`. // // ⚠️ `managedBy: 'system-data'` is NOT a reason to exempt this object; // the already-ruled `sys_user_preference` is `system-data` too. The