All checks were successful
deploy / deploy (push) Successful in 47s
Proof: History-writer now writes routed event batches with one bulk insert per table, preserving decision and normalized quote history while reducing Kafka lag that delayed durable strategy decision rows. Assumptions: Kafka message order within a topic partition remains sufficient for durability; environment status events keep their dedicated dedupe path; this change does not alter strategy, edge, notional, inventory, arming, or relay submission behavior. Still fake: Venue-native terminal fill ids and fee-complete realized PnL remain unavailable; historical decision rows can still lag until the deployed batch writer drains existing backlog.
114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import { buildInventorySnapshot } from '../src/core/inventory.mjs';
|
|
import { routeHistoryRecord } from '../src/core/history-records.mjs';
|
|
import { insertHistoryEvents } from '../src/lib/postgres.mjs';
|
|
|
|
test('inventory snapshot keeps pending funding out of spendable balances', () => {
|
|
const snapshot = buildInventorySnapshot({
|
|
accountId: 'solver.near',
|
|
balances: {
|
|
'nep141:btc.omft.near': '1000',
|
|
'nep141:eure.omft.near': '2000',
|
|
},
|
|
recentDeposits: [
|
|
{
|
|
asset_id: 'nep141:eure.omft.near',
|
|
amount: '300',
|
|
status: 'PENDING',
|
|
},
|
|
],
|
|
trackedWithdrawals: [
|
|
{
|
|
withdrawal_hash: 'wd-1',
|
|
asset_id: 'nep141:btc.omft.near',
|
|
amount: '25',
|
|
status: 'PENDING',
|
|
},
|
|
],
|
|
assetRegistry: new Map([
|
|
['nep141:btc.omft.near', { decimals: 8 }],
|
|
['nep141:eure.omft.near', { decimals: 18 }],
|
|
]),
|
|
observedAt: '2026-04-02T10:00:00.000Z',
|
|
});
|
|
|
|
assert.equal(snapshot.spendable['nep141:eure.omft.near'], '2000');
|
|
assert.equal(snapshot.pending_inbound['nep141:eure.omft.near'], '300');
|
|
assert.equal(snapshot.pending_outbound['nep141:btc.omft.near'], '25');
|
|
});
|
|
|
|
test('history writer routes decision events into the decision table family', () => {
|
|
const routed = routeHistoryRecord({
|
|
topic: 'decision.trade_decision',
|
|
event: {
|
|
event_id: 'evt-1',
|
|
event_type: 'trade_decision',
|
|
venue: 'near-intents',
|
|
schema_version: 1,
|
|
ingested_at: '2026-04-02T10:00:00.000Z',
|
|
payload: {
|
|
decision_id: 'decision-1',
|
|
quote_id: 'quote-1',
|
|
pair: 'a->b',
|
|
direction: 'btc_to_eure',
|
|
decision: 'rejected',
|
|
decision_reason: 'strategy_disarmed',
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.equal(routed.table, 'trade_decisions');
|
|
assert.equal(routed.record.decision_key, 'decision-1');
|
|
assert.equal(routed.record.quote_id, 'quote-1');
|
|
});
|
|
|
|
test('bulk history insert writes multiple routed events in one table statement', async () => {
|
|
const queries = [];
|
|
const pool = {
|
|
async query(sql, params) {
|
|
queries.push({ sql, params });
|
|
return {
|
|
rows: [
|
|
{ event_id: params[0] },
|
|
{ event_id: params[12] },
|
|
],
|
|
rowCount: 2,
|
|
};
|
|
},
|
|
};
|
|
|
|
const result = await insertHistoryEvents(pool, [
|
|
{
|
|
table: 'trade_decisions',
|
|
topic: 'decision.trade_decision',
|
|
event: historyEvent('evt-1', { decision_id: 'decision-1', quote_id: 'quote-1' }),
|
|
record: { quote_id: 'quote-1', pair: 'a->b', decision_key: 'decision-1' },
|
|
},
|
|
{
|
|
table: 'trade_decisions',
|
|
topic: 'decision.trade_decision',
|
|
event: historyEvent('evt-2', { decision_id: 'decision-2', quote_id: 'quote-2' }),
|
|
record: { quote_id: 'quote-2', pair: 'a->b', decision_key: 'decision-2' },
|
|
},
|
|
]);
|
|
|
|
assert.equal(queries.length, 1);
|
|
assert.match(queries[0].sql, /INSERT INTO trade_decisions/);
|
|
assert.match(queries[0].sql, /RETURNING event_id/);
|
|
assert.equal(queries[0].params.length, 24);
|
|
assert.deepEqual([...result.insertedEventIds].sort(), ['evt-1', 'evt-2']);
|
|
});
|
|
|
|
function historyEvent(eventId, payload) {
|
|
return {
|
|
event_id: eventId,
|
|
event_type: 'trade_decision',
|
|
venue: 'near-intents',
|
|
source: 'strategy-engine',
|
|
observed_at: '2026-04-02T10:00:00.000Z',
|
|
ingested_at: '2026-04-02T10:00:00.001Z',
|
|
payload,
|
|
};
|
|
}
|