All checks were successful
deploy / deploy (push) Successful in 58s
Proof: quote-response execution now uses verifierSaltCache.getCachedFreshSalt() only, rejects verifier_salt_unavailable before signing or relay when no fresh cached salt exists, preserves stale command expiry before salt lookup, exposes salt cache and executor queue-delay state in health/sentinel/dashboard surfaces, and is covered by targeted regression tests plus full npm test and dashboard build. Assumptions: the existing verifier salt freshness policy remains safe for cached signing use; fixed in-code queue-delay warning thresholds are sufficient for operator alerts without new latency env vars; no strategy selection, pricing, edge, notional, inventory, arming, signer, or pair enablement behavior changed. Still fake: venue-native terminal fill ids and fee-complete realized PnL remain unavailable; executor concurrency remains single-consumer; live post-deploy evidence still needs collection after repo-workflow deployment.
241 lines
7.1 KiB
JavaScript
241 lines
7.1 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import {
|
|
buildExecutorRuntimeAlerts,
|
|
buildMakerCompetitivenessRuntimeAlerts,
|
|
deriveServiceHealth,
|
|
shouldContainExecutorForAlerts,
|
|
shouldRaiseIngestPublishStale,
|
|
} from '../src/core/runtime-health.mjs';
|
|
|
|
test('publish stale does not raise before any matching quote exists', () => {
|
|
assert.equal(shouldRaiseIngestPublishStale({
|
|
lastMatchingQuoteAt: null,
|
|
lastPublishedAt: null,
|
|
matchingQuoteAgeMs: null,
|
|
publishedAgeMs: null,
|
|
publishStaleMs: 30_000,
|
|
}), false);
|
|
});
|
|
|
|
test('publish stale raises after a matching quote exists but no publish follows', () => {
|
|
assert.equal(shouldRaiseIngestPublishStale({
|
|
lastMatchingQuoteAt: '2026-04-08T20:45:00.000Z',
|
|
lastPublishedAt: null,
|
|
matchingQuoteAgeMs: 10_000,
|
|
publishedAgeMs: null,
|
|
publishStaleMs: 30_000,
|
|
}), true);
|
|
});
|
|
|
|
test('executor containment stays disabled for quote-stale-only conditions', () => {
|
|
assert.equal(shouldContainExecutorForAlerts([{
|
|
alert_code: 'near_intents_quotes_stale',
|
|
severity: 'critical',
|
|
}]), false);
|
|
});
|
|
|
|
test('executor containment stays disabled even for broken truth path alerts', () => {
|
|
assert.equal(shouldContainExecutorForAlerts([{
|
|
alert_code: 'near_intents_ingest_disconnected',
|
|
severity: 'critical',
|
|
}]), false);
|
|
assert.equal(shouldContainExecutorForAlerts([{
|
|
alert_code: 'near_intents_publish_stale',
|
|
severity: 'critical',
|
|
}]), false);
|
|
assert.equal(shouldContainExecutorForAlerts([{
|
|
alert_code: 'history_writer_stalled',
|
|
severity: 'critical',
|
|
}]), false);
|
|
});
|
|
|
|
test('armed service treats critical truth alerts for any active pair as critical', () => {
|
|
const health = deriveServiceHealth({
|
|
service: 'strategy-engine',
|
|
snapshot: {
|
|
reachable: true,
|
|
state: {
|
|
armed: true,
|
|
},
|
|
health: {
|
|
ok: true,
|
|
},
|
|
},
|
|
activePairs: [
|
|
'btc->eure',
|
|
'btc->usdc',
|
|
],
|
|
activeAlerts: [{
|
|
alert_code: 'reference_price_stale',
|
|
severity: 'critical',
|
|
service_scope: 'strategy-engine',
|
|
pair: 'btc->usdc',
|
|
}],
|
|
now: '2026-05-18T10:00:00.000Z',
|
|
});
|
|
|
|
assert.equal(health.status, 'critical');
|
|
assert.equal(health.label, 'armed on stale truth');
|
|
});
|
|
|
|
test('maker competitiveness alerts are pair-scoped for high quote-finished relay failure rate', () => {
|
|
const alerts = buildMakerCompetitivenessRuntimeAlerts({
|
|
makerCompetitiveness: {
|
|
generated_at: '2026-05-18T10:00:00.000Z',
|
|
groups: [
|
|
{
|
|
pair: 'nbtc->usdc',
|
|
direction: 'base_to_quote',
|
|
request_kind: 'exact_in',
|
|
result_code: 'submission_failed',
|
|
failure_category: 'quote_not_found_or_finished',
|
|
quote_age_bucket: '100-250ms',
|
|
notional_bucket: '5-10',
|
|
count: 4,
|
|
},
|
|
{
|
|
pair: 'nbtc->usdc',
|
|
direction: 'base_to_quote',
|
|
request_kind: 'exact_in',
|
|
result_code: 'quote_response_ok',
|
|
failure_category: null,
|
|
quote_age_bucket: '<100ms',
|
|
notional_bucket: '5-10',
|
|
count: 1,
|
|
accepted_count: 1,
|
|
},
|
|
{
|
|
pair: 'nbtc->eure',
|
|
result_code: 'quote_response_ok',
|
|
failure_category: null,
|
|
count: 8,
|
|
accepted_count: 8,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
assert.equal(alerts.length, 1);
|
|
assert.equal(alerts[0].alert_code, 'maker_quote_not_found_or_finished_rate_high');
|
|
assert.equal(alerts[0].service_scope, 'strategy-engine');
|
|
assert.equal(alerts[0].pair, 'nbtc->usdc');
|
|
assert.equal(alerts[0].details.quote_not_found_or_finished_count, 4);
|
|
assert.equal(alerts[0].details.quote_not_found_or_finished_rate, 0.8);
|
|
});
|
|
|
|
test('history writer retention pressure and stale rollups surface as runtime warnings', () => {
|
|
const pressure = deriveServiceHealth({
|
|
service: 'history-writer',
|
|
snapshot: {
|
|
reachable: true,
|
|
state: {
|
|
database_connectivity: true,
|
|
last_write_at: '2026-06-06T10:59:59.000Z',
|
|
retention_mode: 'pressure',
|
|
},
|
|
health: { ok: true },
|
|
},
|
|
now: '2026-06-06T11:00:00.000Z',
|
|
});
|
|
assert.equal(pressure.status, 'warning');
|
|
assert.equal(pressure.label, 'storage pressure');
|
|
|
|
const stale = deriveServiceHealth({
|
|
service: 'history-writer',
|
|
snapshot: {
|
|
reachable: true,
|
|
state: {
|
|
database_connectivity: true,
|
|
last_write_at: '2026-06-06T10:59:59.000Z',
|
|
retention_mode: 'blocked_rollup_stale',
|
|
},
|
|
health: { ok: true },
|
|
},
|
|
now: '2026-06-06T11:00:00.000Z',
|
|
});
|
|
assert.equal(stale.status, 'warning');
|
|
assert.equal(stale.label, 'rollup stale');
|
|
assert.ok(stale.reasons.some((reason) => /fail-closed/.test(reason)));
|
|
});
|
|
|
|
test('trade executor salt and queue state surface as runtime health warnings', () => {
|
|
const health = deriveServiceHealth({
|
|
service: 'trade-executor',
|
|
snapshot: {
|
|
reachable: true,
|
|
state: {
|
|
armed: true,
|
|
verifier_salt_cache: {
|
|
configured: true,
|
|
has_cached_salt: false,
|
|
salt_fresh: false,
|
|
},
|
|
executor_queue_delay: {
|
|
status: 'warning',
|
|
warning_reason: 'recent command_to_executor_ms max 1500ms exceeds 1000ms',
|
|
},
|
|
},
|
|
health: { ok: true },
|
|
},
|
|
now: '2026-06-12T10:00:00.000Z',
|
|
});
|
|
|
|
assert.equal(health.status, 'warning');
|
|
assert.ok(health.reasons.includes('verifier salt cache is stale or unavailable'));
|
|
assert.ok(health.reasons.includes('recent command_to_executor_ms max 1500ms exceeds 1000ms'));
|
|
});
|
|
|
|
test('executor runtime alerts cover stale salt, refresh failure, and queue delay', () => {
|
|
const alerts = buildExecutorRuntimeAlerts({
|
|
executor: {
|
|
reachable: true,
|
|
state: {
|
|
verifier_salt_cache: {
|
|
configured: true,
|
|
has_cached_salt: true,
|
|
salt_fresh: false,
|
|
salt_age_ms: 750,
|
|
max_age_ms: 500,
|
|
refresh_in_flight: false,
|
|
last_refresh_started_at: '2026-06-12T09:59:59.000Z',
|
|
last_refresh_completed_at: '2026-06-12T09:59:59.100Z',
|
|
last_refresh_duration_ms: 100,
|
|
last_refresh_error: {
|
|
name: 'Error',
|
|
message: 'rpc unavailable',
|
|
},
|
|
},
|
|
executor_queue_delay: {
|
|
status: 'critical',
|
|
latest_ms: 200,
|
|
max_ms: 7_500,
|
|
p90_ms: 5_200,
|
|
p99_ms: 7_500,
|
|
sample_count: 10,
|
|
latest_command_id: 'cmd-1',
|
|
latest_quote_id: 'quote-1',
|
|
},
|
|
},
|
|
},
|
|
thresholds: {
|
|
executorQueueDelayWarningMs: 1_000,
|
|
executorQueueDelayCriticalMs: 5_000,
|
|
},
|
|
pair: 'nbtc->eure',
|
|
});
|
|
|
|
assert.deepEqual(
|
|
alerts.map((alert) => alert.alert_code),
|
|
[
|
|
'trade_executor_verifier_salt_unavailable',
|
|
'trade_executor_verifier_salt_refresh_failed',
|
|
'trade_executor_command_queue_delay_high',
|
|
],
|
|
);
|
|
assert.equal(alerts[0].severity, 'warning');
|
|
assert.equal(alerts[1].details.last_refresh_error.message, 'rpc unavailable');
|
|
assert.equal(alerts[2].severity, 'critical');
|
|
assert.equal(alerts[2].details.p90_ms, 5_200);
|
|
});
|