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
[Decision] service-messaging: should fan-out consult per-tenant channel availability (a new MessagingChannel member) so no delivery row is written for a channel with no transport? — split from #17611 #17732
Split from #17611's ruling (C taken; A deferred to its own pricing). ⛔ A decision card: the question is whether to widen a published interface, which is the maintainer's floor, so it is filed needs-user-decision rather than queued.
At fan-out, resolve channel availability per tenant. For a channel whose transport is not configured, write nosys_notification_delivery row; record on sys_notification that the channel was suppressed and why. Hot-table cost for such channels goes to zero; the suppression stays auditable at the notification level.
Why it is its own card, and why it is a decision
Measured by the services seat on origin/main @ 6fa2a8ae1 (5641086533 on #17611): MessagingChannel (packages/services/service-messaging/src/channel.ts) has three members — id, send(), optional classifyError?() — and no availability or capability query; fan-out (messaging-service.ts) only checks that the channel is REGISTERED, and the reported case is a channel that is registered while the tenant has no transport, one layer below. ⇒ A adds a member to a published interface, with tenant context, and every channel implementation (inbox, email today; webhook, push, chat channels later) has to answer it. That is a Clause-②: yes widening and a declare-and-maintain obligation.
What the ruling on #17611 already bought, and what this card is for
#17611 C caps terminal rows at 7d through the existing retention.onlyWhen key (the same shape as sys_automation_run), which by the seat's arithmetic turns a ~28,000-row ceiling into ~2,200. The remaining question is whether the existence of workless rows is acceptable at all, or only their age. If the former, A is the fix; if the latter, C is sufficient and this card closes as not planned.
Options
what
cost
A
Add the availability member to MessagingChannel, consult it at fan-out, suppress with a recorded reason
published-interface widening; every channel implements it; a per-tenant availability answer may cost an I/O round trip at fan-out (unmeasured)
hold
Take no contract change; let #17611's 7d retention run and read the table again
zero cost; the hot table still carries ~2,200 workless rows at steady state on the reporting tenant
Split from #17611's ruling (C taken; A deferred to its own pricing). ⛔ A decision card: the question is whether to widen a published interface, which is the maintainer's floor, so it is filed
needs-user-decisionrather than queued.一句话问题
租户没有配置某个渠道(例如没有邮件传输)时,通知 fan-out 现在仍然为该渠道写一行投递记录,这一行第一次尝试就死信。要不要让 fan-out 在写之前先问一句「这个租户这个渠道能发吗」,不能就不写这一行,只在通知上记录该渠道被抑制及原因?代价是给已发布的
MessagingChannel接口新增一个可用性成员。The proposal (the reporter's option A on #17611)
At fan-out, resolve channel availability per tenant. For a channel whose transport is not configured, write no
sys_notification_deliveryrow; record onsys_notificationthat the channel was suppressed and why. Hot-table cost for such channels goes to zero; the suppression stays auditable at the notification level.Why it is its own card, and why it is a decision
Measured by the services seat on
origin/main@6fa2a8ae1(5641086533 on #17611):MessagingChannel(packages/services/service-messaging/src/channel.ts) has three members —id,send(), optionalclassifyError?()— and no availability or capability query; fan-out (messaging-service.ts) only checks that the channel is REGISTERED, and the reported case is a channel that is registered while the tenant has no transport, one layer below. ⇒ A adds a member to a published interface, with tenant context, and every channel implementation (inbox, email today; webhook, push, chat channels later) has to answer it. That is aClause-②: yeswidening and a declare-and-maintain obligation.What the ruling on #17611 already bought, and what this card is for
#17611 C caps terminal rows at 7d through the existing
retention.onlyWhenkey (the same shape assys_automation_run), which by the seat's arithmetic turns a ~28,000-row ceiling into ~2,200. The remaining question is whether the existence of workless rows is acceptable at all, or only their age. If the former, A is the fix; if the latter, C is sufficient and this card closes as not planned.Options
MessagingChannel, consult it at fan-out, suppress with a recorded reason⛔ Confidence gaps carried from #17611
emaildelivery for a tenant with no email transport — it dead-letters on its first attempt and is kept 90d, so the hot outbox grows ~1 dead row per notification #17611); if it does not, C yields nothing there and this card is the live one.deademail rows (reports, SLA, manual triage).Refs
#17611 (ruling C, 2026-09-12) · 5641086533 (the services seat's four-facet price) · #17609 (driver-side missing index) · #17610 (scheduler idle cost) · hotcrm#1892 (12 flows notify on
['inbox','email'])Filed by the director seat,
session_01QsCVSivtpwT6ZXs5Rtvqxe, 2026-09-12T01:0xZ, with Claude Code.Generated by Claude Code