-
Lifecycle truth
-
Recent quote decisions and execution evidence
+
Why quotes are not trades
+
Recent quote outcomes and blockers
- Strategy rejection, executor blocking, submission failure, and submission success are separated. Submission never implies trade completion or realized asset movement.
+ Each row answers why the quote was filtered, rejected, blocked, submitted without outcome, failed, not filled, or completed. Submission still never means asset movement.
diff --git a/test/operator-dashboard.test.mjs b/test/operator-dashboard.test.mjs
index cf396b1..66f6988 100644
--- a/test/operator-dashboard.test.mjs
+++ b/test/operator-dashboard.test.mjs
@@ -584,9 +584,44 @@ test('bootstrap normalizes actionable decision vocabulary before exposing it to
assert.equal(bootstrap.funds.submission_ledger.items[0].decision_reason, 'strategy_approved');
assert.equal(bootstrap.strategy.strategy_state.recent_decisions[0].decision, 'approved');
assert.equal(bootstrap.strategy.strategy_state.recent_lifecycle_rows[0].reason_code, 'quote_response_ok');
+ assert.equal(bootstrap.strategy.strategy_state.trade_funnel.successful_trade_count, 0);
+ assert.equal(bootstrap.strategy.strategy_state.trade_funnel.unresolved_submission_count, 1);
+ assert.equal(bootstrap.strategy.strategy_state.trade_funnel.counts.submitted, 1);
+ assert.match(bootstrap.strategy.strategy_state.trade_funnel.caveat, /No quote currently has linked terminal outcome/);
assert.doesNotMatch(JSON.stringify(bootstrap), /Actionable/);
});
+test('completed lifecycle evidence is the only source of successful trade rows', () => {
+ const rows = deriveQuoteLifecycleRows({
+ recentExecutionResults: [
+ {
+ command_id: 'cmd-submitted',
+ quote_id: 'quote-submitted',
+ result_at: '2026-04-09T09:00:00.000Z',
+ status: 'submitted',
+ result_code: 'quote_response_ok',
+ },
+ {
+ command_id: 'cmd-completed',
+ quote_id: 'quote-completed',
+ result_at: '2026-04-09T09:01:00.000Z',
+ status: 'submitted',
+ result_code: 'quote_response_ok',
+ outcome_status: 'completed',
+ outcome_reason: 'settled',
+ },
+ ],
+ });
+
+ const completed = rows.filter((row) => row.lifecycle_state === 'completed');
+ const submitted = rows.filter((row) => row.lifecycle_state === 'submitted');
+
+ assert.equal(completed.length, 1);
+ assert.equal(completed[0].quote_id, 'quote-completed');
+ assert.equal(submitted.length, 1);
+ assert.equal(submitted[0].quote_id, 'quote-submitted');
+});
+
test('system service state ignores sentinel alert severity and keeps alert surfaces empty', () => {
const config = buildConfig();
const bootstrap = buildDashboardBootstrap({