# R5 capability census — BATCH 1 evidence (read-only)

Census date: 2026-06-15. Donor = multideal (primary); cross-checks noted inline. No verdicts.

---

## util
### Donor capabilities (mature) — what the donor actually has in this domain
- Agorot/ILS money formatting suite — multideal/apps/web/src/lib/money.ts:20 — Converts integer agorot to display strings (signed, debt-safe, locale variants).
- Locale-aware currency formatter — multideal/apps/web/src/lib/format.ts:33 — `formatCurrency` via Intl for ILS amounts.
- Israel timezone datetime helpers — multideal/apps/web/src/lib/datetime.ts:9 — `nowInIsrael`, `toIsraelDateString`, `formatDateLocale` anchored to `Asia/Jerusalem`.
- Base64url + hex encoding — multideal/apps/web/src/lib/encoding.ts:13 — CF-safe `bytesToHex`, `base64UrlDecodeStr/Bytes` (no Node Buffer).
- Phone hint label formatter — multideal/apps/web/src/lib/phone.ts:11 — Masks/formats stored phone hints for display.
- Open-redirect sanitizer — multideal/apps/web/src/lib/sanitize-redirect.ts:11 — Parses/decodes redirect params; allows same-origin paths only.
- Display initials helper — multideal/apps/web/src/lib/string.ts:10 — `initialsOf` for avatar fallbacks.
- Client CSRF token reader — multideal/apps/web/src/lib/csrf.ts:11 — Reads double-submit cookie for `x-csrf-token` header.
- Cross-tab auth/mutation broadcast — multideal/apps/web/src/lib/cross-tab-sync.ts:9 — `broadcastMhEvent` / `listenMhEvents` via localStorage + BroadcastChannel.
- Sentry caught-error sink (client) — multideal/apps/web/src/lib/observability/capture.ts:26 — `captureCaught` with PII scrub + scope tags.
- Canonical filter hash — multideal/apps/web/src/lib/geo/canonicalFilterHash.ts:17 — SHA-256 of normalized feed filter for cache keys.
- URL query CSV parse/build — multideal/apps/web/src/lib/url/queryCodec.ts:2 — `csvParse`, `csvBuild`, `clampInt`, `setIfPresent`.
- URL filter state hook — multideal/apps/web/src/lib/url/useUrlFilterState.ts:27 — Bidirectional URL↔state sync with `UrlCodec` + history modes.
- History push/replace policy type — multideal/apps/web/src/lib/url/historyPolicy.ts:1 — `HistoryMode` for filter navigation.
- Zod first-issue extractor — multideal/apps/web/src/lib/validation/zod.ts:4 — `firstZodIssue` replaces duplicated Zod error handling.
- Image encode worker wrapper — multideal/apps/web/src/lib/image-upload/encodeImage.ts:48 — Client-side resize/hash/variant bundle via Web Worker.
- Image upload with typed errors — multideal/apps/web/src/lib/image-upload/uploadImage.ts:12 — `UploadError` + presigned upload flow.
- Optimistic mutation factory — multideal/apps/web/src/lib/query/optimistic.ts:51 — `createOptimisticMutation` for React Query rollbacks.
- Paginated admin list hook — multideal/apps/web/src/lib/hooks/usePaginatedQuery.ts:52 — Client pagination state + SSR seeding.
- Promo value/status formatters — multideal/apps/web/src/lib/promo-formatters.ts:24 — Domain promo display helpers (app-tinted).
- Israeli address input shape — multideal/apps/web/src/lib/address.ts:1 — Shared address form contract (app-tinted).
- Admin table sort/prefs/export — multideal/apps/web/src/lib/admin/table-sort.ts:1 — Admin list UX utilities (app-tinted).
- URL codec plugins (many screens) — multideal/apps/web/src/lib/url/codecs/searchCodec.ts:10 — Per-screen `UrlCodec` serializers (app-tinted).
- zync SSRF outbound URL guard — zync.is/packages/utils/src/ssrf-guard.ts:33 — `validateSafeOutboundUrl` blocks private/reserved hosts.
- zync exponential reconnect backoff — zync.is/apps/zync-app/src/lib/realtime/backoff.ts:15 — `reconnectDelay` with jitter for WS clients.

### DELTA (donor HAS, module surface LACKS)
- Agorot/ILS money formatting — multideal/apps/web/src/lib/money.ts:20 — Integer minor-unit → display strings — sibling-overlap: none
- Locale currency formatter — multideal/apps/web/src/lib/format.ts:33 — Intl-based ILS formatting — sibling-overlap: none
- Israel civil-date helpers — multideal/apps/web/src/lib/datetime.ts:9 — `nowInIsrael` / `formatDateLocale` in fixed TZ — sibling-overlap: none
- Base64url decode helpers — multideal/apps/web/src/lib/encoding.ts:24 — CF-safe encoding beyond hex — sibling-overlap: none
- Open-redirect sanitizer — multideal/apps/web/src/lib/sanitize-redirect.ts:11 — Safe post-login redirect paths — sibling-overlap: none
- Cross-tab event bus — multideal/apps/web/src/lib/cross-tab-sync.ts:9 — Login/logout/mutation sync across tabs — sibling-overlap: none
- Client error capture sink — multideal/apps/web/src/lib/observability/capture.ts:26 — Sentry wrapper with scrubbing — sibling-overlap: none
- Canonical content hash — multideal/apps/web/src/lib/geo/canonicalFilterHash.ts:17 — Stable SHA-256 cache key from filter object — sibling-overlap: none
- URL query codec utilities — multideal/apps/web/src/lib/url/queryCodec.ts:2 — CSV/clamp/setIfPresent helpers — sibling-overlap: none
- URL-driven filter state hook — multideal/apps/web/src/lib/url/useUrlFilterState.ts:27 — React hook for shareable filter URLs — sibling-overlap: none
- Zod first-error helper — multideal/apps/web/src/lib/validation/zod.ts:4 — Single-message Zod extraction — sibling-overlap: none
- Image encode/upload pipeline — multideal/apps/web/src/lib/image-upload/encodeImage.ts:48 — Worker-based resize + upload errors — sibling-overlap: none
- Optimistic mutation helper — multideal/apps/web/src/lib/query/optimistic.ts:51 — Rollback-aware mutation config — sibling-overlap: none
- Client pagination hook — multideal/apps/web/src/lib/hooks/usePaginatedQuery.ts:52 — Admin list page/limit state — sibling-overlap: none
- Phone display formatter — multideal/apps/web/src/lib/phone.ts:11 — Hint masking for UI — sibling-overlap: none
- Display initials helper — multideal/apps/web/src/lib/string.ts:10 — Name → avatar initials — sibling-overlap: none
- SSRF URL validation — zync.is/packages/utils/src/ssrf-guard.ts:33 — Outbound URL safety checks — sibling-overlap: none

### Maturity note
- zync.is is richer for SSRF/outbound URL validation (`packages/utils/src/ssrf-guard.ts`) and WS reconnect backoff (`apps/zync-app/src/lib/realtime/backoff.ts`); multideal is richest overall for money/geo/url/observability/image-upload leaves.

---

## db
### Donor capabilities (mature) — what the donor actually has in this domain
- Neon serverless client factory — multideal/apps/web/src/server/db/client.ts:49 — `getDb` with WebSocket Pool + `poolQueryViaFetch`.
- Tx-capable DrizzleClient union type — multideal/apps/web/src/server/db/client.ts:45 — `DrizzleDb | PgTransaction` for queriers inside/outside tx.
- PII column encrypt/decrypt SQL fragments — multideal/apps/web/src/server/db/crypto.ts:42 — `encrypt`/`decrypt` via `pgp_sym_encrypt/decrypt`.
- Blind index HMAC for lookups — multideal/apps/web/src/server/db/crypto.ts:67 — `blindIndex` deterministic SHA-256 hex for equality search.
- PII write patch helper — multideal/apps/web/src/server/db/pii-write.ts:5 — Typed phone/email patch shapes for encrypted columns.
- Outbox poll with SKIP LOCKED + retry — multideal/apps/web/src/server/db/queries/outbox.ts:27 — `getPendingOutboxEvents` (3 retries, 5-min backoff, dead_at).
- Outbox dead-letter list/redrive — multideal/apps/web/src/server/db/queries/outbox.ts:102 — `listDeadOutbox`, `redriveOutboxEvent`.
- Cron high-water cursor — multideal/apps/web/src/server/db/queries/cron-cursors.ts:5 — `getCursor` / `advanceCursor` monotonic UPSERT.
- Cron run heartbeat — multideal/apps/web/src/server/db/queries/cron-runs.ts:7 — `recordCronSuccess` / `recordCronError` for ops monitoring.
- DLQ counter per queue key — multideal/apps/web/src/server/db/queries/dlq-events.ts:8 — `incrementDeadLetter`, `acknowledgeDlq`.
- Guest access token persistence — multideal/apps/web/src/server/db/queries/guest-access-token.ts:45 — Mint/verify hashed guest purchase tokens.
- Drizzle migration runner (tooling) — multideal/apps/web/package.json:73 — `db:migrate` → `drizzle-kit migrate` (not a library export).
- App schema + ~90 query modules — multideal/apps/web/src/server/db/schema.ts:372 — Full marketplace schema; `queries/` has ~90 domain query files (app-domain; count only).
- zync Hyperdrive client factory — zync.is/packages/db/src/client.ts:11 — `createDb(env)` via postgres.js + Hyperdrive.
- zync Db | DbTx transaction handle type — zync.is/packages/db/src/client.ts:23 — Same querier-in-tx pattern as multideal.
- zync fractional index helpers — zync.is/packages/db/src/lib/fractional-index.ts:26 — `positionBetween`, `needsRebalance`, `rebalanceColumn`.
- zync ticket list cursor codec — zync.is/packages/db/src/queries/support.ts:100 — `encodeTicketCursor` / `decodeTicketCursor`.

### DELTA (donor HAS, module surface LACKS)
- DrizzleClient tx-union type — multideal/apps/web/src/server/db/client.ts:45 — Querier usable in outer db or tx callback — sibling-overlap: none
- PII encrypt SQL fragment — multideal/apps/web/src/server/db/crypto.ts:42 — Column-level `pgp_sym_encrypt` wrapper — sibling-overlap: none
- Blind index for encrypted lookup — multideal/apps/web/src/server/db/crypto.ts:67 — HMAC-SHA256 searchable index — sibling-overlap: none
- Outbox SKIP LOCKED polling — multideal/apps/web/src/server/db/queries/outbox.ts:27 — Concurrent-safe pending fetch — sibling-overlap: jobs
- Outbox retry/dead-letter state — multideal/apps/web/src/server/db/queries/outbox.ts:85 — `markOutboxEventFailed` with dead_at cap — sibling-overlap: jobs
- Outbox dead-letter redrive — multideal/apps/web/src/server/db/queries/outbox.ts:119 — Admin redrive of dead events — sibling-overlap: jobs
- Cron cursor persistence — multideal/apps/web/src/server/db/queries/cron-cursors.ts:5 — Monotonic job cursors for incremental crons — sibling-overlap: jobs
- Cron success/error heartbeat — multideal/apps/web/src/server/db/queries/cron-runs.ts:7 — Ops visibility for scheduled handlers — sibling-overlap: jobs
- DLQ event counter table — multideal/apps/web/src/server/db/queries/dlq-events.ts:8 — Per-queue dead-letter metrics — sibling-overlap: jobs
- Guest access token queries — multideal/apps/web/src/server/db/queries/guest-access-token.ts:45 — Hashed anon resource tokens — sibling-overlap: auth
- Migration runner script — multideal/apps/web/package.json:73 — `drizzle-kit migrate` wired in app tooling — sibling-overlap: none
- Fractional index ordering — zync.is/packages/db/src/lib/fractional-index.ts:26 — Gap-based reorder without full renumber — sibling-overlap: none
- Keyset cursor encode/decode — zync.is/packages/db/src/queries/support.ts:100 — Stable pagination cursors — sibling-overlap: none

### Maturity note
- multideal is richest for production querier/outbox/cron/DLQ patterns; zync.is adds fractional-index ordering and ticket cursor codecs (`packages/db/src/lib/fractional-index.ts`, `queries/support.ts:100`).

---

## auth
### Donor capabilities (mature) — what the donor actually has in this domain
- Session create/rotate/revoke — multideal/apps/web/src/server/auth/session.ts:82 — 30-day sessions, RT grace window, version bumps.
- Argon2id password hash/verify — multideal/apps/web/src/server/auth/credentials.ts:126 — `hashPassword`, `verifyPasswordSmart`, peppered PHC format.
- Magic link issue/consume — multideal/apps/web/src/server/auth/credentials.ts:254 — Token mint + single-use consumption with errors.
- Email verification tokens — multideal/apps/web/src/server/auth/credentials.ts:339 — `createToken` / `consumeToken` for signup/change flows.
- WebAuthn registration stubs — multideal/apps/web/src/server/auth/credentials.ts:425 — Admin WebAuthn option generation (auth path partially stubbed).
- HS256 access JWT sign/verify — multideal/apps/web/src/server/auth/tokens.ts:69 — `signAccessToken`, `verifyAccessToken`, refresh token hash.
- Firebase ID token verify — multideal/apps/web/src/server/auth/tokens.ts:243 — Phone/social login bridge.
- CSRF HMAC token compute/verify — multideal/apps/web/src/server/auth/csrf.ts:57 — Double-submit + HMAC-bound tokens (`computeCsrfToken`, `verifyCsrf`).
- CSRF request middleware — multideal/apps/web/src/server/middleware/csrf.ts:43 — Astro middleware enforcing `x-csrf-token` on mutating routes (host).
- Auth cookie builders — multideal/apps/web/src/server/auth/cookies.ts:83 — Access/refresh/CSRF/vendor-reg cookie set/clear helpers.
- Role resolution + case RBAC — multideal/apps/web/src/server/auth/access.ts:43 — `resolveRoles`, `determineCaseRole` (app-tinted).
- Guard redirect resolver — multideal/apps/web/src/server/auth/guard-outcome.ts:20 — Maps auth errors → safe redirect paths (host).
- DB-backed request rate limit — multideal/apps/web/src/server/security/rate-limit.ts:33 — Token-bucket via `rate_limit_buckets` table (host).
- Rate-limit policy registry — multideal/apps/web/src/server/security/rate-limit-policies.ts:1 — Per-scope max/window definitions (host).
- Per-user password-hash DO lockout — multideal/apps/web-do/src/do/PasswordHashDO.ts:8 — Serial per-user argon2id under DO CPU budget (rate-limit floor).
- Guest access token mint/verify — multideal/apps/web/src/server/db/queries/guest-access-token.ts:45 — Anon purchase confirmation tokens (engine-ish).
- Email verification sweep cron — multideal/apps/web/src/server/cron/email-verifications-sweep.ts:16 — Expire stale verification rows (host).
- zync permission RBAC helpers — zync.is/packages/auth/src/rbac.ts:13 — `hasPermission`, `isAtLeastRole` on JWT claims.
- zync Hono auth guards — zync.is/packages/auth/src/middleware.ts:32 — `requirePermission`, `requireAdminSession`, `requireTier` (host).
- zync native CF rate-limit middleware — zync.is/packages/auth/src/rate-limit.ts:25 — Binding-based 429 middleware (host).
- zync 2FA temp session + lockout constants — zync.is/packages/auth/src/two-factor.ts:16 — Pending-2FA tokens, backup-code attempt cap.
- zync portal/contractor session packages — zync.is/packages/auth/src/portal/session.ts:1 — Separate portal session flows.
- zync login throttle lib — zync.is/apps/zync-api/src/lib/login-throttle.ts:1 — API-layer login throttling.

### DELTA (donor HAS, module surface LACKS)
- Full session lifecycle (create/rotate/revoke-all) — multideal/apps/web/src/server/auth/session.ts:82 — DB-backed sessions with RT rotation — sibling-overlap: none
- Magic link issue/consume — multideal/apps/web/src/server/auth/credentials.ts:254 — Passwordless login tokens — sibling-overlap: none
- Email verification token pair — multideal/apps/web/src/server/auth/credentials.ts:339 — Create/consume verification tokens — sibling-overlap: none
- CSRF token engine — multideal/apps/web/src/server/auth/csrf.ts:57 — HMAC/double-submit token primitives — sibling-overlap: none
- CSRF request middleware — multideal/apps/web/src/server/middleware/csrf.ts:43 — Mutating-route enforcement (host concern) — sibling-overlap: none
- Auth cookie builders — multideal/apps/web/src/server/auth/cookies.ts:83 — HttpOnly access/refresh/CSRF cookie helpers — sibling-overlap: none
- DB token-bucket rate limiter — multideal/apps/web/src/server/security/rate-limit.ts:33 — Per-IP/subject 429 enforcement — sibling-overlap: none
- Per-user hash DO rate-limit/lockout floor — multideal/apps/web-do/src/do/PasswordHashDO.ts:8 — Serial expensive verify per userId — sibling-overlap: none
- Guest/anon resource token — multideal/apps/web/src/server/db/queries/guest-access-token.ts:45 — Hashed time-limited guest access — sibling-overlap: none
- Firebase ID token verification — multideal/apps/web/src/server/auth/tokens.ts:243 — External IdP bridge — sibling-overlap: none
- Case/domain RBAC resolver — multideal/apps/web/src/server/auth/access.ts:61 — `determineCaseRole` for support cases — sibling-overlap: helpdesk
- Guard redirect mapping — multideal/apps/web/src/server/auth/guard-outcome.ts:20 — Auth failure → redirect URL — sibling-overlap: none
- Permission-based Hono guards — zync.is/packages/auth/src/middleware.ts:32 — `requirePermission` / tier gates — sibling-overlap: none
- Expanded RBAC claim helpers — zync.is/packages/auth/src/rbac.ts:13 — Flat permission set checks — sibling-overlap: none
- Native CF rate-limit middleware — zync.is/packages/auth/src/rate-limit.ts:25 — Workers binding middleware — sibling-overlap: none
- 2FA pending-session + backup-code lockout — zync.is/packages/auth/src/two-factor.ts:24 — Temp session TTL and attempt cap — sibling-overlap: none

### Maturity note
- zync.is is richer for RBAC middleware, 2FA, and native CF rate-limit bindings; multideal is richest for session/magic-link/csrf/guest-token/email-verification and DB-backed rate limits.

---

## jobs
### Donor capabilities (mature) — what the donor actually has in this domain
- Cron expression dispatcher — multideal/apps/web/src/server/cron/index.ts:86 — `dispatchCron` maps CF cron strings → handler bundles.
- Cron bundle heartbeat recording — multideal/apps/web/src/server/cron/index.ts:49 — Records success/error per bundle via `cron-runs` queries.
- Outbox cron processor — multideal/apps/web/src/server/cron/process-outbox.ts:34 — Polls outbox, dispatches via handler registry.
- Outbox handler plugin registry — multideal/apps/web/src/server/workflows/outbox/registry.ts:40 — Explicit `OUTBOX_HANDLERS` array (~40+ event kinds).
- Outbox queue producer — multideal/apps/web/src/server/queues/outbox-producer.ts:28 — `enqueueOutbox` sends `{outboxId}` to CF queue post-commit.
- Outbox queue consumer — multideal/apps/web/src/server/queues/outbox-consumer.ts:27 — Batch handler with `ackAll`/`retryAll`.
- LLM job queue producer/nudge — multideal/apps/web/src/server/queues/llm-jobs-producer.ts:37 — `nudgeJobRunner` wakes JobRunner DO.
- LLM job queue consumer — multideal/apps/web/src/server/queues/llm-jobs-consumer.ts:19 — Batch dispatch to `runJob`.
- LLM job runner (never-throws) — multideal/apps/web/src/server/ai/runner.ts:4 — `runJob` returns `ok|retry|fatal`; maps provider errors.
- Per-job-kind plugin registry — multideal/apps/web/src/server/ai/kinds/registry.ts:26 — `JOB_KIND_REGISTRY` typed dispatch table.
- LLM cron backstop + stale reap — multideal/apps/web/src/server/cron/process-llm-jobs.ts:54 — Reaps stuck RUNNING, retries FAILED, SLA alerts.
- Cron cursor advancement (incremental jobs) — multideal/apps/web/src/server/db/queries/cron-cursors.ts:11 — Used by rollup/notif-stats crons.
- DLQ dead-letter counter — multideal/apps/web/src/server/db/queries/dlq-events.ts:8 — Tracks final-retry failures per queue key.
- Rate-limit bucket GC cron — multideal/apps/web/src/server/cron/rate-limit-gc.ts:17 — Cleans expired `rate_limit_buckets` rows.
- Session cleanup cron — multideal/apps/web/src/server/cron/session-cleanup.ts:13 — Expired session purge.
- ~28 additional domain cron handlers — multideal/apps/web/src/server/cron/ — deal-expiry, marketing-lifecycle, returns-sla, etc. (app-domain).
- zync cron route dispatcher — zync.is/apps/zync-api/src/cron/runner.ts:51 — `dispatchCronRoutes` self-fetch HTTP cron map.
- zync invoice-generate queue consumer — zync.is/apps/zync-api/src/queues/invoice-generate.ts:29 — Typed batch consumer with per-message ack/retry.
- zync comms-inbound queue — zync.is/apps/zync-api/src/queues/comms-inbound.ts:1 — Inbound comms queue handler.
- fewtok proxy SSE retry/backoff — fewtok/src/proxy/forward.ts:1 — Transport-level retry in proxy (not a job framework).

### DELTA (donor HAS, module surface LACKS)
- Cron expression → handler bundle map — multideal/apps/web/src/server/cron/index.ts:86 — Multi-job scheduled bundles with dynamic imports — sibling-overlap: none
- Cron ops heartbeat (success/error) — multideal/apps/web/src/server/cron/index.ts:49 — Persists last run status per cron key — sibling-overlap: db
- Explicit outbox handler registry — multideal/apps/web/src/server/workflows/outbox/registry.ts:40 — Closed-set plugin list for event types — sibling-overlap: none
- Outbox 5-min retry + dead_at cap — multideal/apps/web/src/server/db/queries/outbox.ts:44 — Backoff between outbox attempts (platform outbox lacks dead/redrive) — sibling-overlap: jobs
- Outbox dead-letter list/redrive — multideal/apps/web/src/server/db/queries/outbox.ts:102 — Admin redrive of failed outbox rows — sibling-overlap: jobs
- LLM job kind plugin registry — multideal/apps/web/src/server/ai/kinds/registry.ts:26 — Typed per-kind hooks for AI runner — sibling-overlap: none
- Generic runJob lifecycle (ok/retry/fatal) — multideal/apps/web/src/server/ai/runner.ts:4 — Never-throws runner mapping to retry/DLQ — sibling-overlap: none
- Stale RUNNING job reaper — multideal/apps/web/src/server/cron/process-llm-jobs.ts:58 — Resets jobs stuck RUNNING >10 min — sibling-overlap: none
- Cron incremental cursor helpers — multideal/apps/web/src/server/db/queries/cron-cursors.ts:5 — High-water marks for rollup crons — sibling-overlap: db
- DLQ counter persistence — multideal/apps/web/src/server/db/queries/dlq-events.ts:8 — Per-queue dead-letter metrics table — sibling-overlap: db
- HTTP self-fetch cron router — zync.is/apps/zync-api/src/cron/runner.ts:51 — Cron expr → internal POST route list — sibling-overlap: none
- Typed domain queue consumer pattern — zync.is/apps/zync-api/src/queues/invoice-generate.ts:35 — Per-message try/ack/retry in batch — sibling-overlap: none

### Maturity note
- multideal is richest for outbox registry, LLM job lifecycle hooks, cron bundles, and DLQ/cursor integration; zync.is adds HTTP-dispatched cron routing and typed invoice queue consumers.

---

## mail
### Donor capabilities (mature) — what the donor actually has in this domain
- Resend send wrapper — multideal/apps/web/src/server/email/resend.ts:57 — `sendEmail` with React render + dev D1 mock capture.
- React static markup renderer — multideal/apps/web/src/server/email/resend.ts:45 — `renderEmail` via `react-dom/server`.
- React email primitives — multideal/apps/web/src/server/email/primitives.tsx:11 — Lightweight Html/Body/Text/Link components.
- Typed transactional send API — multideal/apps/web/src/server/email/send.ts:131 — `sendReceipt`, `sendMagicLink`, etc. (30+ domain functions).
- ~35 React email templates — multideal/apps/web/src/server/email/templates/ — Receipt, support, marketing, returns families (app-domain content).
- Bulk/broadcast mailer abstraction — multideal/apps/web/src/server/email/bulk-mailer.ts:44 — `BrevoMailer` with upsert/remove/campaign/stats.
- Marketing unsubscribe HMAC tokens — multideal/apps/web/src/server/email/marketing-token.ts:12 — `signUnsubscribeToken` / `verifyUnsubscribeToken`.
- Unsubscribe handler outbox event — multideal/apps/web/src/server/workflows/outbox/handlers/handle-buyer-unsubscribed.ts:1 — Marketing opt-out side effects (app).
- zync MJML-ish template renderer — zync.is/packages/notifications/src/email/render.ts:117 — `renderEmailTemplate` with locale dir/lang + `{{var}}` interpolation.
- zync template escape helper — zync.is/packages/notifications/src/email/escape.ts:1 — HTML interpolation hardening.
- zync Resend adapter — zync.is/packages/notifications/src/email/resend.ts:1 — Thin Resend send wrapper.
- zync multi-channel deliver — zync.is/packages/notifications/src/deliver.ts:1 — Routes email/telegram/web-push from one entry.
- Platform `SuppressionEvent` type only — platform/packages/mail/src/index.ts:2 — Bounce/complaint/unsubscribe shape declared; no store/webhook impl in mail module.

### DELTA (donor HAS, module surface LACKS)
- React email render pipeline — multideal/apps/web/src/server/email/resend.ts:45 — JSX → static HTML for transactional mail — sibling-overlap: none
- React email layout primitives — multideal/apps/web/src/server/email/primitives.tsx:11 — Minimal component set for templates — sibling-overlap: none
- Dev email mock capture (D1) — multideal/apps/web/src/server/email/resend.ts:62 — Non-prod send interception — sibling-overlap: none
- Bulk/broadcast mailer interface — multideal/apps/web/src/server/email/bulk-mailer.ts:20 — `BulkMailer` + Brevo implementation — sibling-overlap: none
- Campaign stats (delivered/opens/bounces) — multideal/apps/web/src/server/email/bulk-mailer.ts:120 — `getCampaignStats` from ESP — sibling-overlap: none
- List contact upsert/remove — multideal/apps/web/src/server/email/bulk-mailer.ts:73 — ESP list membership + blacklist — sibling-overlap: none
- Signed unsubscribe URL tokens — multideal/apps/web/src/server/email/marketing-token.ts:12 — HMAC one-click unsubscribe links — sibling-overlap: none
- MJML-style template registry + render — zync.is/packages/notifications/src/email/render.ts:117 — Locale-aware HTML template interpolation — sibling-overlap: none
- Template interpolation escaping — zync.is/packages/notifications/src/email/escape.ts:1 — Safe `{{key}}` substitution — sibling-overlap: none
- Multi-channel notification deliver — zync.is/packages/notifications/src/deliver.ts:1 — Email + push + telegram routing — sibling-overlap: none
- Suppression list implementation — platform/packages/mail/src/index.ts:2 — Type exists; no donor-style bounce/suppression store in mail module — sibling-overlap: none

### Maturity note
- multideal is richest for React Email transactional sends, Brevo bulk campaigns, and unsubscribe tokens; zync.is is richer for locale-aware template registry and multi-channel deliver (`packages/notifications`).
