import test from 'node:test'; import assert from 'node:assert/strict'; import { buildInitialMakerTiming, extendMakerTiming, quoteAgeMsAt, } from '../src/core/maker-timing.mjs'; import { buildMakerCompetitivenessSummary } from '../src/core/maker-competitiveness.mjs'; import { classifyRelaySubmissionFailure } from '../src/core/relay-failure-classification.mjs'; test('maker timing computes waterfall fields and marks clock skew unavailable', () => { const initial = buildInitialMakerTiming({ quoteReceivedAt: '2026-05-18T10:00:00.000Z', quoteNormalizedAt: '2026-05-18T10:00:00.010Z', quotePublishedAt: '2026-05-18T10:00:00.020Z', }); const timing = extendMakerTiming(initial, { strategy_received_at: '2026-05-18T10:00:00.030Z', strategy_decided_at: '2026-05-18T10:00:00.040Z', command_published_at: '2026-05-18T10:00:00.050Z', executor_received_at: '2026-05-18T10:00:00.075Z', relay_result_at: '2026-05-18T10:00:00.140Z', outcome_observed_at: '2026-05-18T10:00:02.000Z', }); assert.equal(timing.quote_to_decision_ms, 40); assert.equal(timing.decision_to_command_ms, 10); assert.equal(timing.command_to_executor_ms, 25); assert.equal(timing.executor_to_relay_result_ms, 65); assert.equal(timing.quote_to_relay_result_ms, 140); assert.equal(timing.quote_to_outcome_ms, 2000); assert.equal(quoteAgeMsAt(timing, '2026-05-18T10:00:00.050Z'), 50); const skewed = extendMakerTiming(initial, { strategy_decided_at: '2026-05-18T09:59:59.999Z', }); assert.equal(skewed.quote_to_decision_ms, null); assert.equal(skewed.unavailable_reasons.quote_to_decision_ms, 'clock_skew_or_negative_duration'); }); test('relay submission failure classifier preserves specific already-finished category', () => { assert.equal( classifyRelaySubmissionFailure(new Error('quote not found or already finished')), 'quote_not_found_or_finished', ); assert.equal( classifyRelaySubmissionFailure({ error_message: 'quote not found or already finished' }), 'quote_not_found_or_finished', ); assert.equal( classifyRelaySubmissionFailure(new Error('quote_response timed out')), 'relay_timeout', ); assert.equal( classifyRelaySubmissionFailure(new Error('Socket not connected')), 'relay_disconnected', ); assert.equal( classifyRelaySubmissionFailure(new Error('current_salt unavailable')), 'salt_unavailable', ); }); test('maker competitiveness aggregates pair, direction, request kind, result, failure, age, notional, and outcome', () => { const nbtc = 'nep141:nbtc.bridge.near'; const eure = 'nep141:eure.omft.near'; const usdc = 'nep141:eth-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.omft.near'; const baseTiming = buildInitialMakerTiming({ quoteReceivedAt: '2026-05-18T10:00:00.000Z', }); const summary = buildMakerCompetitivenessSummary({ generatedAt: '2026-05-18T10:01:00.000Z', lifecycleRows: [ { quote_id: 'quote-eure-ok', pair: `${nbtc}->${eure}`, direction: 'base_to_quote', request_kind: 'exact_in', edge_bps: '49', notional: '5', notional_symbol: 'EURe', outcome_status: 'submitted', execution_result_at: '2026-05-18T10:00:00.080Z', maker_timing: extendMakerTiming(baseTiming, { strategy_decided_at: '2026-05-18T10:00:00.010Z', command_published_at: '2026-05-18T10:00:00.020Z', executor_received_at: '2026-05-18T10:00:00.030Z', relay_result_at: '2026-05-18T10:00:00.080Z', }), execution: { status: 'submitted', result_code: 'quote_response_ok', timing: { current_salt_source: 'cache' }, }, }, { quote_id: 'quote-usdc-failed', pair: `${nbtc}->${usdc}`, direction: 'base_to_quote', request_kind: 'exact_in', edge_bps: '20', notional: '8', notional_symbol: 'USDC', execution_result_at: '2026-05-18T10:00:00.400Z', maker_timing: extendMakerTiming(baseTiming, { strategy_decided_at: '2026-05-18T10:00:00.100Z', command_published_at: '2026-05-18T10:00:00.150Z', executor_received_at: '2026-05-18T10:00:00.250Z', relay_result_at: '2026-05-18T10:00:00.400Z', }), execution: { status: 'failed', result_code: 'submission_failed', failure_category: 'quote_not_found_or_finished', error_message: 'quote not found or already finished', timing: { current_salt_source: 'cache' }, }, }, { quote_id: 'quote-usdc-skip', pair: `${nbtc}->${usdc}`, direction: 'base_to_quote', request_kind: 'exact_in', edge_bps: '20', notional: '12', notional_symbol: 'USDC', maker_timing: extendMakerTiming(baseTiming, { strategy_decided_at: '2026-05-18T10:00:00.600Z', }), decision: { decision: 'blocked', decision_reason: 'maker_quote_too_old', response_policy: { measured_quote_age_ms: 600, max_quote_age_ms: 250, }, }, }, ], }); assert.equal(summary.total.count, 3); assert.equal(summary.total.accepted_count, 1); assert.equal(summary.total.relay_failed_count, 1); assert.equal(summary.total.policy_skip_count, 1); assert.equal(summary.total.quote_not_found_or_finished_count, 1); assert.ok(summary.groups.some((group) => ( group.pair === `${nbtc}->${usdc}` && group.request_kind === 'exact_in' && group.edge_bps === '20' && group.result_code === 'submission_failed' && group.failure_category === 'quote_not_found_or_finished' && group.quote_age_bucket === '250-500ms' && group.notional_bucket === '5-25 USDC' && group.outcome_status === 'relay_failed' ))); assert.ok(summary.age_buckets.some((bucket) => ( bucket.pair === `${nbtc}->${usdc}` && bucket.quote_age_bucket === '500-1000ms' && bucket.outcome_status === 'policy_skip' ))); assert.equal(summary.latest_errors[0].error_message, 'quote not found or already finished'); assert.equal(summary.policy_skips[0].reason_code, 'maker_quote_too_old'); }); test('maker competitiveness keeps edge bps as a grouping dimension', () => { const nbtc = 'nep141:nbtc.bridge.near'; const usdc = 'nep141:usdc.omft.near'; const base = { pair: `${nbtc}->${usdc}`, direction: 'base_to_quote', request_kind: 'exact_in', notional: '8', notional_symbol: 'USDC', outcome_status: 'not_filled', execution: { status: 'submitted', result_code: 'quote_response_ok', }, }; const summary = buildMakerCompetitivenessSummary({ lifecycleRows: [ { ...base, quote_id: 'quote-edge-1', edge_bps: '1' }, { ...base, quote_id: 'quote-edge-20', edge_bps: '20' }, ], }); const edgeGroups = summary.groups.filter((group) => group.pair === `${nbtc}->${usdc}`); assert.equal(edgeGroups.length, 2); assert.deepEqual(edgeGroups.map((group) => group.edge_bps).sort(), ['1', '20']); });