emailOutbox has held ZERO rows for 30 days - the drain path is an uncontrolled zero in production
Measured 2026-09-11 on venus prod: SELECT count(*) FROM "emailOutbox" returns 0, with no min/max createdAt. RETENTION_DAYS is 30 and pruneEmailOutbox (src/lib/email-outbox.ts:152-159) only deletes terminal rows older than that, so this is not pruned-away history - nothing has been enqueued for at least 30 days. Found while setting the unschedule gate for VENUS-396. Not blocking it. THE QUESTION: is this a healthy zero or an uncontrolled one? Two very different readings and nothing currently distinguishes them. (a) HEALTHY: happy-path sends go inline and succeed, so a row is only ever written when an inline send FAILS, and none have. Then pg_cron job 1 has correctly drained nothing for its whole life and the outbox is a backstop that has never been needed. (b) BROKEN: rows are not being enqueued on failure at all - the enqueue path is unreached, mis-gated, or swallowing - in which case a failed outbound email is lost silently and the backstop is decorative. This is the shape that matters: a backstop nobody has ever seen fire and a backstop that cannot fire look identical from here. PROVE IT BEFORE READING IT EITHER WAY, per the uncontrolled-zero rule: show the filter CAN return non-empty. Drive enqueueEmail / the inline failure path on the local pg harness (scripts/pg-harness.sh) and assert a row lands with status pending; do NOT insert into prod emailOutbox to manufacture the test - that table carries real clinical mail. Then cross-check outbound volume against appEvents to establish whether any outbound send has failed in the window at all; if literally zero sends have failed in 30 days, that is itself worth confirming rather than assuming. Also worth checking in the same pass: whether the AFTER INSERT wake trigger and dedupeKey path have any production exercise, for the same reason.
Activity
-
support-evolutiva-cc
-
ANSWERED: the zero is HEALTHY, and it has a production witness rather than an assumption. SELECT-only reads on venus prod 2026-10-06 07:10Z plus source at HEAD. (1) emailOutbox is still 0 rows, min/max createdAt NULL, as on 2026-09-11. (2) The failing path HAS run in production. appEvents action='email-sent' is emitted ONLY by drainEmailOutbox after a claimed row sends (src/lib/email-outbox.ts:297-305), and it holds 9 rows, all attemptCount=1: one organic on 2026-07-15 11:10:04Z (subject 'CyT-BMF / Venus / Error 500 - POST /prac...', i.e. the admin error alert failing SMTP inline and being enqueued), and eight deliberate VENUS-287 proof sends on 2026-07-19 08:31-08:42Z. So inline-failure -> enqueueEmail -> claim -> send is exercised end to end in prod, which disproves reading (b): the backstop is not decorative, it has fired. Reading (a) holds with the correction that happy-path-only is not why the table is empty. (3) The table is empty because retention removed the rows, exactly as the row's own premise allows: pruneEmailOutbox deletes terminal rows past RETENTION_DAYS=30, and the newest row of any kind dates to 2026-07-19, eleven weeks ago. Hence min/max NULL rather than old rows. (4) No inline SMTP failure has occurred since 2026-07-19. Coverage limit on that sentence, and it is the one real finding below. (5) The drain SIDE was already proven independently and I am not re-proving it: src/lib/__tests__/email-outbox-drain-harness.test.ts is the VENUS-396 gate-3 positive claim-and-send control on scripts/pg-harness.sh, with forced-red falsification controls, written 2026-10-04. It seeds rows by INSERT, so it covers claim->send and NOT the enqueue side; prod covers the enqueue side per (2). Together the two halves cover the whole path. 478 email-outbox-drain-heartbeat rows since 2026-10-04 cover liveness. (6) The row's last paragraph asks about the AFTER INSERT wake trigger and the dedupeKey path. Both are about mechanism that is not there: the live table carries exactly one trigger, trg_emailoutbox_updatedat, and no dedupeKey column. venus52-emailoutbox-wake-trigger.sql added the wake trigger and venus86-drop-wake-trigger-and-drain-bearer.sql dropped it; the 2026-07-19 08:42Z event subject '[VENUS-287 e2e test] trigger-wake delivery' is its production exercise, from while it existed. dedupeKey appears nowhere in venus db/ or src/ for this table - it is a premise carried in from the MARS-76 port, not a venus surface. Nothing to check on either.
-
THE ONE REMAINING GAP, and it is a PRODUCER gap, not a query-coverage limit. An inline SMTP failure that enqueues successfully writes NO appEvents row at the moment it fails: src/lib/email-transport.ts:252-279 logs outboundEmailSent only on success, and the enqueue branch logs nothing (enqueueEmail itself, email-outbox.ts:143-161, is a bare INSERT with no logEvent). email-admin.ts:105-112 is the same shape. So the failure path has exactly three producers, all of them DOWNSTREAM of the queue: the drain's email-sent / email-outbox-transient-fail / email-outbox-dead-letter, and sendEmailEnqueueFailed on the double fault (0 rows ever). Consequences, each measured rather than asserted: (i) the inline-failure RATE is unobservable except by inference from drain outcomes, and after RETENTION_DAYS the row that carried the evidence is deleted; (ii) a row enqueued but never drained would leave no ledger row at all; (iii) the caller cannot tell queued from sent, because the enqueue branch returns success:true with messageId='queued'. (ii) is currently not live risk: the drain timer is running - 478 email-outbox-drain-heartbeat rows, all verb=GET, latest 2026-10-06 07:05:27Z, roughly 5-minute cadence - so a pending row is picked up. The gap is about what survives, not about delivery. PROPOSED FIX, one warn-tier event in the enqueue branch of both twins, so an inline SMTP failure leaves a durable ledger row independent of queue retention and of whether the drain ever runs. Recipient shaping must go through the existing outboxTelemetry coarse form; no raw address, no caller-supplied string, smtpCode only. This touches the email send path, so it is Class-A: design-ping to audit before implementing and a diff review before pushing. Not implemented yet.
-
ANSWERED, no code change in this row. The zero is healthy and has a production witness: appEvents action='email-sent' is emitted only by drainEmailOutbox (src/lib/email-outbox.ts:297-305) and holds 9 rows, all attemptCount=1 - one organic 2026-07-15 11:10:04Z (admin 500-alert failing SMTP inline, enqueued, drained and sent) plus eight VENUS-287 proofs on 07-19. Inline-failure -> enqueueEmail -> claim -> send is therefore exercised end to end in production, which disproves reading (b). The empty table is the RETENTION_DAYS=30 prune of July rows, consistent with min/max createdAt NULL. No inline SMTP failure since 2026-07-19. Drain liveness independently covered: 478 email-outbox-drain-heartbeat rows, all verb=GET, latest 2026-10-06 07:05:27Z. Drain-side claim-and-send already proven by the VENUS-396 gate-3 harness (src/lib/__tests__/email-outbox-drain-harness.test.ts, 2026-10-04); prod covers the enqueue side, so the two halves cover the whole path. Two row premises killed: venus86-drop-wake-trigger-and-drain-bearer.sql already dropped the AFTER INSERT wake trigger (venus52 added it; its only prod exercise is the 2026-07-19 08:42Z VENUS-287 e2e row), and dedupeKey exists nowhere in venus db/ or src/ for this table - a MARS-76 port premise. Live table carries one trigger, trg_emailoutbox_updatedat. NOT CLOSED SILENTLY: the one real gap found, a producer gap, is filed as its own row per pmmaster-evolutiva-cc-muwcafzhq88h. Read at remote main cfe3a10, venus v1.17.36. SELECT-only throughout; no write to venus prod.