Build1 distinct publisher3 min readUpdated
An operator of a virtual phone number product lays out the failure modes of a three-line purchase flow. The expensive one is inventory nobody inside the product can see.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
A developer who runs a virtual phone number product has published a breakdown of what a purchase flow really does when it calls a carrier, writes a row to its own database, and creates a Stripe subscription in the same request [1][5]. The three systems share no transaction log, have no two-phase commit, and none of them can roll back the others, so the tidy snippet is an uncompensated distributed transaction with money on both ends [2]. The two directions of leak are simple to state. The carrier keeps invoicing for a number the database has never heard of; Stripe stops invoicing for a number the database still believes is paid up [3]. Neither system raises the subject [4]. Three sequential writes have two gaps between them, and by the author's account every bad state is reachable from a plain network timeout at a bad moment [1][6]. The instinct is to armour the write path with sagas, compensating transactions and idempotency keys everywhere. He recommends the idempotency keys, on the grounds that they cost nothing and do help, while noting the gap does not close: "carrier says yes, then the process dies before the insert" is always reachable, and reordering the calls only changes which orphan you get [9]. That is the part worth internalising. The worst class of orphan is invisible from inside your own product: no row, no user, no support ticket, just a number sitting in the carrier's inventory producing an invoice line every month until somebody actually reads the invoice [7]. The class where a customer is charged for something the product has released at least generates a complaint; the rest leak quietly [8]. His answer is a scheduled reconciler, running daily, designed with three properties [10]. Diagnosis is read-only and physically separate from action: one function reads all three systems and returns a delta, other code decides what to do with it, so the diagnosis can be run from a script against production on a Sunday with zero chance of changing anything [11]. It acts only when intent is unambiguous. Database says pending_cancellation and Stripe says canceled means a customer.subscription.deleted webhook was dropped, so finalize locally [12]. Database says cancelled but the carrier still holds the number means a release call failed, which is rare and where the obvious automated fix is destructive if the diagnosis was wrong, so it logs an anomaly for a human [13]. Anything stranger goes into a deltas array for admin review rather than a clever branch [14]. And it iterates every provider account: they keep more than one account per carrier, and their first orphan scan walked only the primary, leaving orphan inventory undiscovered in the second account for weeks [15]. Two operational details he flags as having paid for themselves. Give the reconciler a real timeout budget, because their run makes four passes with per-row calls out to a carrier, Stripe and an app store, the default serverless function timeout cuts it partway through, the late passes are the money backstops, and a truncated reconciliation looks exactly like a clean one in the logs [16]. Alert on deltas rather than fixes, because nobody reads "reconciled 3 rows" every morning for a year, and the signal you want is the thing the reconciler refused to touch [17]. The second category of pain is typing. "Phone number" is a family of products that the search API flattens into rows that look interchangeable [18]. A result carrying sms: true says the number is technically SMS-capable, not that a message will land, which depends on account configuration, the messaging profile, and in some regions a registration you have not filed [19]. They shipped numbers sold as able to receive texts that could not; the flag was not wrong, it answered a different question than the UI was asking [20].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The purchase flow described is three sequential calls: carrier.numbers.buy to purchase the number, a db.insert into rented_numbers with the user id and E.164 number, and stripe.subscriptions.create for the customer and price.
The three systems share no transaction log, have no two-phase commit, and none of them can roll back the others, making the flow a distributed transaction.
The carrier will keep charging for a number the database has never heard of, and Stripe will stop charging for a number the database still thinks is paid up.
The author states they run a virtual phone number product and are listing the failure modes that actually cost their company money, roughly in order of cost.
Every inconsistent state below the fully consistent one is reachable from a plain network timeout at a bad moment.
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.
Single first-hand operator account, mechanically specific but uncorroborated
The structural claims are self-evident from the posted code and standard distributed-systems reasoning: three sequential cross-system writes with no shared transaction log leave two divergence windows. That part is strong. Everything empirical — the invisible orphan invoice lines, the second-account scan miss, the mis-sold SMS-capable numbers, the serverless truncation — rests entirely on one unnamed practitioner's recollection in one dev.to post, with no counts, invoices, logs, named carriers or second source. No contradicting evidence exists in the cluster either, so the score sits mid-range: internally coherent and plausible, externally unverified.
One self-reported production deployment, no external uptake
Adoption evidence is limited to the author's own product: a daily reconciler running in production against a carrier, Stripe and an app store, and one incident showing an earlier single-account version in use. There is no third-party implementation, no released tool or library, no user counts and no other operator confirming the pattern, so measured adoption is low and confined to the author's own stack.
Slightly understated relative to its own evidence
The post makes no product pitch, names no tool to buy, and repeatedly limits its own claims — idempotency keys 'do help' but do not close the gap, the destructive fix is deliberately not automated, the regulatory bundle flow it built 'has been used zero times'. Its headline mechanism is a plain consequence of the code it shows rather than an extrapolation. The mild negative reflects that the load-bearing operational warning — a truncated reconciliation being indistinguishable from a clean one in the logs — is buried under 'two smaller things that paid for themselves' despite being the most consequential monitoring failure described.
Mild practitioner-credibility incentive, no product being sold
The author has a disclosed commercial interest in a virtual phone number product and gains developer-audience credibility from publishing on dev.to, which creates an incentive to present the company's engineering as competent and its lessons as generalizable. Countervailing signals are strong: the post volunteers unflattering incidents (numbers sold as SMS-capable that could not receive texts, orphan inventory missed for weeks, a compliance flow used zero times), names no product of its own to buy, and does not disparage identified vendors. Carriers are left unnamed, which limits accountability but also removes any obvious vendor-alignment motive.
Confident on mechanism, guarded on magnitude
Confidence is high that the described architecture creates the divergence classes and that the author runs a reconciler as described, because the code, the reasoning and the first-person disclosure are all present in the source. Confidence is much lower on any quantitative or generalizing reading: one publisher, one author, no figures, unnamed carriers, and no way to test whether the per-carrier and per-region claims hold beyond this company's stack. The blended score reflects a well-argued mechanism resting on a thin evidentiary base.
build
A Stripe SDK Major Bump Turned One Metadata Lookup Into a Silent Non-Delivery1 distinct publisher
build
Three ledgers, one payment: reconciliation breaks because the model picked a winner1 distinct publisher
build
A 20-digit ID went into a JSON repair tool and a different number came out1 distinct publisher
build
Your agent's retry logic is reading a timeout as a fact it does not have1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 20, 2026