unrip/test/inventory-and-history.test.mjs
philipp d9e7d570f4
All checks were successful
deploy / deploy (push) Successful in 1m13s
Bound raw quote retention drain
Proof: Raw NEAR Intents quote retention now keeps only a 30 minute raw firehose window and drains up to 10M stale unlinked raw rows per pass. Targeted raw retention tests, full npm test, and operator dashboard bundle build pass.

Assumptions: raw quote firehose rows are debug evidence, while normalized quote demand, decisions, commands, executor results, outcomes, inventory, pricing, and DB config remain the durable trading evidence.

Still fake: venue-native terminal fill ids and fee-complete realized PnL remain unavailable; raw quote firehose rows truncated during emergency recovery are intentionally no longer readable.
2026-05-24 14:59:58 +02:00

170 lines
5.3 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, pruneRawNearIntentsQuoteHistory } 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']);
});
test('raw quote retention preserves rows linked to maker lifecycle evidence', async () => {
const queries = [];
const pool = {
async query(sql, params) {
queries.push({ sql, params });
return { rows: [], rowCount: 42 };
},
};
const result = await pruneRawNearIntentsQuoteHistory(pool, {
now: '2026-05-21T12:00:00.000Z',
retainRecentMs: 6 * 60 * 60 * 1000,
batchSize: 123,
});
assert.equal(result.deletedCount, 42);
assert.equal(result.cutoff, '2026-05-21T06:00:00.000Z');
assert.equal(result.batchSize, 123);
assert.equal(queries.length, 1);
assert.match(queries[0].sql, /DELETE FROM raw_near_intents_quotes/);
assert.match(queries[0].sql, /trade_decisions/);
assert.match(queries[0].sql, /execute_trade_commands/);
assert.match(queries[0].sql, /trade_execution_results/);
assert.match(queries[0].sql, /quote_outcome_attributions/);
assert.deepEqual(queries[0].params, ['2026-05-21T06:00:00.000Z', 123]);
});
test('raw quote retention drains multiple bounded batches when firehose backlog exceeds one batch', async () => {
const rowCounts = [500_000, 500_000, 12];
const queries = [];
const pool = {
async query(sql, params) {
queries.push({ sql, params });
return { rows: [], rowCount: rowCounts.shift() ?? 0 };
},
};
const result = await pruneRawNearIntentsQuoteHistory(pool, {
now: '2026-05-21T12:00:00.000Z',
retainRecentMs: 30 * 60 * 1000,
batchSize: 500_000,
maxBatches: 20,
});
assert.equal(result.deletedCount, 1_000_012);
assert.equal(result.cutoff, '2026-05-21T11:30:00.000Z');
assert.equal(result.batchSize, 500_000);
assert.equal(result.maxBatches, 20);
assert.equal(result.batches, 3);
assert.equal(queries.length, 3);
for (const query of queries) {
assert.match(query.sql, /DELETE FROM raw_near_intents_quotes/);
assert.deepEqual(query.params, ['2026-05-21T11:30:00.000Z', 500_000]);
}
});
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,
};
}