From f28321ef7e74097c5929554bf53431f063c576b6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Aug 2026 15:28:10 +0000 Subject: [PATCH 1/3] =?UTF-8?q?docs(service-messaging):=20mark=20the=20sub?= =?UTF-8?q?scription=E2=86=92recipient=20expansion=20not-yet-wired=20(#980?= =?UTF-8?q?7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The object header described a live `audience: 'subscribers'` expansion that does not exist: `AudienceSpec` has no such member, `EmitInput.audience` is required, and no `RecipientResolver` branch expands a topic's subscriptions. Mark it NOT WIRED so the Setup grid is not read as a live routing control, and align the `principal` description with the forms the resolver really accepts. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01PnJHU45vPJj5UQrxe946Bx --- .../notification-subscription.object.ts | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 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 642d31030b..e02bb04680 100644 --- a/packages/services/service-messaging/src/objects/notification-subscription.object.ts +++ b/packages/services/service-messaging/src/objects/notification-subscription.object.ts @@ -6,11 +6,18 @@ import { ObjectSchema, Field } from '@objectstack/spec/data'; * `sys_notification_subscription` — who is subscribed to a topic (ADR-0030 * Layer 3). * - * Declares standing interest in a `topic` by a `principal` (`role:x`, `team:x`, - * `user:id`, or a bare user id). Where a producer emits with `audience: - * 'subscribers'` (or no explicit audience), the resolver expands the topic's - * subscriptions into recipients — the opt-in counterpart to the explicit - * audience most producers pass today. + * Declares standing interest in a `topic` by a `principal` (see that field for + * the accepted selector forms). + * + * ⚠️ [#9807] The subscription→recipient expansion is **NOT WIRED in this + * repo**: `AudienceSpec` (`messaging-service.ts`) has no `'subscribers'` + * member, `EmitInput.audience` is REQUIRED, and no `RecipientResolver` branch + * expands a topic's subscriptions — so nothing here reads these rows at + * runtime. Every delivery today comes from the explicit `audience` a producer + * passes to `emit()`, which makes the Setup "Notification Subscriptions" grid + * admin-authored data, NOT a live routing control. The ADR-0030 Layer-3 + * expansion is future work, deferred on measured zero pull; ADR-0012/0030 + * describe that target state, not today's behaviour. * * Distinct from `sys_notification_preference`: a subscription says "include me * for this topic"; a preference says "but mute it on this channel". @@ -45,7 +52,13 @@ export const NotificationSubscription = ObjectSchema.create({ label: 'Principal', required: true, searchable: true, - description: "Subscriber selector: 'role:x' | 'team:x' | 'user:id' | bare user id.", + // [#9807] Kept in step with what `RecipientResolver.resolveOne()` really + // accepts for a string spec, so this does not under-describe the day the + // expansion above is wired: an email-shaped value is matched against + // `sys_user` (kept verbatim when no user matches), and anything otherwise + // unrecognized falls through as a bare user id. + description: + "Subscriber selector: 'role:x' | 'team:x' | 'user:id' | 'owner_of:object:id' | an email | a bare user id.", }), enabled: Field.boolean({ From aedf352c9a5d2a9f1d4f6c803a37d3a5052e3040 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Aug 2026 15:50:18 +0000 Subject: [PATCH 2/3] chore(service-messaging): regenerate the en translation bundle (#9807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `check:i18n` verdict on the annotation commit: `services/service-messaging DRIFTED (1)`. The default (en) bundle is a copy of the source, rewritten from it on every run (#8543), so the `principal` description edit has to land here too. Generator output — `node scripts/check-i18n-bundles.mjs --write`. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01PnJHU45vPJj5UQrxe946Bx --- .../service-messaging/src/translations/en.objects.generated.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/services/service-messaging/src/translations/en.objects.generated.ts b/packages/services/service-messaging/src/translations/en.objects.generated.ts index ac3330d9a0..4f4da6f80f 100644 --- a/packages/services/service-messaging/src/translations/en.objects.generated.ts +++ b/packages/services/service-messaging/src/translations/en.objects.generated.ts @@ -238,7 +238,7 @@ export const enObjects: NonNullable = { }, principal: { label: "Principal", - help: "Subscriber selector: 'role:x' | 'team:x' | 'user:id' | bare user id." + help: "Subscriber selector: 'role:x' | 'team:x' | 'user:id' | 'owner_of:object:id' | an email | a bare user id." }, enabled: { label: "Enabled", From 980dec44e7e1038bcc238f54aa975d69ee1d04e3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Aug 2026 15:50:41 +0000 Subject: [PATCH 3/3] chore: add changeset for #9807 The `principal` description is a shipped user-visible string (it reaches dist/index.js and the en translation bundle as Setup help text), so this is a real patch changeset rather than a `skip-changeset` comment-only diff. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01PnJHU45vPJj5UQrxe946Bx --- ...cation-subscription-expansion-not-wired.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .changeset/notification-subscription-expansion-not-wired.md diff --git a/.changeset/notification-subscription-expansion-not-wired.md b/.changeset/notification-subscription-expansion-not-wired.md new file mode 100644 index 0000000000..e0f34c5634 --- /dev/null +++ b/.changeset/notification-subscription-expansion-not-wired.md @@ -0,0 +1,24 @@ +--- +"@objectstack/service-messaging": patch +--- + +docs(service-messaging): mark the `sys_notification_subscription` expansion not-yet-wired and align the `principal` description with the resolver (#9807) + +The object header described a live routing control that does not exist: "where a +producer emits with `audience: 'subscribers'` … the resolver expands the topic's +subscriptions into recipients". Nothing implements that. `AudienceSpec` +(`messaging-service.ts`) has no `'subscribers'` member, `EmitInput.audience` is +required, and `RecipientResolver` has no branch that reads +`sys_notification_subscription` — the literal `'subscribers'` occurs exactly once +in the repo, in that sentence. Every delivery today comes from the explicit +`audience` a producer passes to `emit()`, so the Setup "Notification +Subscriptions" grid is admin-authored data, not a live routing control. The +header now says so, per the maintainer ruling on #9807 (annotate now; the +ADR-0030 Layer-3 expansion stays future work, deferred on measured zero pull). + +The `principal` field description shipped a four-form list (`'role:x'` | +`'team:x'` | `'user:id'` | bare user id) narrower than what +`RecipientResolver.resolveOne()` accepts for the same string shape; it now also +names `'owner_of:object:id'` and the email form (matched against `sys_user`). +This is a user-visible string: it ships into `dist/` and into the generated `en` +translation bundle as the field's help text in the Setup grid.