import test from 'node:test'; import assert from 'node:assert/strict'; import { createAlertEngine } from '../src/core/alert-engine.mjs'; function createEngine() { return createAlertEngine({ activePair: 'nep141:btc.omft.near->nep141:eure.omft.near', priceStaleMs: 30_000, inventoryStaleMs: 30_000, fundingCreditPendingMs: 300_000, fundingStuckMs: 3_600_000, evaluationIntervalMs: 5_000, }); } test('alert engine raises and clears stale state transitions', () => { const engine = createEngine(); let transitions = engine.applyEvent('ref.market_price', { price_id: 'price-1', pair: 'nep141:btc.omft.near->nep141:eure.omft.near', eur_per_btc: '100000', btc_per_eure: '0.00001', observed_at: '2026-04-03T08:00:00.000Z', }, '2026-04-03T08:00:00.000Z'); assert.equal(transitions.length, 1); assert.equal(transitions[0].alert_code, 'inventory_snapshot_stale'); assert.equal(transitions[0].status, 'raised'); transitions = engine.applyEvent('state.intent_inventory', { inventory_id: 'inventory-1', account_id: 'solver.near', reconciliation_status: 'ok', spendable: { 'nep141:btc.omft.near': '1000' }, synced_at: '2026-04-03T08:00:00.000Z', }, '2026-04-03T08:00:00.000Z'); assert.equal(transitions.length, 1); assert.equal(transitions[0].alert_code, 'inventory_snapshot_stale'); assert.equal(transitions[0].status, 'cleared'); transitions = engine.evaluate('2026-04-03T08:00:31.000Z'); assert.equal(transitions.length, 2); assert.deepEqual( transitions.map((transition) => `${transition.alert_code}:${transition.status}`).sort(), [ 'inventory_snapshot_stale:raised', 'reference_price_stale:raised', ], ); transitions = engine.applyEvent('ref.market_price', { price_id: 'price-2', pair: 'nep141:btc.omft.near->nep141:eure.omft.near', eur_per_btc: '100100', btc_per_eure: '0.00000999', observed_at: '2026-04-03T08:00:32.000Z', }, '2026-04-03T08:00:32.000Z'); assert.equal(transitions.length, 1); assert.equal(transitions[0].alert_code, 'reference_price_stale'); assert.equal(transitions[0].status, 'cleared'); }); test('executor submission failure produces an alert event and clears on recovery', () => { const engine = createEngine(); engine.applyEvent('ref.market_price', { price_id: 'price-1', pair: 'nep141:btc.omft.near->nep141:eure.omft.near', eur_per_btc: '100000', btc_per_eure: '0.00001', observed_at: '2026-04-03T08:00:00.000Z', }, '2026-04-03T08:00:00.000Z'); engine.applyEvent('state.intent_inventory', { inventory_id: 'inventory-1', account_id: 'solver.near', reconciliation_status: 'ok', spendable: { 'nep141:btc.omft.near': '1000' }, synced_at: '2026-04-03T08:00:00.000Z', }, '2026-04-03T08:00:00.000Z'); let transitions = engine.applyEvent('exec.trade_result', { command_id: 'cmd-1', quote_id: 'quote-1', pair: 'nep141:btc.omft.near->nep141:eure.omft.near', status: 'failed', result_code: 'submission_failed', error: { message: 'relay timeout' }, }, '2026-04-03T08:00:10.000Z'); assert.equal(transitions.length, 1); assert.equal(transitions[0].alert_code, 'executor_submission_failed'); assert.equal(transitions[0].status, 'raised'); transitions = engine.applyEvent('exec.trade_result', { command_id: 'cmd-2', quote_id: 'quote-2', pair: 'nep141:btc.omft.near->nep141:eure.omft.near', status: 'submitted', result_code: 'quote_response_ok', }, '2026-04-03T08:00:20.000Z'); assert.equal(transitions.length, 1); assert.equal(transitions[0].alert_code, 'executor_submission_failed'); assert.equal(transitions[0].status, 'cleared'); });