notification-reliabilitybreakdown.mdscope.md behind this batch. Notes quoted per stub.Two notification defects. The inbox lost its per-family accent colours when a schema cleanup
deleted the UPPER_SNAKE constants the colour map keyed on — every row now renders the default
accent (a known issue accepted at the remove-dead-misc-schema gate but never filed). And
the notification system fails silently by design — Ably and Resend errors are swallowed — with
nothing anywhere recording a failed delivery, so a broken template or key would go unnoticed
indefinitely. Jamie wants accents restored and a place where failures are tracked.
Cross-cutting (notifications reach all six personas); feature-role-matrix: notifications.
Lands in apps/web (inbox UI, an admin visibility surface) and
packages/services/src/notifications/ (delivery outcome recording).
_done/inbox-accent-colours.mdnotification-inbox-list.tsx keys its accent map on the UPPER_SNAKE notification constants
that the remove-dead-misc-schema run deleted, so every inbox row renders the default
accent — the visual grouping by family (bids vs invoices vs SLA breaches) is gone. Known at
that run's ship gate, left for intake, never filed. Jamie's note: "file a fix for the inbox
row default accent color issue We need to have accent colours in the notification inbox."
Re-key the accent map to the live dot.case type families (bid.*, invoice.*, quote.*,
project.*, service-lead.*, user.*, messaging.*, sla.*) — mapping by family prefix
rather than per-type constants so future types in a family inherit their colour — using the
semantic tokens so both themes hold.
Evidence: remove-dead-misc-schema release note ("notification-inbox-list.tsx keys its
accent map on the UPPER_SNAKE constants this run deletes, so every inbox row now renders the
default accent — left for intake but no stub filed"); the 25 live dot.case types across 8
families in packages/services/src/notifications/. Colour choices follow the
brand-guidelines skill (tint for surfaces, semantic tokens). touches:
apps/web/components (notification inbox + centre).
_done/notification-failure-tracking.mdNotifications fail silently by design — the Ably publish warns and swallows, email sending no-ops when unconfigured, and per-send errors vanish. Sensible for the sender's UX, but nothing records that a delivery failed, so a broken template, revoked API key, or bad recipient would go unnoticed until a human complains. Jamie's note: "notifications fail silently by design, we need somewhere to track failed notifications."
Record the delivery outcome per channel (in-app / Ably / email) on or alongside the notification record — failure reason, channel, timestamp — without making sends any less fire-and-forget for the caller. Surface it for admins: a failure count with recent failures (type, recipient, channel, reason) on an admin surface, and a loud signal on the dashboard when failures spike. Keep volume sane on the platform's highest-volume collection (cap or TTL the failure detail).
ABLY_API_KEY unset in an env where it should be set)
becomes visible within a day, not never.Notification, or a separate bounded
notification-delivery-log? The db-audit already flags notifications as the
highest-volume collection with no TTL; Define should answer both together (the missing
TTL is db-audit finding #7).Evidence: swallow points in packages/services/src/notifications/core/publish.ts (warn +
swallow), core/send-email.ts, core/instance.ts (documented fail-silent design,
getResendIfConfigured no-op); models/notification.ts. New model → demo-reset purge-policy
classification (its drift test will insist). Follow the notification skill; any new admin
route follows web-route. touches: packages/services/src/notifications/, apps/web (admin
surface).
Recorded by the intake-easy-features session; these rulings bind Define.
Q2 (what counts as a failure) had no ruling to inherit, so the taxonomy was settled in the
build and now lives on the model
(packages/services/src/db/models/notification-delivery-log.ts):
persist-failed: the notifications write itself failed, so no notification
exists at all. A different class from a channel being down, exactly as Q2 anticipated.transport-error (the Ably publish threw) and not-configured
(ABLY_API_KEY absent).transport-error (Resend threw or returned an error in its response),
not-configured (RESEND_API_KEY absent), template-missing (no TEMPLATE_REGISTRY
entry — the silent never-sends), recipient-missing (no address on the user record).Deliberate suppression is not a failure and is never recorded: a preference switched off,
a type in EMAIL_DISABLED_TYPES, or the fan-out's one-email-per-person dedupe. A
not-configured row is written once per channel per process, so a missing key is visible
within the day without burying the per-send failures.