unrip/test/quote-lifecycle-statistics.test.mjs
philipp 503a69e71c
All checks were successful
deploy / deploy (push) Successful in 59s
Retain quote lifecycle statistics across pruning
Proof: added persisted quote_lifecycle_stat_subjects snapshots, refreshed statistics from retained per-quote subjects, preserved completed/attributed execution evidence during lifecycle retention, and wired successful lifecycle evidence into the dashboard trade funnel; verified with targeted lifecycle/dashboard tests, full npm test, and operator dashboard bundle build.

Assumptions: detailed successful trade rows already deleted by prior retention cannot be reconstructed from aggregate rollups without faking quote-level settlement evidence; the new subject table starts preserving surviving and future quote evidence after deployment.

Still fake: fee-aware realized PnL and venue-native fill truth beyond retained settlement/inventory evidence remain out of scope; already-pruned detailed success rows remain unrecoverable.
2026-06-13 14:04:20 +02:00

128 lines
4.6 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {
buildQuoteLifecycleStatistics,
classifyQuoteLifecycleStatisticsBucket,
quoteLifecycleStatisticWindow,
} from '../src/core/quote-lifecycle-statistics.mjs';
test('quote lifecycle statistics classify states without upgrading submitted-only rows to success', () => {
assert.equal(classifyQuoteLifecycleStatisticsBucket({
lifecycle_state: 'submitted',
execution: { status: 'submitted', result_code: 'quote_response_ok' },
}), 'submitted_no_reply');
assert.equal(classifyQuoteLifecycleStatisticsBucket({
lifecycle_state: 'failed',
execution: { status: 'failed', failure_category: 'quote_not_found_or_finished' },
}), 'submission_failed');
assert.equal(classifyQuoteLifecycleStatisticsBucket({
lifecycle_state: 'command_emitted',
}), 'awaiting_executor');
assert.equal(classifyQuoteLifecycleStatisticsBucket({
lifecycle_state: 'completed',
outcome_status: 'completed',
has_settlement_evidence: true,
}), 'success');
});
test('quote lifecycle statistics can aggregate retained quote subject buckets', () => {
const rows = buildQuoteLifecycleStatistics({
computedAt: '2026-06-12T14:20:00.000Z',
lifecycleRows: [{
quote_id: 'quote-retained-success',
quote_activity_at: '2026-06-12T14:11:01.000Z',
latest_stage_at: '2026-06-12T14:11:10.000Z',
statistics_bucket: 'success',
}],
});
const allTime = rows.find((row) => row.grain === 'all_time');
const fiveMinute = rows.find((row) => (
row.grain === 'five_minute'
&& row.window_start === '2026-06-12T14:10:00.000Z'
));
assert.equal(allTime.quote_count, 1);
assert.equal(allTime.bucket_counts.success, 1);
assert.equal(fiveMinute.quote_count, 1);
assert.equal(fiveMinute.bucket_counts.success, 1);
});
test('quote lifecycle statistics use UTC grain boundaries with Monday UTC weeks', () => {
assert.deepEqual(quoteLifecycleStatisticWindow('2026-06-12T17:34:44.123Z', 'five_minute'), {
grain: 'five_minute',
window_start: '2026-06-12T17:30:00.000Z',
window_end: '2026-06-12T17:35:00.000Z',
});
assert.deepEqual(quoteLifecycleStatisticWindow('2026-06-14T23:59:00.000Z', 'week'), {
grain: 'week',
window_start: '2026-06-08T00:00:00.000Z',
window_end: '2026-06-15T00:00:00.000Z',
});
assert.deepEqual(quoteLifecycleStatisticWindow('2026-06-01T00:00:00.000Z', 'month'), {
grain: 'month',
window_start: '2026-06-01T00:00:00.000Z',
window_end: '2026-07-01T00:00:00.000Z',
});
});
test('quote lifecycle statistics dedupe quotes and refresh later results in the original quote window', () => {
const rows = [
{
quote_id: 'quote-follow',
lifecycle_state: 'command_emitted',
quote_activity_at: '2026-06-12T17:31:01.000Z',
latest_stage_at: '2026-06-12T17:31:03.000Z',
},
{
quote_id: 'quote-follow',
lifecycle_state: 'failed',
quote_activity_at: '2026-06-12T17:31:01.000Z',
latest_stage_at: '2026-06-12T17:36:10.000Z',
execution: {
status: 'failed',
failure_category: 'quote_not_found_or_finished',
},
},
];
const statistics = buildQuoteLifecycleStatistics({
lifecycleRows: rows,
computedAt: '2026-06-12T17:40:00.000Z',
});
const allTime = statistics.find((row) => row.grain === 'all_time');
const fiveMinute = statistics.find((row) => (
row.grain === 'five_minute'
&& row.window_start === '2026-06-12T17:30:00.000Z'
));
const laterFiveMinute = statistics.find((row) => (
row.grain === 'five_minute'
&& row.window_start === '2026-06-12T17:35:00.000Z'
));
assert.equal(allTime.quote_count, 1);
assert.equal(allTime.bucket_counts.submission_failed, 1);
assert.equal(allTime.bucket_counts.awaiting_executor, 0);
assert.equal(fiveMinute.quote_count, 1);
assert.equal(fiveMinute.bucket_counts.submission_failed, 1);
assert.equal(laterFiveMinute, undefined);
});
test('quote lifecycle statistics preserve missing identifiers as unavailable evidence', () => {
const statistics = buildQuoteLifecycleStatistics({
lifecycleRows: [{
quote_id: null,
lifecycle_state: 'observed',
quote_activity_at: '2026-06-12T17:31:01.000Z',
}],
computedAt: '2026-06-12T17:40:00.000Z',
});
const allTime = statistics.find((row) => row.grain === 'all_time');
const fiveMinute = statistics.find((row) => row.grain === 'five_minute');
assert.equal(allTime.quote_count, 0);
assert.equal(allTime.missing_identifier_count, 1);
assert.equal(allTime.bucket_counts.unavailable, 1);
assert.equal(fiveMinute.quote_count, 0);
assert.equal(fiveMinute.missing_identifier_count, 1);
});