Build1 distinct publisher3 min readPublished
Shadow mode hands a candidate email agent the same live inbound events as production and no way to act on them. The work that makes it trustworthy sits in idempotent ingest and in the columns that grade the proposal.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The two identifiers do the work. Nylas delivers webhooks at least once, so a redelivery must not spawn a second shadow run [5]. The top-level notification id is the delivery key and the inner `data.object.id` is the message key, and the post keeps both because they answer different questions [6]. `shadow_events` makes the delivery key its primary key [7]. `shadow_runs` keys on `(notification_id, candidate_version)` [8]. The dedupe unit is therefore delivery times version: a redelivered notification for the same candidate collides and does nothing, while running prompt version A and model version B against the same notification inserts two rows instead of pretending they are one experiment [20][10].
Order matters more than the DDL. Insert the event and its pending run inside the webhook transaction, before enqueueing, with `ON CONFLICT DO NOTHING`, and enqueue only when that statement returns a row [9]. Put the enqueue first and you have moved the idempotency requirement into the worker, which is the half that pays for the model call [17].
Count the columns in `shadow_runs`. Eleven, of which three hold what the candidate produced (`proposed_action`, `input_hash`, `input_snapshot`) and three hold what it gets measured against (`outcome`, `reviewer_verdict`, `actual_message_id`) [18]. That ratio is the honest cost of the stage. Proposals are cheap; the author is clear that the record is only useful beside an outcome you already trust, meaning the production agent's action, a human-approved reply, a support label, or an explicit reviewer verdict [13]. That is also the condition for this design transferring to your shop. If support is humans today and nobody writes the action taken into a structured field, there is nothing to join against, and shadow runs pile up as ungraded prose.
The failure mode named in the post is precisely the one a prose review misses: a candidate that writes well and would have answered a billing question instead of escalating it [14]. A tool change that quietly makes the agent write twice is the same shape [21]. Comparison catches both. Reading the draft catches neither. And the `confidence: 0.91` in the sample proposal is a field the model emitted, not evidence about the model [12].
The draft rule is the sharpest line in the piece: do not create a Nylas draft for the candidate reply, because drafts are visible mailbox state and a human can mistake an experiment for a proposed response and send it [11]. A draft is an experiment with a Send button next to it.
Retention bounds what you can learn later. The example keeps an encrypted, access-controlled input snapshot for 30 days [16] while `input_hash` stays in the row permanently [8], so once the snapshot expires you can still tell whether two runs saw identical input, but you cannot replay either one [19]. The author also declines the easy claim that no-send equals safe: the candidate still reads live customer content, so run it only where you already have authority to process that content, and leave attachments and tools out unless the experiment needs them [15].
Ranked by verification strength, evidence, and original report placement.
The post defines shadow mode as a stage where the candidate agent receives the same live inbound messages as production, reads the same canonical thread context, and records what it would have done.
In shadow mode the candidate never sends, moves, labels, or creates a draft in the customer mailbox, and a person or the existing production workflow still owns the outcome.
Nylas delivers the event and exposes the message and thread data, while the application persists the candidate version, proposed action and comparison result; the author states shadow mode is an application rollout feature, not an email-provider switch.
The author works on the Nylas CLI and uses it to inspect the live plumbing and send test events; the implementation is described as deliberately database-shaped rather than tied to a queue or model provider.
The design subscribes to message.created, and Nylas delivers webhooks at least once, so a redelivery must not create another shadow run.
The top-level notification id is the delivery key and the inner data.object.id is the message key; the post says to keep both because they answer different questions.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 29, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
A unique index is not a duplicate check: the race inside a webhook idempotency middleware1 distinct publisher
build
Notion's agent stack is live, not slideware, and it only changes one of your decisions1 distinct publisher
build
The 680 MB database that was really a 17 GB disk: self-hosted support platforms fail at month six1 distinct publisher
build
Your "Index Only Scan" Did 2,847 Heap Fetches: Covering Indexes Are a Vacuum Problem1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Checkable design, untested in the field
The parts a reader can verify are printed in full: both tables, the conflict clause, the composite key, and the rule that the job is enqueued only when the insert returns a row. That design either holds together on inspection or it doesn't, and it does. Everything outside the code is thinner — the at-least-once webhook guarantee that motivates the whole scheme is asserted by the author rather than cited, the worker is labelled illustrative pseudocode and the excerpt breaks off mid-function, and no instance of this running against live support mail appears anywhere in this reporting.
No one has run it on the record
Nobody in this story reports operating the pattern. There are no shadow-run counts, no team saying which candidate they promoted or rejected because of what the tables showed, no release or deployment attached to it. A schema and a rationale published as a how-to give nothing to measure, and we would rather say so than manufacture a number.
Caveats louder than the pitch
Unusually for the genre, the most forceful sentence in the post is a limitation: no send is an important safety property, and not the whole threat model. It also volunteers that deleting the snapshot at 30 days makes replay impossible on purpose, and that a candidate writing fluent prose instead of escalating a billing question has failed. Against that restraint sits one unearned promise, carried mostly by framing rather than by the text — that two tables are what stands between a fixture and the customer's inbox. They are the start of it; the review process nobody here describes is the rest.
Disclosed vendor interest, verifiable code
The author says up front that he works on the Nylas CLI, and the post leans on that CLI, the Nylas Message API and a Nylas Agent Account while naming an earlier Nylas guide as its prerequisite — a spoke in a content series, in its own words. The disclosure is clean and the schema is useful whether or not you buy anything. Still, notice which conclusion the architecture arrives at: shadow mode is an application concern, not a provider switch, so the vendor's surface stays exactly as it is while the reader's database absorbs the new work.
Sure what it says, unsure what it does
Two things pull opposite ways. The design details are self-evidencing — the deduplication unit really is delivery times candidate version, readable straight off the primary key — so our account of what is being proposed is solid. Whether it holds up in a live support inbox rests on one author's assertion on a developer blog with no usage signal of any kind behind it. High confidence in the description; little in the outcome.