ADR 0004: A Compensating Saga Rather Than Two-Phase Commit
Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.
A corridor transfer spans a database, a blockchain and a bank rail. It must debit a sender, convert currency, settle on-chain, and pay out — and any step can fail.
Decision
An explicit saga: compliance → reserve → swap → settle → payout, each step with an execute and a compensate. On failure the saga walks the completed steps backwards and compensates each.A compensation is the exact reverse of the journal that step posted — every direction flipped, same accounts, same amounts.
Consequences
Good. Compensation is safe by arithmetic rather than by careful coding: if the original journal balanced, its reversal balances, so a compensation can never itself unbalance the ledger. That matters because the compensation path only runs when something has already gone wrong.The claim is enforced. The chaos suite fails each of the five steps in turn and asserts the ledger balances in every currency, the sender’s balance is exactly unchanged, and every intermediate account returns to zero.Order is asserted separately, and had to be. For the ledger alone, order is irrelevant — reversals commute. Mutation testing showed compensating forward passed every test. It is still wrong: the rail recall must precede the settlement unwind, and each reversal must describe the step it actually undoes. Balance is necessary but not sufficient — an audit trail can be false while the arithmetic is true.Costs. There is no isolation: a partially completed transfer is observable between steps. Reversing the on-chain leg is a ledger-level compensation representing funds recovered from the settlement partner — nothing un-sends a confirmed transaction, and the gas fee is deliberately never reversed because it was really spent.
Alternatives
Two-phase commit — impossible. Banks and blockchains do not enrol in a distributed transaction, and no coordinator can hold a prepare across a chain finality window.Best-effort with manual cleanup — what many systems do, and what produces reconciliation breaks nobody can explain.Reserving with holds instead of debiting — complementary rather than alternative; the ledger models holds and wiring them at quote time is still open.
{"docsConfig":{"theme":"palm","$schema":"https://mintlify.com/docs.json","name":"Arc","description":"Arc is a simulation of cross-border stablecoin and fiat infrastructure for the EU↔Africa corridor — and a field guide to how stablecoin payments actually work.","colors":{"primary":"#14B8A6","light":"#2DD4BF","dark":"#0F766E"},"logo":{"light":"https://mintcdn.com/arc-doc/m0ZoL8ScOCykrqmD/logo/arc-light.svg?fit=max\u0026auto=format\u0026n=m0ZoL8ScOCykrqmD\u0026q=85\u0026s=90e2e1d537056757a14f4f611ff78d11","dark":"https://mintcdn.com/arc-doc/m0ZoL8ScOCykrqmD/logo/arc-dark.svg?fit=max\u0026auto=format\u0026n=m0ZoL8ScOCykrqmD\u0026q=85\u0026s=58a04971d1ea14b20bd347e971014244","href":"/"},"favicon":"https://mintcdn.com/arc-doc/m0ZoL8ScOCykrqmD/logo/mark.svg?fit=max\u0026auto=format\u0026n=m0ZoL8ScOCykrqmD\u0026q=85\u0026s=24cce491a91f6bde7dfc139f0b283c8e","appearance":{"default":"dark"},"navbar":{"links":[{"href":"/start/quickstart","label":"Run it locally"},{"href":"https://github.com/el-uno/fintech_arc/blob/main/docs/BUILD_PLAN.md","label":"Build plan"}],"primary":{"type":"github","href":"https://github.com/el-uno/fintech_arc"}},"footer":{"socials":{"github":"https://github.com/el-uno/fintech_arc"}},"search":{"prompt":"Search the corridor"},"fonts":{"heading":{"family":"Inter"},"body":{"family":"Inter"}},"styling":{"eyebrows":"breadcrumbs","codeblocks":"dark","latex":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"arc-doc","hasAudioNarration":false,"actualSubdomain":"arc-doc","customDomains":["arc.udokaam.dev"],"gitSource":{"type":"github","owner":"udoka-am","repo":"fintech_arc","deployBranch":"main","contentDirectory":"apps/docs-site","isPrivate":false,"mountPath":"","label":""},"entitlements":{},"buildId":"6aea22181e900d99c6189d28:success","clientVersion":"0.0.4128","searchFilterCounts":[{"language":"default","tag":"Architecture","count":23},{"language":"default","tag":"IRL Scenarios","count":16},{"language":"default","tag":"Guide","count":10},{"language":"default","tag":"Decisions","count":9},{"language":"default","tag":"Practice","count":7},{"language":"default","tag":"The corridor problem","count":6},{"language":"default","tag":"The core","count":5},{"language":"default","tag":"Foundations","count":5},{"language":"default","tag":"Work through it","count":5},{"language":"default","tag":"Start here","count":4}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"/* cyrillic-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2');\n unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2');\n unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2');\n unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 700;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 700;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 700;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2');\n unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 700;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 700;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 700;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Inter';\n font-style: normal;\n font-weight: 700;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx3cwhsk.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxTcwhsk.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxPcwhsk.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* vietnamese */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx_cwhsk.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx7cwhsk.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwg.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx3cwhsk.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxTcwhsk.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxPcwhsk.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* vietnamese */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx_cwhsk.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx7cwhsk.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwg.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx3cwhsk.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxTcwhsk.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxPcwhsk.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* vietnamese */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx_cwhsk.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPx7cwhsk.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'JetBrains Mono';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(/_mintlify/assets/fonts/google/s/jetbrainsmono/v24/tDbv2o-flEEny0FZhsfKu5WU4zr3E_BX0PnT8RD8yKwBNntkaToggR7BYRbKPxDcwg.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n:root{--arc-teal: #2dd4bf;--arc-teal-deep: #14b8a6;--arc-amber: #f59e0b;--arc-rose: #fb7185;--arc-ground: #0d1117;--arc-raised: #151b23;--arc-sunken: #090d13;--arc-hairline: #232b36;--arc-ink: #e6edf3;--arc-ink-dim: #9aa7b4;--arc-ink-faint: #6b7785;--arc-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace}.light{--arc-ground: #ffffff;--arc-raised: #f7f9fa;--arc-sunken: #eef2f5;--arc-hairline: #dfe5ea;--arc-ink: #0d1117;--arc-ink-dim: #4a5561;--arc-ink-faint: #78838f}body{font-feature-settings:'cv05', 'ss01', 'tnum';letter-spacing:-0.006em}h1,h2,h3,h4{letter-spacing:-0.024em;font-weight:650}h1{letter-spacing:-0.032em}h2::before{content:'▚ ';color:var(--arc-teal);font-family:var(--arc-mono);font-weight:500;opacity:0.55}table{font-variant-numeric:tabular-nums}table td:not(:first-child),table th:not(:first-child){text-align:right;font-family:var(--arc-mono);font-size:0.86em}table td:first-child{font-family:var(--arc-mono);font-size:0.86em}code,pre,kbd{font-family:var(--arc-mono);font-feature-settings:'liga' 0}:not(pre)>code{border:1px solid var(--arc-hairline);border-radius:4px;background:var(--arc-sunken);color:var(--arc-teal);padding:0.1em 0.36em;font-size:0.86em;font-weight:500}pre{border:1px solid var(--arc-hairline);border-radius:6px;box-shadow:none}.arc-eyebrow{display:block;font-family:var(--arc-mono);font-size:0.7rem;font-weight:600;letter-spacing:0.14em;text-transform:uppercase;color:var(--arc-teal);margin-bottom:0.6rem}.arc-eyebrow--amber{color:var(--arc-amber)}.arc-eyebrow--dim{color:var(--arc-ink-faint)}.arc-stats{display:grid;grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));gap:1px;background:var(--arc-hairline);border:1px solid var(--arc-hairline);border-radius:6px;overflow:hidden;margin:1.75rem 0}.arc-stat{background:var(--arc-raised);padding:1rem 1.1rem}.arc-stat__value{display:block;font-family:var(--arc-mono);font-size:1.45rem;font-weight:600;line-height:1.1;color:var(--arc-teal);font-variant-numeric:tabular-nums}.arc-stat__label{display:block;margin-top:0.4rem;font-size:0.78rem;line-height:1.4;color:var(--arc-ink-dim)}.arc-stat__source{display:block;margin-top:0.35rem;font-family:var(--arc-mono);font-size:0.66rem;letter-spacing:0.04em;color:var(--arc-ink-faint)}.arc-claim{border-left:2px solid var(--arc-teal);background:linear-gradient(90deg, rgba(45, 212, 191, 0.06), transparent 70%);padding:0.9rem 1.1rem;margin:1.6rem 0;border-radius:0 5px 5px 0}.arc-gap{border-left:2px solid var(--arc-amber);background:linear-gradient(90deg, rgba(245, 158, 11, 0.06), transparent 70%);padding:0.9rem 1.1rem;margin:1.6rem 0;border-radius:0 5px 5px 0}.arc-claim p:last-child,.arc-gap p:last-child{margin-bottom:0}.arc-symptom{font-size:1.08rem;line-height:1.6;color:var(--arc-ink);border:1px solid var(--arc-hairline);border-radius:6px;background:var(--arc-sunken);padding:1.15rem 1.3rem;margin:1.5rem 0 2rem}.arc-symptom::before{content:'SYMPTOM';display:block;font-family:var(--arc-mono);font-size:0.66rem;letter-spacing:0.16em;color:var(--arc-rose);margin-bottom:0.55rem}.arc-cite{font-size:0.82rem;color:var(--arc-ink-faint);font-family:var(--arc-mono)}.mermaid{background:var(--arc-sunken);border:1px solid var(--arc-hairline);border-radius:6px;padding:1rem}"}],"page":{"pagePath":"decisions/0004-saga-over-two-phase-commit","slug":"/decisions/0004-saga-over-two-phase-commit","pageMetadata":{"title":"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit","sidebarTitle":"ADR 0004","description":"Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.","icon":"diagram-project","keywords":["saga pattern","compensating transactions","two-phase commit","distributed transactions","payment orchestration","chaos testing"],"href":"/decisions/0004-saga-over-two-phase-commit"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={code:`code`,em:`em`,p:`p`,strong:`strong`,..._provideComponents(),...props.components},{Heading,Info}=_components;if(!Heading)_missingMdxReference(`Heading`,true);if(!Info)_missingMdxReference(`Info`,true);return _jsxs(_Fragment,{children:[_jsx(`span`,{className:`arc-eyebrow`,children:`ADR 0004 · Accepted · Phase 4`}),`\n`,_jsx(Info,{children:_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Status:`}),` Accepted · `,_jsx(_components.strong,{children:`Phase:`}),` 4 · `,_jsx(_components.strong,{children:`Supersedes:`}),` none · `,_jsx(_components.strong,{children:`Superseded by:`}),` none`]})}),`\n`,_jsx(Heading,{level:`2`,id:`context`,children:`Context`}),`\n`,_jsx(_components.p,{children:`A corridor transfer spans a database, a blockchain and a bank rail. It must debit a sender, convert currency, settle on-chain, and pay out — and any step can fail.`}),`\n`,_jsx(Heading,{level:`2`,id:`decision`,children:`Decision`}),`\n`,_jsxs(_components.p,{children:[`An explicit `,_jsx(_components.strong,{children:`saga`}),`: `,_jsx(_components.code,{children:`compliance → reserve → swap → settle → payout`}),`, each step with an `,_jsx(_components.code,{children:`execute`}),` and a `,_jsx(_components.code,{children:`compensate`}),`. On failure the saga walks the completed steps `,_jsx(_components.strong,{children:`backwards`}),` and compensates each.`]}),`\n`,_jsxs(_components.p,{children:[`A compensation is the `,_jsx(_components.strong,{children:`exact reverse of the journal that step posted`}),` — every direction flipped, same accounts, same amounts.`]}),`\n`,_jsx(Heading,{level:`2`,id:`consequences`,children:`Consequences`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Good.`}),` Compensation is safe by `,_jsx(_components.em,{children:`arithmetic`}),` rather than by careful coding: if the original journal balanced, its reversal balances, so a compensation can never itself unbalance the ledger. That matters because the compensation path only runs when something has already gone wrong.`]}),`\n`,_jsx(_components.p,{children:`The claim is enforced. The chaos suite fails each of the five steps in turn and asserts the ledger balances in every currency, the sender’s balance is exactly unchanged, and every intermediate account returns to zero.`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Order is asserted separately, and had to be.`}),` For the ledger alone, order is irrelevant — reversals commute. Mutation testing showed compensating `,_jsx(_components.em,{children:`forward`}),` passed every test. It is still wrong: the rail recall must precede the settlement unwind, and each reversal must describe the step it actually undoes. `,_jsx(_components.strong,{children:`Balance is necessary but not sufficient — an audit trail can be false while the arithmetic is true.`})]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Costs.`}),` There is no isolation: a partially completed transfer is observable between steps. Reversing the on-chain leg is a `,_jsx(_components.em,{children:`ledger-level`}),` compensation representing funds recovered from the settlement partner — nothing un-sends a confirmed transaction, and the gas fee is deliberately never reversed because it was really spent.`]}),`\n`,_jsx(Heading,{level:`2`,id:`alternatives`,children:`Alternatives`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.em,{children:`Two-phase commit`}),` — impossible. Banks and blockchains do not enrol in a distributed transaction, and no coordinator can hold a prepare across a chain finality window.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.em,{children:`Best-effort with manual cleanup`}),` — what many systems do, and what produces reconciliation breaks nobody can explain.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.em,{children:`Reserving with holds instead of debiting`}),` — complementary rather than alternative; the ledger models holds and wiring them at quote time is still open.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"codeStyling":"dark","config":{},"pageMetadata":{"title":"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit","sidebarTitle":"ADR 0004","description":"Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.","icon":"diagram-project","keywords":["saga pattern","compensating transactions","two-phase commit","distributed transactions","payment orchestration","chaos testing"],"href":"/decisions/0004-saga-over-two-phase-commit"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Context","slug":"context","depth":2,"children":[]},{"title":"Decision","slug":"decision","depth":2,"children":[]},{"title":"Consequences","slug":"consequences","depth":2,"children":[]},{"title":"Alternatives","slug":"alternatives","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"arc-doc","siteName":"Arc","title":"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit - Arc","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-08-14T01:40:08.891Z","originalFileLocation":"decisions/0004-saga-over-two-phase-commit.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"dark\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Arc\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit - Arc\">\u003cmeta data-mint-head property=\"og:description\" content=\"Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Arc\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://arc-doc.mintlify.site/_mintlify/api/og/v2?division=Decisions\u0026amp;title=ADR+0004%3A+A+Compensating+Saga+Rather+Than+Two-Phase+Commit\u0026amp;description=Why+a+corridor+transfer+is+a+saga+with+a+compensating+action+per+step%2C+given+that+banks+and+blockchains+do+not+participate+in+distributed+transactions.\u0026amp;theme=a62ca8cb35008bd1421320f2\u0026amp;signature=025615426be46dabb75829043d0ee82e7cbf0ff76a0ac5efb08f116fd471e5af\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit - Arc\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://arc-doc.mintlify.site/_mintlify/api/og/v2?division=Decisions\u0026amp;title=ADR+0004%3A+A+Compensating+Saga+Rather+Than+Two-Phase+Commit\u0026amp;description=Why+a+corridor+transfer+is+a+saga+with+a+compensating+action+per+step%2C+given+that+banks+and+blockchains+do+not+participate+in+distributed+transactions.\u0026amp;theme=a62ca8cb35008bd1421320f2\u0026amp;signature=025615426be46dabb75829043d0ee82e7cbf0ff76a0ac5efb08f116fd471e5af\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/arc-doc/8qf7D6aInLMuoIah/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Arc\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#14B8A6\">\u003clink data-mint-head rel=\"canonical\" href=\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/decisions/0004-saga-over-two-phase-commit.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://arc.udokaam.dev/#organization\",\"name\":\"Arc\",\"url\":\"https://arc.udokaam.dev\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/arc-doc/m0ZoL8ScOCykrqmD/logo/arc-light.svg?fit=max\u0026auto=format\u0026n=m0ZoL8ScOCykrqmD\u0026q=85\u0026s=90e2e1d537056757a14f4f611ff78d11\"}},{\"@type\":\"WebSite\",\"@id\":\"https://arc.udokaam.dev#website\",\"name\":\"Arc\",\"url\":\"https://arc.udokaam.dev\",\"publisher\":{\"@id\":\"https://arc.udokaam.dev/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit#webpage\",\"url\":\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit\",\"name\":\"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit\",\"description\":\"Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.\",\"dateModified\":\"2026-08-14T01:40:08.891Z\",\"isPartOf\":{\"@id\":\"https://arc.udokaam.dev#website\"},\"breadcrumb\":{\"@id\":\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Decisions\",\"item\":\"https://arc.udokaam.dev/decisions\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit\",\"item\":\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit#article\",\"headline\":\"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit\",\"name\":\"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit\",\"description\":\"Why a corridor transfer is a saga with a compensating action per step, given that banks and blockchains do not participate in distributed transactions.\",\"url\":\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit\",\"mainEntityOfPage\":{\"@id\":\"https://arc.udokaam.dev/decisions/0004-saga-over-two-phase-commit#webpage\"},\"dateModified\":\"2026-08-14T01:40:08.891Z\",\"keywords\":\"saga pattern, compensating transactions, two-phase commit, distributed transactions, payment orchestration, chaos testing\",\"publisher\":{\"@id\":\"https://arc.udokaam.dev/#organization\"},\"isPartOf\":{\"@id\":\"https://arc.udokaam.dev#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Arc\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Arc\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/decisions/0004-saga-over-two-phase-commit.md","siteName":"Arc","nav":{"global":null,"tabs":[{"tab":"Guide","pages":[{"title":"Guide","href":""}]},{"tab":"Architecture","groups":[{"group":"Foundations","icon":"layer-group","pages":[{"title":"Arc Architecture Overview: Six Contexts, One Deployable","sidebarTitle":"Overview","icon":"layer-group","href":"/architecture/overview"},{"title":"Why Every Monetary Value in Arc Is a Bigint Amount","sidebarTitle":"Money","icon":"calculator","href":"/architecture/money"},{"title":"Contexts, Events, and the Boundary That Fails Builds","sidebarTitle":"Events","icon":"inbox","href":"/architecture/contexts-and-events"},{"title":"Platform and Security: Signing, Idempotency, Secrets","sidebarTitle":"Platform","icon":"shield-halved","href":"/architecture/security"},{"title":"The Last Mile API: Partner Onboarding and Sandbox","sidebarTitle":"Partner platform","icon":"plug","href":"/architecture/partner-platform"}]},{"group":"The core","icon":"book-open","pages":[{"title":"The Arc Ledger: Double-Entry Accounting With No Tolerance","sidebarTitle":"Ledger","icon":"scale-balanced","href":"/architecture/ledger"},{"title":"The Chain Layer: One Interface, Five Different Physics","sidebarTitle":"Chain Layer","icon":"link","href":"/architecture/chain-layer"},{"title":"The Settlement Saga: Five Steps, Five Compensations","sidebarTitle":"Settlement Saga","icon":"rotate-left","href":"/architecture/settlement-saga"},{"title":"Risk and Compliance: A Blocking Gate on Money Movement","sidebarTitle":"Compliance","icon":"shield","href":"/architecture/compliance"},{"title":"Reconciliation: Balanced Books Are Not Correct Books","sidebarTitle":"Reconciliation","icon":"scale-unbalanced","href":"/architecture/reconciliation"}]},{"group":"Proof","icon":"flask","pages":[{"title":"What the Arc Test Suite Proves and How It Was Verified","sidebarTitle":"Testing","icon":"flask","href":"/architecture/testing"}]},{"group":"Flows","icon":"route","pages":[{"title":"Consumer Remittance: €1,000 From Munich to M-Pesa Kenya","sidebarTitle":"Consumer Flow","icon":"user","href":"/flows/consumer-remittance"},{"title":"Enterprise Payout: NGN Virtual Account to SEPA Instant","sidebarTitle":"Enterprise Flow","icon":"building","href":"/flows/enterprise-payout"},{"title":"Reversal: Four Compensating Journals, in Reverse Order","sidebarTitle":"Reversal","icon":"rotate-left","href":"/flows/reversal"}]},{"group":"Decisions","icon":"gavel","pages":[{"title":"Architecture Decision Records: How Arc Was Designed","sidebarTitle":"Overview","icon":"gavel","href":"/decisions/index"},{"title":"ADR 0001: Money as Integer Minor Units, Enforced by Lint","sidebarTitle":"ADR 0001","icon":"calculator","href":"/decisions/0001-money-as-integer-minor-units"},{"title":"ADR 0002: Modular Monolith Over Microservices, Enforced","sidebarTitle":"ADR 0002","icon":"cubes","href":"/decisions/0002-modular-monolith"},{"title":"ADR 0003: A Chain-Agnostic Driver With a Deterministic Simulator","sidebarTitle":"ADR 0003","description":"Why settlement talks to a driver interface rather than a chain SDK, and why the default implementation is a seeded simulator rather than a testnet.","icon":"link","href":"/decisions/0003-chain-abstraction"},{"title":"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit","sidebarTitle":"ADR 0004","icon":"diagram-project","href":"/decisions/0004-saga-over-two-phase-commit"},{"title":"ADR 0005: Idempotency Keys, and Why a Reused Key Is a Conflict","sidebarTitle":"ADR 0005","description":"Why retrying a payout returns the original response, why the same key with a different body is a 409 rather than a cache hit, and why signatures carry a nonce.","icon":"rotate-right","href":"/decisions/0005-idempotency-strategy"},{"title":"ADR 0006: A Transactional Outbox for At-Least-Once Delivery","sidebarTitle":"ADR 0006","icon":"inbox","href":"/decisions/0006-transactional-outbox"},{"title":"ADR 0007: Row-Level Tenancy With Environment-Prefixed Credentials","sidebarTitle":"ADR 0007","icon":"users-between-lines","href":"/decisions/0007-multi-tenancy-model"},{"title":"ADR 0008: Double-Entry Accounting, Enforced by the Database","sidebarTitle":"ADR 0008","icon":"scale-balanced","href":"/decisions/0008-double-entry-ledger"}]}]},{"tab":"IRL Scenarios","pages":[{"title":"IRL Scenarios","href":"/stories"}]},{"tab":"Practice","pages":[{"title":"Practice","href":"/practice"}]}]},"basePath":"","title":"ADR 0004: A Compensating Saga Rather Than Two-Phase Commit - Arc","buildId":"dpl_5tKr6cUUeuVJdEZ9JAEY3h4soMJ8","deploymentId":"dpl_5tKr6cUUeuVJdEZ9JAEY3h4soMJ8","dynamics":[],"chunks":[]}