Skip to content

feat(messaging): ADR-0030 P2 — subscription + preference#1444

Merged
os-zhuang merged 2 commits into
mainfrom
claude/adr-0030-p2
Jun 1, 2026
Merged

feat(messaging): ADR-0030 P2 — subscription + preference#1444
os-zhuang merged 2 commits into
mainfrom
claude/adr-0030-p2

Conversation

@os-zhuang
Copy link
Copy Markdown
Contributor

Summary

Implements ADR-0030 P2 — Subscription + preference, continuing from the merged P0 (#1434) and P1 (#1441). Adds the Layer-3 preference filter so users can mute notification topics/channels, with admin-global defaults and mandatory-topic bypass.

What changed

Objects

  • sys_notification_preference — per (user_id, topic, channel) toggle (enabled, plus digest/quiet_hours for P3). user_id='*' rows are the admin-global default; a real-user row overrides it; topic/channel support * wildcards. Unique (user_id, topic, channel).
  • sys_notification_subscription — standing subscription of a principal (role:/team:/user:/id) to a topic. Object + schema land now; subscription-driven fan-out (expand a topic's subscribers when a producer emits without explicit audience) is a documented follow-up.

PreferenceResolver (wired into emit())

Inserted between recipient resolution (P1) and fan-out/enqueue:

  • Most-specific-wins resolution over the matrix: user → *, topic → *, channel → *, default ON. A user's row beats the global * default.
  • Mandatory-topic bypass — configurable via MessagingServicePlugin({ mandatoryTopics }), exact match or prefix. (e.g. security.). Users can't mute these.
  • Fail-open — no data engine or a lookup error delivers all channels, so a preference outage never silently swallows notifications.
  • emit() now filters the (recipient × channel) matrix per user (different recipients can accept different channels); fanOut/enqueueDeliveries iterate per-recipient targets.

Wiring

Both objects are registered by MessagingServicePlugin and contributed to the Setup app's Configuration nav slot (ADR-0029 D7), so they appear in REST/Studio only when messaging is installed.

Acceptance (per build spec)

  • ✅ A user muting a topic/channel stops receiving it on that channel.
  • ✅ Mandatory topics still deliver.

Testing

service-messaging: 66 passing — adds preference-resolver.test.ts (resolution matrix: defaults, single-channel mute, topic mute, global-default + user override, specificity, wildcard topic, mandatory exact/prefix bypass, fail-open, org scoping) + an emit-level mute/mandatory-bypass integration test. service-automation 105 ✓, platform-objects 78 ✓.

Follow-ups

  • Subscription-driven fan-out (audience: subscribers).
  • digest / quiet_hours batching middleware → P3.
  • P3: email/push/webhook/Slack channels on connectors + sys_notification_template.
  • Still pending from P0: objectui bell cut-over + mark-read receipt write.

🤖 Generated with Claude Code


Generated by Claude Code

Adds the Layer-3 preference filter so users can mute notification topics/
channels, with admin-global defaults and mandatory-topic bypass.

- sys_notification_preference: per (user_id, topic, channel) toggle; user_id='*'
  = admin-global default, a real-user row overrides it; topic/channel support '*'
  wildcards; unique (user_id, topic, channel). digest/quiet_hours fields for P3.
- sys_notification_subscription: standing subscription of a principal to a topic
  (object + schema now; subscription-driven fan-out is a follow-up).
- PreferenceResolver wired into emit() between recipient resolution and
  fan-out/enqueue. Most-specific-wins (user→*, topic→*, channel→*; default ON).
  Mandatory topics bypass (configurable, exact or prefix.); fail-open on no data
  / lookup error so a preference outage never silently drops notifications.
  emit() now filters the (recipient × channel) matrix per user.
- Both objects registered by the plugin and contributed to the Setup app
  Configuration nav slot (ADR-0029 D7).

Tests: service-messaging 66 passing — adds preference-resolver.test.ts
(resolution matrix) + an emit-level mute/mandatory-bypass test.

https://claude.ai/code/session_015pRGvrm3zrk5m8YvZhkAmF
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 1, 2026 5:34am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Jun 1, 2026
@os-zhuang os-zhuang marked this pull request as ready for review June 1, 2026 05:21
@github-actions github-actions Bot added the size/l label Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants