Migration recap · week of August 24 · 2026

This week, the whole stack went to production.

Not cutover — customers are still on the old site, and will be until the day we throw the switch. But the production environment now runs everything: 386 commits promoted, sixteen modules deployed, and every safety gate we’ve built along the way standing guard for real.

The promotion itself was deliberately boring, which is the highest compliment deployment work can earn. The staging branch merged to main through pull requests, production got its own deploy scripts with the same philosophy as everything else here — gates that fail closed, so a script that can’t affirmatively verify its environment refuses to run — and sixteen modules went up. Then every one of them was verified the paranoid way: what the database says it’s running, checked against what’s actually on disk, module by module. Demo payment providers off. Simulation modes off. The environment parameter that hard-blocks destructive tools: set. The dress rehearsal is over; the stage is built and lit. What remains before an audience shows up is data, credentials, and a cutover checklist — not construction.

Second: last week I held a story because it didn’t have an ending. Now it does. The support helpdesk is live — email arrives, becomes a ticket, auto-assigns to our IT director, and sends the customer an acknowledgment; ticket number four closed the loop end to end. Getting there was a guided tour of modern Microsoft 365 email authentication: a send account whose basic SMTP auth had been quietly retired, an OAuth flow that refuses to mint tokens until the account has logged in interactively once — even with MFA off — an inbound address that couldn’t authenticate because it was an alias rather than a real mailbox, and one genuinely devious failure where the browser silently reused an existing login session in the middle of the OAuth connect flow. That last one was solved with an incognito window, which is the kind of fix you only find after exhausting everything dignified.

Third, a win for laziness done right: we scoped bank-account (ACH) payments for checkout, and recon found the capability already there — live in the platform’s built-in processor integration, hidden behind a collapsed “choose another method” element. Zero code for the core feature. The part that genuinely needs building — paying several invoices at once from the portal — is now designed, with server-side validation and amount guards, and goes to build next. “Built-ins first” keeps paying rent precisely because we keep checking before we build.

Fourth, the enrichment machine’s control sample earned its keep. A fresh batch of product research came back almost all low-confidence, and the tempting read was “hard batch.” Instead we re-ran a batch with known-good history — and it collapsed the same way. That meant the research model itself had drifted, not our parts: its citations were wandering off to a government vulnerability database and home-improvement retailers instead of sewing-machine sources. A domain hint prepended to the research query brought the known-good batch back to its old numbers, and the hint ships behind an A/B flag so we can keep proving it’s the hint doing the work. Trust nothing without a control — especially the parts of the machine you don’t operate.

Two closing lines from the trenches. The recurring mystery regressions in our two-developer workflow finally got a root cause: promoting code by copying folders instead of merging branches creates parallel histories that git cannot reconcile — it just silently overwrites, and what it overwrites is your fixes. One reconciliation merge later, the rule is simple: merges only, never copies. And a stakeholder review produced a punch list where recon revealed one requested “feature” was actually a bug — a field indexed under one name and fetched under another, so it had never rendered — and caught one surface violating our own every-price-through-the-engine rule. Flagged for immediate fix, and I’d rather catch our own rule broken in our own audit than any other way.

Three hundred eighty-six commits to production, and the most important lesson of the week still came from a control sample and a diff. That feels about right.