Skip to content
Centriu
Centriu Loop

Deploy Sequencing Automation: A Rule Written in Prose Is Not a Rule at All

A Centriu Loop deploy shipped new application code that calls its own core ledger-movement function using sixteen named parameters — the function's new, intended shape, matching a migration written specifically to support it. That deploy went out while the live production database still had only an OLDER, twelve-parameter version of that same function, because of the two migrations the new code actually depended on, only one had been applied to production; the other had been prepared but not yet run. The database's own query layer resolves which specific function to call by matching the complete SET of parameter NAMES a request supplies against the parameter names a function actually declares — not by simply counting how many values were passed, and not by comparing their types. Sixteen named parameters, four of them entirely unknown to the live, twelve-parameter function, matched nothing at all — the call failed outright with a "function not found" error, rather than a partial success, a type error, or any softer symptom that might have been noticed sooner. The practical result: launching, using, adjusting, and refunding cashback were all broken end to end, for roughly three hours, because every one of those actions passes through the identical mismatched function call. The gap existed specifically because the rule that would have prevented it — apply every required migration before deploying the code that depends on it — was documented in prose, in the team's own deploy guide, and nowhere enforced by the deploy process itself; a rule that exists only as a sentence a person has to remember is not a rule the system can be relied on to follow.
Code shipped ahead of its migration
Cashback broken end to end, ~3h
Deploy pipeline and database connection diagram
A rule written in prose is not a rule at all.

A documented rule and an enforced rule are not the same thing

Writing down "apply every migration before deploying code that depends on it" in a deploy guide correctly identifies the right rule — the two really do need to happen in that order, every time. But a sentence in a document has no mechanism connecting it to what actually happens at deploy time: it depends entirely on a person remembering it, at the right moment, under whatever pressure or distraction a real deploy carries. The gap between a correctly-stated rule and an actually-enforced one is invisible for as long as the rule is never actually broken — and becomes a real production outage the first time it is.

How the underlying problem shows up before you fix it

A documented operational rule ("do X before Y") exists only as prose in a guide or runbook, with no automated check anywhere in the deploy process confirming the rule was actually followed before code depending on it goes live.

New application code is written and deployed to call a database function using an updated set of named parameters, while the corresponding database migration that would give the function that same updated shape has not yet actually been applied to the target it is being deployed against.

A query layer that resolves a function call by matching the caller's own supplied parameter NAMES against what a function actually declares — rather than by argument count or position — fails a mismatched call OUTRIGHT with a not-found error, rather than degrading gracefully or partially succeeding, which can make the failure look like a different, unrelated kind of problem at first glance.

A single shared function sits behind multiple distinct user-facing actions (here: launching, using, adjusting, and reversing a balance) — meaning one mismatched function call breaks all of those actions simultaneously and completely, rather than degrading one feature while leaving the others intact.

Every other verification a deploy pipeline runs (compiles cleanly, type-checks, passes its own automated tests, matches its own recorded commit) can be completely green, because none of those checks queries the live TARGET database's own actual, current schema — they confirm the code is internally consistent, not that it matches what it is about to run against.

Why a green build and a broken deploy can both be true at once

A build pipeline's own checks — does the code compile, does it type-check, do the automated tests pass, does the deployed artifact match the intended commit — are all genuinely valuable, and none of them, even taken together, can tell you whether the LIVE DATABASE the code is about to run against actually has the specific function shape the code expects. That is a fact about the deploy TARGET's own current, real state, not about the code itself — and a pipeline that never asks the target a direct question ("does this specific function, with this specific parameter list, actually exist on you right now") has no way to catch a mismatch between the two, no matter how many other things it correctly verifies.

What actually happened, and how it was corrected

A Centriu Loop deploy shipped code calling the ledger's own movement-recording function with sixteen named parameters — the function's new, intended shape. The live production database, at that moment, still ran an older, twelve-parameter version of the identical function, because only one of the two migrations the new code required had actually been applied; the second had been written and prepared, but the step to actually run it against production had been skipped.

The underlying database's own query layer resolves precisely which function a call is asking for by matching the caller's complete set of supplied parameter NAMES against a function's own declared parameter names — arity and typing are not what determines the match. Four of the sixteen names the new code supplied did not exist on any function the live database actually had, so the call matched nothing at all, failing immediately with a distinct "function not found" signal rather than any softer or more ambiguous symptom. Because every one of Loop's cashback actions — launching a credit, redeeming it, adjusting a balance, reversing a mistake — passes through this identical shared function, all of them failed together, for roughly three hours, until the mismatch was diagnosed and the missing migration applied.

The diagnosis itself was replicated directly, not just reasoned about after the fact: a real PostgreSQL 16 database was rebuilt to match exactly the pre-fix production state (every prior migration applied, specifically excluding the two the deploy actually needed), and the identical sixteen-parameter call was issued against it — reproducing the exact same failure, and confirming precisely which four parameter names the live function did not yet recognize. The fix itself applied the one missing migration on its own, verified in a dry run beforehand to touch exactly that one migration and no others, restoring the function to its full sixteen-parameter shape with no application code needing to change at all — the code had already been correct from the moment it was written; only the database's own state had lagged behind it.

A closely related, smaller correction landed the same night: the incident's own changelog entry had originally been dated using a mix of time zones — the deploy itself recorded in local time, the migration timestamps recorded in UTC — which made a genuinely three-hour gap between the break and the fix read, at a glance, as if it spanned into the following day. Every timestamp in the record was corrected to a single, explicitly-labeled time zone, so the true, short duration of the outage is what the record actually shows.

What is actually built today

The specific missing migration behind this incident is applied to production, restoring Loop's core ledger-movement function to the full parameter shape its own live application code already expected.

The incident's own root cause was independently reproduced against a real database rebuilt to the exact pre-fix production state, rather than inferred from logs alone — confirming precisely which parameters the mismatch involved.

The incident's own changelog record now uses a single, explicitly-labeled time zone throughout, correcting a mixed-timezone entry that had made a three-hour gap read as if it spanned a full day.

Every cashback action that shares this one underlying function — launch, use, adjustment, and reversal — was restored together, in the same fix, since all four had broken together for the identical underlying reason.

This specific incident directly motivated a dedicated release gate (covered on a companion page) built to check exactly this class of mismatch automatically, before any future deploy, rather than relying on a documented rule alone.

A key cut to a lock that had not been rekeyed yet (illustrative framing of the actual confirmed mechanism)

Before the fix, new application code, cut specifically for a database function's NEW sixteen-parameter shape, was deployed while the live database's own function was still in its OLDER, twelve-parameter shape — like a new key cut for a lock that had not actually been rekeyed yet. The key did not almost fit; it matched nothing at all, and every door depending on that one lock stopped opening. After the fix, the missing migration brought the lock's own shape up to match the key that had already been cut, and every one of those doors opened again.

What changes operationally

The specific migration behind this incident is applied and verified against production, Loop's ledger-movement function matches its own application code's expectations again, and the incident's own record is corrected to a single, accurate time zone — closing an outage where a documented deploy-ordering rule existed only in prose, with nothing in the deploy process itself checking that it had actually been followed.

When this is not the right fit

This automation covers specifically the root cause and correction of one production incident in Centriu Loop's own deploy process — a migration-ordering gap between application code and a live database function. It is a distinct mechanism from this pillar's separate wave 71 page on Loop's deploy-time SQL-safety text scanner, which catches dangerous COMMANDS in migration text before deploy — a different check, at a different stage, for a different class of risk. The dedicated release gate built specifically to prevent a recurrence of THIS incident is covered on its own companion page.

A rule written down vs. a rule the deploy process itself checks

Documenting the correct order of operations in a deploy guide costs almost nothing to write, and it is entirely correct as GUIDANCE — the rule it states really is the right one. Its weakness is that following it depends entirely on a person remembering it correctly, under real conditions, every single time, with no fallback if they don't. Building an automated check that directly confirms, against the live target itself, whether the required migration has actually landed before deploying dependent code closes that gap regardless of what any individual deploy remembers or forgets — which is exactly the shape of the gate this incident motivated, covered on its own companion page.

Related systems

Main system: Centriu Loop.

What it does NOT do

  • Does not indicate any application-code defect — the code deployed was already correct for the function's intended, final shape; the gap was entirely in the live database not yet matching that shape.
  • Does not affect any cashback balance or transaction data — the incident's own account confirms the underlying financial figures remained byte-for-byte identical before and after, with zero divergence.
  • Does not overlap with this pillar's separate wave 71 page on Loop's deploy-time SQL-safety text scanner — that page concerns catching dangerous SQL COMMANDS in migration text before deploy; this page concerns a live function's own parameter contract falling out of sync with already-deployed application code.
  • Does not itself constitute the release gate built to prevent a recurrence — that dedicated mechanism, including its own dual-verification design, is covered on a separate companion page.
  • Does not extend to any other module in Centriu's other systems — this incident and its correction are specific to Loop's own ledger-movement function and the two migrations behind it.

Security and governance

The specific migration behind this incident has been applied and independently verified against production, restoring Centriu Loop's ledger-movement function to match its own already-deployed application code — with the underlying financial data confirmed byte-for-byte unchanged throughout. Any personal or financial data referenced in ledger records remains subject to Brazil's LGPD (Law No. 13,709/2018). Full detail on deploy and change-control practices lives at /governanca and /iso.

Pricing and contracting

Available by monthly subscription, with tiered plans. Values and terms come from the official pricing table at /precos (Centriu's central source — never restated here).

Frequently asked questions

Was any cashback balance lost or corrupted during this incident?

No — the underlying financial figures were confirmed byte-for-byte identical before and after, with zero divergence. The outage affected the ABILITY to launch, use, adjust, or reverse cashback for roughly three hours; it did not alter any existing balance.

Why did the database function fail outright instead of just working incorrectly?

Because the database's own query layer resolves a function call by matching the complete set of parameter NAMES supplied against what a function actually declares. Four of the new call's parameter names did not exist on the live, older function at all, so nothing matched — producing a clean "function not found" error rather than a partial or silently wrong result.

How was the root cause actually confirmed, rather than just guessed at from the error message?

By rebuilding a real database to the exact pre-fix production state and reissuing the identical failing call against it — reproducing the exact same failure and confirming precisely which parameter names the mismatch involved, before applying any fix.

Is this the same finding as the deploy-guard page on this site?

No — that page (wave 71) concerns a text scanner catching dangerous SQL commands in migration files before deploy. This page concerns a live database function's own parameter contract falling out of sync with already-deployed application code, a different failure at a different stage of the same broader deploy process.

What specifically was corrected about the incident's own written record?

Its changelog entry originally mixed local time (for the deploy) and UTC (for the migration timestamps), which made a genuine three-hour gap read as if it spanned an entire extra day. Every timestamp was corrected to one single, explicitly-labeled time zone.

What does Centriu Loop cost?

It is sold by subscription with a published starting price — exact current values are on the central pricing page.

See how Centriu Loop closed this exact deploy-sequencing gap

Reach our commercial team directly, or leave your details below — we'll follow up with guidance for your case.

Sources

  1. Centriu Loop — public product page — Centriu, 2026-07-20 · link(primária)
  2. Centriu Loop — public factsheet (API, JSON) — Centriu, 2026-07-21 · link
  3. Law No. 13,709/2018 — Brazil’s General Data Protection Law (LGPD) — Presidência da República (Brazil), 2018-08-14 · link

Last material update on .

By · AI-assisted production, with human review