prod -> main back-merge: the billing cluster
prod -> main back-merge: the billing cluster
Ask of the reviewer: confirm the one claim this rests on — that main's settlement outbox preserves every billing behaviour prod writes inline. If that holds, all 36 conflicted billing hunks resolve to main, and nothing prod has is lost. Evidence for each is below; every claim is checkable with the command next to it.
Branch: backmerge/billing-review (origin/main + git merge origin/prod).
ours = main, theirs = prod. 51 files conflict; 9 are billing (36 hunks).
Why these conflict at all
Prod was maintained by cherry-pick for months, so it never received main's multi-region work. The whole billing cluster conflicts on one axis:
| prod | main | |
|---|---|---|
| period accrual + credit debit | inline, in the writer's regional transaction | recorded as outbox rows, shipped to the global DB |
| where the money tables live | same database as the writer | GLOBAL (db/ownership.ts) — a different database outside the home region |
| exactly-once | the single transaction | billing_settlement_claims insert-or-skip |
Main did not drop prod's logic; it relocated it. One transaction cannot
span two databases, so the writer records what it owes regionally and
billingSettlementShip.ts applies it globally.
The load-bearing claim, and its proof
Main's shipper reproduces prod's inline block statement for statement:
| prod (inline) | main (billingSettlementShip.ts) | same? |
|---|---|---|
INSERT INTO billing_usage_period_org … ON CONFLICT DO UPDATE SET accrued_micros + EXCLUDED… | same statement, same ON CONFLICT | yes |
INSERT INTO billing_usage_period_user … | same | yes |
debitCredits(tx, org, micros, meta, \cycle:${org}:${sampledAt}:b${batches}:p${period}`)` | useCredits({ idempotencyKey: row.key }) where row.key is that same template, byte for byte | yes |
const debited = applied ? micros : 0 | if (!res.applied) return { debitedMicros: 0 } | yes |
UPDATE billing_usage_period_org SET debited_micros = debited_micros + ${debited} | if (row.bump_debited) UPDATE … debited_micros + ${micros} | yes |
batchDebited += debited | shipKeys() returns debitedMicros | yes |
The byte-identical debit key is the point: an interval in flight at deploy
still dedups against a ledger row the old code wrote. Main states this in its
own comment (billingSettlementShip.ts:14-17).
git show origin/main:apps/api/src/billingSettlementShip.ts | sed -n '138,170p'Ordering is preserved too: accruals ship before the debit, and shipKeys stops
at the first failure, so a settlement's rows land together or wait together.
Per-file verdict
| file | hunks | axis | verdict |
|---|---|---|---|
billing.ts | 6 | imports; sampler cursor; sampler accrual/debit | main |
billingFinalize.ts | 7 | outbox vs inline | main (+2 fixes prod lacks) |
requestMeter.ts | 4 | outbox vs inline | main |
billing.sampler.test.ts | 3 | test consolidation | main (superset, see below) |
billingSettleChunk.int.test.ts | 5 | outbox vs inline | main (superset) |
requestSettlement.int.test.ts | 3 | outbox vs inline | main (stronger) |
billingSamplerFairness.int.test.ts | 5 | outbox vs inline | main (superset) |
requestMeter.concurrency.int.test.ts | 2 | outbox vs inline | main (superset) |
requestMeter.load.int.test.ts | 1 | outbox vs inline | main (superset) |
Two hunks that are not the outbox axis — read these
billing.ts hunks 2 and 3, readSampleCursor / writeSampleCursor:
- prod:
SELECT … FROM app_config/INSERT INTO app_config - main:
region_state
This is required, not cosmetic. app_config is a GLOBAL table — outside the
home region it is a read-only copy, so prod's version cannot write the cursor
from us-east. The sampler cursor is this region's own rotation state.
On a single-region deployment the two behave identically, so taking main is
also a no-op for today's prod.
Main carries billing fixes prod never got
Found while resolving billingFinalize.ts — these are reasons to take main
beyond mere equivalence:
- ghost-sandbox refusal — finalizing a sandbox row that no longer exists.
open_vercutover fence.
Test coverage: nothing is lost
The one place prod had test names main lacks:
- prod:
no runtime claims a billed unit that nothing computes - prod:
the microVM does not claim per-request billing - main:
the registry claims only units that are actually implemented
Main consolidated the two into one and kept both assertions verbatim
(expect(RUNTIMES.cell.resources.billed).toContain('requests') and
expect(RUNTIMES.microvm.resources.billed).not.toContain('requests')), plus a
BILLED_UNITS_IMPLEMENTED loop prod does not have.
Every other billing test file is larger on main (183/178, 234/193, 43/41,
72/68, 278/230 lines). Two diffs appear to show prod-only assertions; both are
diff-alignment noise — the lines exist on main (billingSettleChunk.int.test.ts
206-210, 229). requestSettlement.int.test.ts is the clearest case: prod
asserts only that a replay changes nothing; main asserts usage is unchanged
and ledger + 1, balance - 21 — i.e. the replay ships the money exactly
once. Strictly stronger.
git show origin/main:apps/api/src/requestSettlement.int.test.ts | sed -n '161,174p'Checked and found equal — no action
- parked-time fix (
parkedFloorMsx2,billable_sincex3): identical counts on both. - graceful-shutdown flush: prod reverted it (
3059c0a0revertingc213fc29). Absent from main too —requestMeter.shutdown.test.tsexists on neither, andserver.tshas 0 shutdown-flush references on both. Taking main does not reintroduce it. sandboxStopAdmission.ts: main has the one-statement CTE claim (#1111); prod the older 5-round-trip transaction. No prod fix at risk.- No prod-only billing source file exists. Main's file set is a superset:
comm -13 <(git ls-tree -r --name-only origin/main -- apps/api/src | grep -iE 'billing|requestMeter|credits' | sort) \ <(git ls-tree -r --name-only origin/prod -- apps/api/src | grep -iE 'billing|requestMeter|credits' | sort) # (empty)
What the reviewer should actually do
- Read the six-row proof table above and spot-check the debit-key row — it is the only thing standing between "dedups correctly" and a double charge.
- Confirm
region_statevsapp_configis the intended ownership call. - Say yes, and the 36 hunks resolve mechanically to main.
The remaining 42 non-billing conflicts are tracked separately.
Explicitly NOT done here
Nothing is pushed to prod. Prod still holds fixes main has never seen; this
document covers only whether the billing subset is safe to resolve to main.
Reproducing the resolution
The resolution is mechanical — nothing was hand-edited. On a fresh
origin/main + git merge origin/prod:
for f in billing.ts billing.sampler.test.ts billingFinalize.ts \
billingSamplerFairness.int.test.ts billingSettleChunk.int.test.ts \
requestMeter.concurrency.int.test.ts requestMeter.load.int.test.ts \
requestMeter.ts requestSettlement.int.test.ts; do
git checkout --ours -- "apps/api/src/$f" && git add "apps/api/src/$f"
doneVerified afterwards: all 9 files are byte-identical to origin/main and carry
zero conflict markers; the 42 remaining conflicts are non-billing.