All checks were successful
deploy / deploy (push) Successful in 46s
Proof: quote-to-relay maker timing now propagates through ingest, normalized quotes, strategy decisions, commands, executor results, quote outcomes, lifecycle rows, dashboard summaries, and runtime alerts; relay failures preserve original text while classifying quote_not_found_or_finished; targeted tests, full npm test, and operator dashboard build passed before commit. Assumptions: response-age policy stays disabled by default and is only activated through DB-backed pair strategy config after operators review timing evidence; unrelated pre-existing dirty worktree files were left unstaged. Still fake: relay acceptance is not settlement or realized PnL; live policy thresholds still require post-deploy evidence before enabling skips for production pairs.
161 lines
6 KiB
JavaScript
161 lines
6 KiB
JavaScript
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',
|
|
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',
|
|
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',
|
|
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.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');
|
|
});
|