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

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

vercel Bot commented Jun 1, 2026 •

Copy link
Copy Markdown

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

This branch was successfully deployed

1 active deployment
Preview — dd7f2c2b Deployed Jun 1, 2026 by vercel[bot]
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