Skip to content

Commit e022b18

Browse files
committed
fix(ledger): drop bundles.arb_id FK to remove cross-process write race
The Rust engine and Go executor each own one half of the trade-ledger write surface and both run fire-and-forget through their own bounded mpsc → writer task. There is no cross-process ordering between Rust's 'ARB PUBLISHED → insert_arb' and Go's 'bundle signed → insert_bundle'; under load the Go bundle insert lands first and the immediate FK check fails. Self-review flagged this as CRIT 2 — it would surface as a steady stream of bundle drops on every busy block and mask real ledger health. Drops bundles_arb_id_fkey via an idempotent migration so both writers can race freely. Trade-off: a transient Rust connection blip can produce an orphan bundle row; that is already metered as aether_ledger_writes_total{op="insert_arb",result="err"}, and downstream LEFT JOIN queries treat the NULL arb side as informative. Comment in the migration spells out the future path (coordinator or reconciliation worker) for re-adding the FK once cross-process ordering exists. Refs PR #122 self-review (CRIT 2).
1 parent d542edf commit e022b18

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
-- Trade ledger — drop bundles.arb_id → arbs(arb_id) foreign key.
2+
--
3+
-- Why: the Rust engine writes `arbs` rows and the Go executor writes
4+
-- `bundles` rows independently, both fire-and-forget through their own
5+
-- bounded mpsc → writer task. There is no cross-process ordering guarantee
6+
-- between "ARB PUBLISHED → insert_arb" on the Rust side and "bundle signed
7+
-- + sent → insert_bundle" on the Go side; under load the Go bundle insert
8+
-- can land at Postgres before the Rust arb insert, and the FK fires
9+
-- immediately on row INSERT (Postgres FK checks are not deferred by
10+
-- default). Result: a measurable fraction of bundle rows would be dropped
11+
-- with `aether_ledger_writes_total{op="insert_bundle",result="err"}` on
12+
-- every busy block, masking real ledger health.
13+
--
14+
-- Trade-off: an `arbs` row may briefly fail to land (Rust connection
15+
-- blip), leaving an orphan bundle. Acceptable because:
16+
-- - both sides drop on failure with a counter, so orphans surface as
17+
-- `aether_ledger_writes_total{op="insert_arb",result="err"}` anyway,
18+
-- - downstream queries already do LEFT JOIN arbs ↔ bundles when both
19+
-- sides are persisted, NULL on the arb side is informative.
20+
--
21+
-- Future: re-add the FK once a coordinator (e.g. Rust writes first and
22+
-- signals Go via gRPC ack) provides ordering, or add a backfilling
23+
-- reconciliation worker that re-runs the missing arb inserts.
24+
--
25+
-- The constraint is dropped IF EXISTS so the migration is idempotent on a
26+
-- partially-applied database.
27+
28+
ALTER TABLE bundles
29+
DROP CONSTRAINT IF EXISTS bundles_arb_id_fkey;

0 commit comments

Comments
 (0)