unrip/src/core/operator-dashboard.mjs
philipp 0b7e5e2e6c
All checks were successful
deploy / deploy (push) Successful in 26s
Implement runtime health sentinel and angry dashboard
Proof: Runtime health sentinel, alert routing, and anomaly detection for stale/disconnected quote truth, truthful dashboard severity, webhook notifications, and safe executor containment.

Assumptions: Existing control APIs remain the service-local truth surface; external notification stays as a generic webhook sink; executor disarm is an allowed non-fund-moving containment action; current dashboard/operator files in the worktree belong to this turn and are intended to ship together.

Still fake: No live external receiver is configured; webhook delivery is implemented but unverified end-to-end in production; cluster rollout still depends on deploying the new image; no automatic deployment restart path was added.
2026-04-08 19:35:07 +02:00

1200 lines
42 KiB
JavaScript

import { unitsToNumber } from './assets.mjs';
import { summarizeFundingObservations } from './funding-observations.mjs';
import { resolveDashboardRequestAuth } from './operator-dashboard-auth.mjs';
import { deriveServiceHealth, inferServiceFreshnessTimestamp as inferRuntimeFreshnessTimestamp } from './runtime-health.mjs';
export const DASHBOARD_LIVE_QUOTE_LIMIT = 10;
const DECIMAL_SCALE = 18;
const DECIMAL_FACTOR = 10n ** BigInt(DECIMAL_SCALE);
const ALERT_SEVERITY_ORDER = {
critical: 3,
warning: 2,
info: 1,
};
const CREDITED_FUNDING_STATUSES = new Set(['CREDITED', 'COMPLETED', 'FINALIZED', 'SETTLED']);
const CONTROL_DEFINITIONS = [
{
service: 'near-intents-ingest',
action: 'reconnect',
method: 'POST',
path: '/reconnect',
label: 'Reconnect Ingest',
description: 'Reconnect the ingest websocket without restarting the deployment.',
page: 'system',
risk_class: 'safe',
},
{
service: 'market-reference-ingest',
action: 'refresh',
method: 'POST',
path: '/refresh',
label: 'Refresh Price',
description: 'Fetch the latest BTC/EUR reference price.',
page: 'funds',
risk_class: 'safe',
},
{
service: 'inventory-sync',
action: 'refresh',
method: 'POST',
path: '/refresh',
label: 'Refresh Inventory',
description: 'Sync verifier balances into the latest inventory snapshot.',
page: 'funds',
risk_class: 'safe',
},
{
service: 'liquidity-manager',
action: 'refresh',
method: 'POST',
path: '/refresh',
label: 'Refresh Liquidity',
description: 'Refresh bridge deposit handles, deposits, and tracked withdrawals.',
page: 'funds',
risk_class: 'safe',
},
{
service: 'liquidity-manager',
action: 'pause',
method: 'POST',
path: '/pause',
label: 'Pause Liquidity',
description: 'Pause non-fund-moving liquidity state refreshes.',
page: 'system',
risk_class: 'safe',
},
{
service: 'liquidity-manager',
action: 'resume',
method: 'POST',
path: '/resume',
label: 'Resume Liquidity',
description: 'Resume liquidity state refreshes.',
page: 'system',
risk_class: 'safe',
},
{
service: 'liquidity-manager',
action: 'pause-funding-observer',
method: 'POST',
path: '/pause-funding-observer',
label: 'Pause Funding Observer',
description: 'Pause pre-credit funding observations without touching spendable truth.',
page: 'funds',
risk_class: 'safe',
},
{
service: 'liquidity-manager',
action: 'resume-funding-observer',
method: 'POST',
path: '/resume-funding-observer',
label: 'Resume Funding Observer',
description: 'Resume pre-credit funding observations.',
page: 'funds',
risk_class: 'safe',
},
{
service: 'liquidity-manager',
action: 'freeze-withdrawals',
method: 'POST',
path: '/freeze-withdrawals',
label: 'Update Withdrawal Freeze',
description: 'Toggle withdrawal freeze without submitting live withdrawals.',
page: 'funds',
risk_class: 'safe',
},
{
service: 'liquidity-manager',
action: 'withdrawal-estimate',
method: 'POST',
path: '/withdrawal-estimate',
label: 'Estimate Withdrawal',
description: 'Estimate a bridge withdrawal without moving funds.',
page: 'funds',
risk_class: 'safe',
},
{
service: 'trade-executor',
action: 'reconnect',
method: 'POST',
path: '/reconnect',
label: 'Reconnect Relay',
description: 'Reconnect the trade-executor solver relay websocket.',
page: 'system',
risk_class: 'safe',
},
{
service: 'trade-executor',
action: 'pause',
method: 'POST',
path: '/pause',
label: 'Pause Executor',
description: 'Pause trade-executor command consumption without moving funds.',
page: 'system',
risk_class: 'safe',
},
{
service: 'trade-executor',
action: 'resume',
method: 'POST',
path: '/resume',
label: 'Resume Executor',
description: 'Resume trade-executor command consumption.',
page: 'system',
risk_class: 'safe',
},
{
service: 'trade-executor',
action: 'disarm',
method: 'POST',
path: '/disarm',
label: 'Disarm Executor',
description: 'Force the executor into a non-fund-moving safe state.',
page: 'system',
risk_class: 'safe',
},
{
service: 'ops-sentinel',
action: 'pause',
method: 'POST',
path: '/pause',
label: 'Pause Alerts',
description: 'Pause alert evaluation without changing trade arming state.',
page: 'system',
risk_class: 'safe',
},
{
service: 'ops-sentinel',
action: 'resume',
method: 'POST',
path: '/resume',
label: 'Resume Alerts',
description: 'Resume alert evaluation.',
page: 'system',
risk_class: 'safe',
},
];
const SERVICE_DEFINITIONS = [
['near-intents-ingest', 'Intents Ingest', 'nearIntentsControlBaseUrl'],
['market-reference-ingest', 'Reference Price', 'marketReferenceControlBaseUrl'],
['inventory-sync', 'Inventory Sync', 'inventorySyncControlBaseUrl'],
['liquidity-manager', 'Liquidity Manager', 'liquidityManagerControlBaseUrl'],
['history-writer', 'History Writer', 'historyWriterControlBaseUrl'],
['ops-sentinel', 'Ops Sentinel', 'opsSentinelControlBaseUrl'],
['strategy-engine', 'Strategy Engine', 'strategyEngineControlBaseUrl'],
['trade-executor', 'Trade Executor', 'tradeExecutorControlBaseUrl'],
];
export function resolveDashboardAuth({ mode = 'stub' } = {}) {
return resolveDashboardRequestAuth({ mode });
}
export function listDashboardControls({ page = null } = {}) {
const controls = CONTROL_DEFINITIONS.map((definition) => ({ ...definition }));
if (!page) return controls;
return controls.filter((definition) => definition.page === page);
}
export function resolveDashboardControl({ service, action }) {
return CONTROL_DEFINITIONS.find((definition) => (
definition.service === service && definition.action === action
)) || null;
}
export function listDashboardServices(config) {
return SERVICE_DEFINITIONS.map(([service, label, configKey]) => ({
service,
label,
base_url: config[configKey],
}));
}
export function createDashboardLiveState({
config,
recentQuotes = [],
latestMarketPrice = null,
latestInventory = null,
successfulTradeCount = 0,
lastSuccessfulTradeAt = null,
activeAlerts = [],
} = {}) {
const state = {
active_pair: config.activePair,
btc_asset: config.tradingBtc,
eure_asset: config.tradingEure,
quote_limit: config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT,
recent_quotes: recentQuotes.slice(0, config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT),
latest_market_price: latestMarketPrice?.payload || latestMarketPrice || null,
latest_inventory: latestInventory?.payload || latestInventory || null,
successful_trade_count: Number(successfulTradeCount || 0),
last_successful_trade_at: lastSuccessfulTradeAt || null,
active_alerts: new Map(),
};
for (const alert of activeAlerts) {
if (!alert) continue;
state.active_alerts.set(buildAlertKey(alert), alert);
}
return state;
}
export function applyDashboardLiveEvent(state, { topic, event }) {
if (!event?.payload) return [];
switch (topic) {
case 'norm.swap_demand': {
const quote = normalizeLiveQuote(event.payload, event);
if (!quote) return [];
state.recent_quotes = appendUniqueRecentQuote(state.recent_quotes, quote, state.quote_limit);
return [{
type: 'quotes.recent',
recent_quotes: state.recent_quotes,
}];
}
case 'ref.market_price':
state.latest_market_price = {
...event.payload,
observed_at: event.observed_at || event.payload.observed_at || null,
ingested_at: event.ingested_at || null,
};
return [{
type: 'status_bar.updated',
status_bar: buildLiveStatusBar(state),
}];
case 'state.intent_inventory':
state.latest_inventory = {
...event.payload,
observed_at: event.observed_at || event.payload.synced_at || null,
ingested_at: event.ingested_at || null,
};
return [{
type: 'status_bar.updated',
status_bar: buildLiveStatusBar(state),
}];
case 'ops.alert': {
const alert = normalizeAlert(event.payload);
const key = buildAlertKey(alert);
if (alert.status === 'raised') {
state.active_alerts.set(key, alert);
} else if (alert.status === 'cleared') {
state.active_alerts.delete(key);
}
return [{
type: 'alerts.updated',
alerts: {
active_alert_count: state.active_alerts.size,
highest_alert_severity: highestAlertSeverity([...state.active_alerts.values()]),
},
}, {
type: 'status_bar.updated',
status_bar: buildLiveStatusBar(state),
}];
}
case 'exec.trade_result':
if (event.payload.status !== 'submitted') return [];
state.successful_trade_count += 1;
state.last_successful_trade_at = event.observed_at || event.ingested_at || new Date().toISOString();
return [{
type: 'status_bar.updated',
status_bar: buildLiveStatusBar(state),
}];
default:
return [];
}
}
export function buildDashboardBootstrap({
config,
auth,
portfolioMetric,
inventorySnapshot,
marketPrice,
recentQuotes,
successfulTrades,
successfulTradeSummary,
fundingObservations,
recentDepositStatuses,
recentTradeDecisions,
recentAlertTransitions,
serviceSnapshots,
sourceErrors = [],
} = {}) {
const servicesByName = Object.fromEntries(
(serviceSnapshots || []).map((snapshot) => [snapshot.service, snapshot]),
);
const activeAlerts = normalizeAlertList(
servicesByName['ops-sentinel']?.state?.active_alerts || [],
);
const recentAlerts = normalizeAlertList(
servicesByName['ops-sentinel']?.state?.recent_transitions
|| recentAlertTransitions?.map((entry) => entry.payload)
|| [],
);
const profitability = buildProfitabilitySummary({
metric: portfolioMetric,
successfulTradeSummary,
});
const balances = buildBalanceSummary({
inventorySnapshot,
marketPrice,
config,
});
const funding = buildFundingSummary({
config,
fundingObservations,
recentDepositStatuses,
liquidityState: servicesByName['liquidity-manager']?.state || {},
});
const tradesPage = normalizeSuccessfulTradesPage({
config,
successfulTrades,
});
return {
session: auth,
source_errors: sourceErrors,
default_page: 'funds',
status_bar: buildStatusBar({
config,
profitability,
inventorySnapshot,
marketPrice,
activeAlerts,
servicesByName,
}),
funds: {
profitability,
balances,
funding,
recent_deposits: funding.credited_deposits,
recent_withdrawals: buildRecentWithdrawals({
config,
liquidityState: servicesByName['liquidity-manager']?.state || {},
}),
trade_asset_changes: buildTradeAssetChanges({
config,
trades: tradesPage.items,
}),
recent_quotes: (recentQuotes || []).slice(0, config.operatorDashboardQuoteLimit || DASHBOARD_LIVE_QUOTE_LIMIT),
successful_trades: tradesPage,
controls: listDashboardControls({ page: 'funds' }),
caveats: profitability.caveats,
},
strategy: buildStrategySummary({
servicesByName,
activeAlerts,
recentTradeDecisions,
}),
system: buildSystemSummary({
servicesByName,
activeAlerts,
recentAlerts,
}),
};
}
export function buildProfitabilitySummary({ metric, successfulTradeSummary } = {}) {
const externalCashFlows = metric?.payload?.external_cash_flows || {};
const externalFlowCount = Number(externalCashFlows.flow_count || 0);
const externalFlowAdjusted = externalFlowCount > 0;
const summary = {
computed_at: metric?.computed_at || null,
current_total_portfolio_value_eure: metric?.payload?.current_portfolio_value_eure || null,
deposit_baseline_value_eure: metric?.payload?.baseline_portfolio_value_eure_at_baseline_price || null,
simple_hold_value_eure: metric?.payload?.baseline_portfolio_value_eure_at_current_price || null,
pnl_vs_deposit_baseline_eure: null,
pnl_vs_simple_hold_eure: null,
market_move_contribution_eure: null,
trading_contribution_eure: null,
baseline_anchor_at: metric?.baseline_anchor_at || null,
baseline_status: metric?.baseline_status || metric?.payload?.baseline_status || 'unavailable',
external_flow_adjusted: externalFlowAdjusted,
external_flow_count: externalFlowCount,
external_deposit_count: Number(externalCashFlows.deposit_count || 0),
external_withdrawal_count: Number(externalCashFlows.withdrawal_count || 0),
latest_external_flow_at: externalCashFlows.latest_effective_at || null,
net_external_flow_value_eure: externalCashFlows.net_value_eure_at_flow_time || '0',
recent_trade_count: successfulTradeSummary?.total ?? metric?.payload?.result_count ?? 0,
last_successful_trade_at: successfulTradeSummary?.last_successful_trade_at || null,
caveats: [
'Portfolio PnL is truthful to the current durable inventory and reference price path.',
'Fees and per-trade realized net settlement deltas are not fully tracked yet.',
],
};
if (summary.current_total_portfolio_value_eure == null) {
summary.caveats.unshift('Profitability is unavailable until durable portfolio metrics exist.');
return summary;
}
if (summary.deposit_baseline_value_eure) {
summary.pnl_vs_deposit_baseline_eure = formatDecimalDifference(
summary.current_total_portfolio_value_eure,
summary.deposit_baseline_value_eure,
);
}
if (summary.simple_hold_value_eure) {
summary.pnl_vs_simple_hold_eure = formatDecimalDifference(
summary.current_total_portfolio_value_eure,
summary.simple_hold_value_eure,
);
}
if (summary.deposit_baseline_value_eure && summary.simple_hold_value_eure) {
summary.market_move_contribution_eure = formatDecimalDifference(
summary.simple_hold_value_eure,
summary.deposit_baseline_value_eure,
);
}
if (summary.simple_hold_value_eure) {
summary.trading_contribution_eure = formatDecimalDifference(
summary.current_total_portfolio_value_eure,
summary.simple_hold_value_eure,
);
}
if (summary.external_flow_adjusted) {
summary.caveats.unshift(
`Later credited deposits and completed withdrawals (${summary.external_flow_count}) are treated as external cash flows, not trading PnL.`,
);
}
return summary;
}
export function buildLiveStatusBar(state) {
return {
latest_reference_price_eure_per_btc: state.latest_market_price?.eure_per_btc || null,
market_observed_at:
state.latest_market_price?.observed_at
|| state.latest_market_price?.ingested_at
|| null,
market_freshness_ms: ageMs(
state.latest_market_price?.observed_at || state.latest_market_price?.ingested_at,
),
inventory_observed_at:
state.latest_inventory?.synced_at
|| state.latest_inventory?.observed_at
|| state.latest_inventory?.ingested_at
|| null,
inventory_freshness_ms: ageMs(
state.latest_inventory?.synced_at
|| state.latest_inventory?.observed_at
|| state.latest_inventory?.ingested_at,
),
current_total_portfolio_value_eure: computeCurrentPortfolioValue({
inventory: state.latest_inventory,
marketPrice: state.latest_market_price,
btcAsset: state.btc_asset,
eureAsset: state.eure_asset,
}),
active_alert_count: state.active_alerts.size,
highest_alert_severity: highestAlertSeverity([...state.active_alerts.values()]),
recent_trade_count: state.successful_trade_count,
last_successful_trade_at: state.last_successful_trade_at,
};
}
function buildStatusBar({
config,
profitability,
inventorySnapshot,
marketPrice,
activeAlerts,
servicesByName,
}) {
return {
active_pair: config.activePair,
latest_reference_price_eure_per_btc: marketPrice?.payload?.eure_per_btc || null,
market_observed_at: marketPrice?.payload?.observed_at || marketPrice?.ingested_at || null,
market_freshness_ms: ageMs(marketPrice?.payload?.observed_at || marketPrice?.ingested_at),
inventory_observed_at:
inventorySnapshot?.payload?.synced_at || inventorySnapshot?.ingested_at || null,
inventory_freshness_ms: ageMs(
inventorySnapshot?.payload?.synced_at || inventorySnapshot?.ingested_at,
),
active_alert_count: activeAlerts.length,
highest_alert_severity: highestAlertSeverity(activeAlerts),
strategy_armed: servicesByName['strategy-engine']?.state?.armed ?? null,
executor_armed: servicesByName['trade-executor']?.state?.armed ?? null,
current_total_portfolio_value_eure: profitability.current_total_portfolio_value_eure,
recent_trade_count: profitability.recent_trade_count,
last_successful_trade_at: profitability.last_successful_trade_at,
};
}
function buildBalanceSummary({ inventorySnapshot, marketPrice, config }) {
const inventory = inventorySnapshot?.payload || {};
const spendable = inventory.spendable || {};
const pendingInbound = inventory.pending_inbound || {};
const pendingOutbound = inventory.pending_outbound || {};
return {
synced_at: inventory.synced_at || inventorySnapshot?.ingested_at || null,
reconciliation_status: inventory.reconciliation_status || null,
items: [...config.assetRegistry.values()].map((asset) => {
const spendableUnits = String(spendable[asset.assetId] || '0');
const pendingInboundUnits = String(pendingInbound[asset.assetId] || '0');
const pendingOutboundUnits = String(pendingOutbound[asset.assetId] || '0');
return {
asset_id: asset.assetId,
symbol: asset.symbol,
chain: asset.chain,
spendable_units: spendableUnits,
spendable: formatUnits(spendableUnits, asset.decimals),
pending_inbound_units: pendingInboundUnits,
pending_inbound: formatUnits(pendingInboundUnits, asset.decimals),
pending_outbound_units: pendingOutboundUnits,
pending_outbound: formatUnits(pendingOutboundUnits, asset.decimals),
eur_value_eure: valueAssetInEur({
asset,
units: spendableUnits,
marketPrice: marketPrice?.payload || marketPrice || null,
}),
};
}),
};
}
function buildFundingSummary({ config, fundingObservations, recentDepositStatuses, liquidityState }) {
const observations = (fundingObservations || []).map((entry) => entry.payload || entry);
const summary = summarizeFundingObservations(observations, {
now: new Date().toISOString(),
});
const observerItems = observations.map((observation) => normalizeFundingObservationForUi({
config,
observation,
}));
const depositItems = buildRecentDepositItems({
config,
recentDepositStatuses,
liquidityState,
});
const recentFundingActivity = mergeFundingActivityItems({
observerItems,
depositItems,
});
return {
latest_observed_at: latestFundingActivityAt(recentFundingActivity, summary.latest_funding_observation_at),
control_state: {
paused: liquidityState?.paused ?? null,
funding_observer_paused: liquidityState?.funding_observer_paused ?? null,
withdrawals_frozen: liquidityState?.withdrawals_frozen ?? null,
withdrawal_defaults: liquidityState?.withdrawal_defaults || {},
},
handles: Object.entries(liquidityState?.deposit_addresses || {}).map(([chain, details]) => ({
chain,
asset_id: config.tradingBtc.chain === chain ? config.tradingBtc.assetId : config.tradingEure.assetId,
symbol: config.tradingBtc.chain === chain ? config.tradingBtc.symbol : config.tradingEure.symbol,
address: details?.address || null,
memo: details?.memo || null,
refreshed_at: details?.refreshed_at || null,
})),
credited_deposits: recentFundingActivity
.filter((observation) => CREDITED_FUNDING_STATUSES.has(String(observation?.status || '').toUpperCase()))
.sort((left, right) => sortTimestamps(
fundingActivityTimestamp(right),
fundingActivityTimestamp(left),
))
.slice(0, 10)
.map((observation) => ({ ...observation })),
pre_credit_by_asset: Object.values(summary.funding_visibility_by_asset || {}).map((entry) => {
const asset = config.assetRegistry.get(entry.asset_id);
return {
asset_id: entry.asset_id,
symbol: asset?.symbol || entry.asset_id,
pre_credit_total_units: entry.pre_credit_total || '0',
pre_credit_total: formatUnits(entry.pre_credit_total || '0', asset?.decimals || 0),
latest_status: entry.latest_status,
latest_observation_at: entry.latest_observation_at,
};
}),
pre_credit_by_handle: Object.values(summary.funding_observations_by_handle || {}).map((entry) => {
const asset = config.assetRegistry.get(entry.asset_id);
return {
funding_handle: entry.funding_handle,
chain: entry.chain,
asset_id: entry.asset_id,
symbol: asset?.symbol || entry.asset_id,
pre_credit_total_units: entry.pre_credit_total || '0',
pre_credit_total: formatUnits(entry.pre_credit_total || '0', asset?.decimals || 0),
latest_status: entry.latest_status,
latest_observation_at: entry.latest_observation_at,
observation_count: entry.observations?.length || 0,
};
}),
recent_observations: recentFundingActivity
.sort((left, right) => sortTimestamps(
fundingActivityTimestamp(right),
fundingActivityTimestamp(left),
))
.slice(0, 10)
.map((observation) => ({ ...observation })),
};
}
function buildRecentWithdrawals({ config, liquidityState }) {
return Object.values(liquidityState?.tracked_withdrawals || {})
.sort((left, right) => sortTimestamps(
right.last_checked_at || right.submitted_at || right.noted_at,
left.last_checked_at || left.submitted_at || left.noted_at,
))
.slice(0, 10)
.map((withdrawal) => {
const asset = config.assetRegistry.get(withdrawal.asset_id);
return {
withdrawal_hash: withdrawal.withdrawal_hash,
asset_id: withdrawal.asset_id,
symbol: asset?.symbol || withdrawal.asset_id,
chain: withdrawal.chain || null,
amount_units: String(withdrawal.amount || '0'),
amount: formatUnits(withdrawal.amount || '0', asset?.decimals || 0),
status: withdrawal.status || null,
address: withdrawal.address || null,
submitted_at: withdrawal.submitted_at || null,
last_checked_at: withdrawal.last_checked_at || null,
noted_at: withdrawal.noted_at || null,
};
});
}
function buildTradeAssetChanges({ config, trades }) {
return (trades || []).slice(0, 10).map((trade) => {
const assetIn = config.assetRegistry.get(trade.asset_in);
const assetOut = config.assetRegistry.get(trade.asset_out);
return {
observed_at: trade.observed_at,
quote_id: trade.quote_id,
request_kind: trade.request_kind,
asset_in: trade.asset_in,
asset_in_symbol: assetIn?.symbol || trade.asset_in,
amount_in_units: trade.amount_in,
amount_in: formatUnits(trade.amount_in || '0', assetIn?.decimals || 0),
asset_out: trade.asset_out,
asset_out_symbol: assetOut?.symbol || trade.asset_out,
amount_out_units: trade.amount_out,
amount_out: formatUnits(trade.amount_out || '0', assetOut?.decimals || 0),
};
});
}
function normalizeSuccessfulTradesPage({ config, successfulTrades }) {
return {
...successfulTrades,
items: (successfulTrades?.items || []).map((trade) => normalizeTradeForUi({
config,
trade,
})),
};
}
function buildStrategySummary({ servicesByName, activeAlerts, recentTradeDecisions = [] }) {
const strategyState = servicesByName['strategy-engine']?.state || {};
const executorState = servicesByName['trade-executor']?.state || {};
const durableDecisionsById = new Map(
(recentTradeDecisions || [])
.map((entry) => normalizeDecision({
...(entry.payload || {}),
decision_at:
entry?.payload?.decision_at
|| entry?.observed_at
|| entry?.ingested_at
|| null,
}))
.filter((entry) => entry?.decision_id)
.map((entry) => [entry.decision_id, entry]),
);
const recentDecisions = (strategyState.recent_decisions || []).slice(0, 20).map((decision) => {
const durableDecision = durableDecisionsById.get(decision?.decision_id) || null;
return normalizeDecision({
...(durableDecision || {}),
...(decision || {}),
decision_at:
decision?.decision_at
|| durableDecision?.decision_at
|| null,
});
});
const latestDecision = normalizeDecision({
...(durableDecisionsById.get(strategyState.latest_decision?.decision_id) || {}),
...(strategyState.latest_decision || {}),
decision_at:
strategyState.latest_decision?.decision_at
|| durableDecisionsById.get(strategyState.latest_decision?.decision_id)?.decision_at
|| null,
});
return {
strategy_state: {
armed: strategyState.armed ?? null,
paused: strategyState.paused ?? null,
threshold_pct: strategyState.threshold_pct ?? null,
max_notional_eure: strategyState.max_notional_eure ?? null,
latest_decision: latestDecision?.decision_id ? latestDecision : null,
recent_decisions: recentDecisions.length
? recentDecisions
: [...durableDecisionsById.values()].slice(0, 20),
skipped_counts: strategyState.skipped_counts || {},
durable_control_state: strategyState.durable_control_state || null,
},
executor_state: {
armed: executorState.armed ?? null,
paused: executorState.paused ?? null,
draining: executorState.draining ?? null,
in_flight_count: executorState.in_flight_count ?? 0,
completed_count: executorState.completed_count ?? 0,
last_command: executorState.last_command || null,
last_venue_response: executorState.last_venue_response || null,
last_error: executorState.last_error || null,
signer_registered: executorState.signer_registered ?? null,
account_id: executorState.account_id || null,
signer_public_key: executorState.signer_public_key || null,
},
relevant_alerts: activeAlerts.filter((alert) => (
['strategy-engine', 'trade-executor', 'liquidity-manager'].includes(alert.service_scope)
)),
omitted_controls: [
'Strategy arm and disarm are intentionally absent in this turn.',
'Executor arm and drain are intentionally absent in this turn.',
'Live withdrawal submission is intentionally absent in this turn.',
],
};
}
function buildSystemSummary({ servicesByName, activeAlerts, recentAlerts }) {
const historyWriterState = servicesByName['history-writer']?.state || {};
const sentinelServiceHealth = new Map(
(servicesByName['ops-sentinel']?.state?.service_health || []).map((entry) => [entry.service, entry]),
);
return {
service_health: Object.values(servicesByName).map((snapshot) => (
summarizeServiceSnapshot(snapshot, {
authoritativeHealth: sentinelServiceHealth.get(snapshot.service) || null,
activeAlerts,
})
)),
alerts: {
active: activeAlerts,
recent: recentAlerts,
},
persistence: {
database_connectivity: historyWriterState.database_connectivity ?? null,
last_write_at: historyWriterState.last_write_at || null,
last_alert_write_at: historyWriterState.last_alert_write_at || null,
last_funding_observation_write_at: historyWriterState.last_funding_observation_write_at || null,
last_metrics_at: historyWriterState.last_metrics_at || null,
latest_portfolio_metrics: historyWriterState.latest_portfolio_metrics || null,
offsets: historyWriterState.offsets || {},
metrics_error: historyWriterState.metrics_error || null,
},
controls: listDashboardControls({ page: 'system' }),
};
}
function summarizeServiceSnapshot(snapshot, { authoritativeHealth = null, activeAlerts = [] } = {}) {
const state = snapshot.state || {};
const health = snapshot.health || {};
const derived = authoritativeHealth || deriveServiceHealth({
service: snapshot.service,
snapshot,
activeAlerts: activeAlerts.filter((alert) => alert.service_scope === snapshot.service),
});
const freshnessAt = derived.freshness_at || inferServiceFreshnessTimestamp(snapshot.service, state, health);
return {
service: snapshot.service,
label: snapshot.label,
base_url: snapshot.base_url,
reachable: snapshot.reachable,
health_ok: derived.health_ok,
health_status: derived.status,
health_reasons: derived.reasons || [],
highest_alert_severity: derived.highest_alert_severity || null,
paused: derived.paused ?? state.paused ?? health.paused ?? null,
armed: derived.armed ?? state.armed ?? null,
draining: state.draining ?? null,
freshness_at: freshnessAt,
freshness_age_ms: derived.freshness_age_ms ?? ageMs(freshnessAt),
last_error: state.last_error || health.last_error || null,
summary: buildServiceSummary(snapshot.service, state),
};
}
function buildServiceSummary(service, state) {
switch (service) {
case 'near-intents-ingest':
return {
connected: state.ingest?.connected ?? null,
reconnect_count: state.ingest?.reconnect_count ?? null,
pair_filter: state.pair_filter?.pair_filter || null,
last_message_at: state.ingest?.last_message_at || null,
last_matching_quote_at: state.ingest?.last_matching_quote_at || null,
last_published_at: state.ingest?.last_published_at || null,
};
case 'market-reference-ingest':
return {
last_published_at: state.last_published_at || null,
source_used: state.kraken?.healthy ? 'kraken' : state.coingecko?.healthy ? 'coingecko' : null,
};
case 'inventory-sync':
return {
last_sync_at: state.last_sync_at || null,
reconciliation_status: state.last_snapshot?.reconciliation_status || null,
};
case 'liquidity-manager':
return {
last_refresh_at: state.last_refresh_at || null,
funding_observer_paused: state.funding_observer_paused ?? null,
withdrawals_frozen: state.withdrawals_frozen ?? null,
};
case 'history-writer':
return {
last_write_at: state.last_write_at || null,
last_alert_write_at: state.last_alert_write_at || null,
database_connectivity: state.database_connectivity ?? null,
};
case 'ops-sentinel':
return {
last_event_at: state.last_event_at || null,
last_runtime_eval_at: state.last_runtime_eval_at || null,
active_alert_count: state.active_alerts?.length || 0,
stale: state.stale ?? null,
};
case 'strategy-engine':
return {
latest_decision_id: state.latest_decision?.decision_id || null,
threshold_pct: state.threshold_pct ?? null,
max_notional_eure: state.max_notional_eure ?? null,
};
case 'trade-executor':
return {
in_flight_count: state.in_flight_count ?? 0,
completed_count: state.completed_count ?? 0,
signer_registered: state.signer_registered ?? null,
relay_connected: state.relay?.connected ?? null,
relay_last_message_at: state.relay?.last_message_at || null,
};
case 'operator-dashboard':
return {
source_error_count: state.source_error_count ?? 0,
last_source_error_at: state.last_source_error_at || null,
last_bootstrap_at: state.last_bootstrap_at || null,
};
default:
return {};
}
}
function inferServiceFreshnessTimestamp(service, state, health) {
return inferRuntimeFreshnessTimestamp(service, state, health);
}
function normalizeTradeForUi({ config, trade }) {
const assetIn = config.assetRegistry.get(trade.asset_in);
const assetOut = config.assetRegistry.get(trade.asset_out);
return {
...trade,
asset_in_symbol: assetIn?.symbol || trade.asset_in,
asset_out_symbol: assetOut?.symbol || trade.asset_out,
amount_in_display: formatUnits(trade.amount_in || '0', assetIn?.decimals || 0),
amount_out_display: formatUnits(trade.amount_out || '0', assetOut?.decimals || 0),
};
}
function buildRecentDepositItems({ config, recentDepositStatuses, liquidityState }) {
const recentItems = (recentDepositStatuses || []).map((entry) => normalizeDepositStatusForUi({
config,
depositStatus: entry,
}));
const itemsByKey = new Map(
recentItems.map((item) => [buildFundingActivityKey(item), item]),
);
for (const deposit of Object.values(liquidityState?.deposits || {})) {
const fallbackItem = normalizeLiquidityDepositForUi({
config,
deposit,
observedAt: liquidityState?.last_refresh_at || null,
});
const key = buildFundingActivityKey(fallbackItem);
if (!itemsByKey.has(key)) {
itemsByKey.set(key, fallbackItem);
}
}
return [...itemsByKey.values()];
}
function mergeFundingActivityItems({ observerItems, depositItems }) {
const merged = new Map();
for (const item of depositItems || []) {
merged.set(buildFundingActivityKey(item), item);
}
for (const item of observerItems || []) {
merged.set(buildFundingActivityKey(item), item);
}
return [...merged.values()];
}
function latestFundingActivityAt(items, fallback = null) {
let latest = fallback;
for (const item of items || []) {
if (sortTimestamps(fundingActivityTimestamp(item), latest) > 0) {
latest = fundingActivityTimestamp(item);
}
}
return latest;
}
function fundingActivityTimestamp(item) {
return item?.last_seen_at || item?.credited_at || item?.first_seen_at || null;
}
function buildFundingActivityKey(item) {
return [
item?.tx_hash || 'no-tx',
item?.chain || 'no-chain',
item?.asset_id || 'no-asset',
item?.funding_handle || 'no-handle',
item?.amount_units || 'no-amount',
].join('|');
}
function normalizeFundingObservationForUi({ config, observation }) {
const asset = config.assetRegistry.get(observation.asset_id);
return {
funding_observation_id: observation.funding_observation_id,
asset_id: observation.asset_id,
symbol: asset?.symbol || observation.asset_id,
chain: observation.chain,
funding_handle: observation.funding_handle,
tx_hash: observation.tx_hash,
status: observation.status,
amount_units: observation.amount,
amount: formatUnits(observation.amount || '0', asset?.decimals || 0),
confirmations: observation.confirmations,
first_seen_at: observation.first_seen_at,
last_seen_at: observation.last_seen_at,
credited_at: observation.credited_at || null,
};
}
function normalizeDepositStatusForUi({ config, depositStatus }) {
const payload = depositStatus?.payload || {};
const details = payload.details || {};
return normalizeLiquidityDepositForUi({
config,
deposit: {
tx_hash: details.tx_hash || null,
chain: payload.chain || details.chain || null,
asset_id: payload.asset_id || details.asset_id || null,
amount: details.amount || '0',
address: details.address || details.deposit_address || null,
status: payload.status || details.status || null,
},
observedAt: depositStatus?.observed_at || depositStatus?.ingested_at || null,
});
}
function normalizeLiquidityDepositForUi({ config, deposit, observedAt }) {
const asset = config.assetRegistry.get(deposit?.asset_id);
const status = deposit?.status || null;
const timestamp = observedAt || null;
return {
funding_observation_id: null,
asset_id: deposit?.asset_id || null,
symbol: asset?.symbol || deposit?.asset_id || null,
chain: deposit?.chain || null,
funding_handle: deposit?.address || null,
tx_hash: deposit?.tx_hash || null,
status,
amount_units: String(deposit?.amount || '0'),
amount: formatUnits(deposit?.amount || '0', asset?.decimals || 0),
confirmations: null,
first_seen_at: timestamp,
last_seen_at: timestamp,
credited_at: CREDITED_FUNDING_STATUSES.has(String(status || '').toUpperCase()) ? timestamp : null,
};
}
function normalizeDecision(decision) {
if (!decision) return null;
return {
decision_id: decision.decision_id || null,
decision_at: decision.decision_at || null,
quote_id: decision.quote_id || null,
pair: decision.pair || null,
direction: decision.direction || null,
request_kind: decision.request_kind || null,
decision: decision.decision || null,
decision_reason: decision.decision_reason || null,
gross_edge_pct: decision.gross_edge_pct || null,
threshold_pct: decision.threshold_pct || null,
max_notional_eure: decision.max_notional_eure || null,
strategy_armed: decision.strategy_armed ?? null,
inventory_asset: decision.inventory_asset || null,
eure_notional: decision.eure_notional || null,
};
}
function normalizeAlertList(alerts) {
return (alerts || []).map(normalizeAlert).sort((left, right) => sortTimestamps(
right.raised_at || right.first_raised_at || right.cleared_at,
left.raised_at || left.first_raised_at || left.cleared_at,
));
}
function normalizeAlert(alert) {
return {
alert_code: alert.alert_code,
status: alert.status,
severity: alert.severity,
reason: alert.reason,
service_scope: alert.service_scope,
pair: alert.pair || null,
asset_id: alert.asset_id || null,
tx_hash: alert.tx_hash || null,
raised_at: alert.raised_at || null,
first_raised_at: alert.first_raised_at || null,
cleared_at: alert.cleared_at || null,
last_evaluated_at: alert.last_evaluated_at || null,
details: alert.details || {},
};
}
function appendUniqueRecentQuote(quotes, nextQuote, limit) {
const deduped = [nextQuote, ...quotes.filter((quote) => quote.quote_id !== nextQuote.quote_id)];
return deduped.slice(0, limit);
}
function normalizeLiveQuote(payload, event) {
if (!payload?.quote_id) return null;
return {
quote_id: payload.quote_id,
pair: payload.pair || `${payload.asset_in}->${payload.asset_out}`,
asset_in: payload.asset_in || null,
asset_out: payload.asset_out || null,
request_kind: payload.request_kind || null,
amount_in: payload.amount_in ?? null,
amount_out: payload.amount_out ?? null,
observed_at: event.observed_at || null,
ingested_at: event.ingested_at || null,
};
}
function buildAlertKey(alert) {
return [
alert.alert_code,
alert.service_scope,
alert.pair || '',
alert.asset_id || '',
alert.tx_hash || '',
].join('|');
}
function highestAlertSeverity(alerts) {
return (alerts || []).reduce((highest, alert) => {
const currentRank = ALERT_SEVERITY_ORDER[highest] || 0;
const nextRank = ALERT_SEVERITY_ORDER[alert.severity] || 0;
return nextRank > currentRank ? alert.severity : highest;
}, null);
}
function computeCurrentPortfolioValue({ inventory, marketPrice, btcAsset, eureAsset }) {
if (!inventory || !marketPrice || !btcAsset || !eureAsset) return null;
const btcUnits = String(inventory.spendable?.[btcAsset.assetId] || '0');
const eureUnits = String(inventory.spendable?.[eureAsset.assetId] || '0');
const btcScaled = unitsToScaledDecimal(btcUnits, btcAsset.decimals);
const eureScaled = unitsToScaledDecimal(eureUnits, eureAsset.decimals);
const priceScaled = parseScaledDecimal(marketPrice.eure_per_btc || marketPrice.eur_per_btc || '0');
const total = eureScaled + multiplyScaled(btcScaled, priceScaled);
return formatScaledDecimal(total);
}
function valueAssetInEur({ asset, units, marketPrice }) {
if (!asset) return null;
if (asset.symbol === 'EURe') {
return formatUnits(units || '0', asset.decimals);
}
if (!marketPrice || asset.symbol !== 'BTC') return null;
const scaledUnits = unitsToScaledDecimal(units || '0', asset.decimals);
const priceScaled = parseScaledDecimal(marketPrice.eure_per_btc || marketPrice.eur_per_btc || '0');
return formatScaledDecimal(multiplyScaled(scaledUnits, priceScaled));
}
function formatDecimalDifference(left, right) {
return formatScaledDecimal(parseScaledDecimal(left) - parseScaledDecimal(right));
}
function unitsToScaledDecimal(units, decimals) {
return BigInt(String(units || '0')) * 10n ** BigInt(DECIMAL_SCALE - decimals);
}
function parseScaledDecimal(value) {
const normalized = String(value ?? '0').trim();
const negative = normalized.startsWith('-');
const unsigned = normalized.replace(/^[+-]/, '');
const [wholePart, fractionalPart = ''] = unsigned.split('.');
const whole = BigInt(wholePart || '0');
const fractional = BigInt(
(fractionalPart.padEnd(DECIMAL_SCALE, '0')).slice(0, DECIMAL_SCALE) || '0',
);
const scaled = (whole * DECIMAL_FACTOR) + fractional;
return negative ? -scaled : scaled;
}
function multiplyScaled(left, right) {
return (left * right) / DECIMAL_FACTOR;
}
function formatScaledDecimal(value) {
const negative = value < 0n;
const absolute = negative ? -value : value;
const whole = absolute / DECIMAL_FACTOR;
const fractional = absolute % DECIMAL_FACTOR;
if (fractional === 0n) {
return `${negative ? '-' : ''}${whole}`;
}
const fractionalText = fractional
.toString()
.padStart(DECIMAL_SCALE, '0')
.replace(/0+$/, '');
return `${negative ? '-' : ''}${whole}.${fractionalText}`;
}
function formatUnits(units, decimals) {
const numeric = unitsToNumber(units, decimals);
if (!Number.isFinite(numeric)) return '0';
if (Math.abs(numeric) >= 1000) return numeric.toLocaleString('en-US', { maximumFractionDigits: 8 });
return numeric.toLocaleString('en-US', { maximumFractionDigits: 8 });
}
function ageMs(value) {
const parsed = Date.parse(value || '');
if (!Number.isFinite(parsed)) return null;
return Math.max(0, Date.now() - parsed);
}
function sortTimestamps(left, right) {
return timestampValue(left) - timestampValue(right);
}
function timestampValue(value) {
const parsed = Date.parse(value || '');
return Number.isFinite(parsed) ? parsed : -Infinity;
}