unrip/src/core/service-snapshot-summary.mjs
philipp ddd3dfb9e2
All checks were successful
deploy / deploy (push) Successful in 58s
Remove verifier salt refresh from executor hot path
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.
2026-06-12 18:00:03 +02:00

156 lines
4 KiB
JavaScript

const COMMON_STATE_FIELDS = [
'paused',
'armed',
'last_error',
'last_event_at',
'last_runtime_eval_at',
'last_published_at',
'last_publish_error',
'publish_count',
'last_sync_at',
'last_write_at',
'last_metrics_at',
'last_quote_outcomes_at',
'database_connectivity',
'source_error_count',
'last_source_error_at',
'last_bootstrap_at',
];
export function summarizeServiceSnapshotForSentinel(snapshot = {}) {
return {
service: snapshot.service,
label: snapshot.label,
base_url: snapshot.base_url,
reachable: snapshot.reachable,
state: summarizeServiceState(snapshot.service, snapshot.state),
health: snapshot.health || null,
error: snapshot.error || null,
};
}
export function summarizeServiceState(service, state) {
if (!state || typeof state !== 'object') return state || null;
switch (service) {
case 'near-intents-ingest':
return pickFields(state, ['service', 'namespace', 'pair_filter', 'ingest']);
case 'market-reference-ingest':
return pickFields(state, [
'service',
'namespace',
'paused',
'kraken',
'coingecko',
'last_published_at',
'last_publish_error',
'publish_count',
'error_count',
'active_pair',
]);
case 'inventory-sync':
return {
...pickFields(state, ['service', 'namespace', 'account_id', 'paused', 'last_sync_at', 'last_error', 'publish_count']),
last_snapshot: summarizeInventorySnapshot(state.last_snapshot),
};
case 'liquidity-manager':
return pickFields(state, [
'service',
'namespace',
'account_id',
'paused',
'funding_observer_paused',
'withdrawals_frozen',
'deposit_addresses',
'supported_tokens_error',
'withdrawal_defaults',
'latest_funding_observation_at',
'last_refresh_at',
'last_error',
]);
case 'history-writer':
return pickFields(state, [
'service',
'namespace',
'database_connectivity',
'last_write_at',
'last_alert_write_at',
'last_funding_observation_write_at',
'last_environment_status_write_at',
'last_environment_status_seen_at',
'last_environment_status_duplicate_at',
'last_metrics_at',
'last_quote_outcomes_at',
'latest_portfolio_metrics',
'latest_quote_outcomes',
'offsets',
'metrics_error',
'quote_outcomes_error',
]);
case 'strategy-engine':
return pickFields(state, [
'service',
'namespace',
'paused',
'armed',
'last_error',
'latest_decision',
'latest_inventory_event',
'decision_count',
'command_count',
'reject_count',
'block_count',
]);
case 'trade-executor':
return pickFields(state, [
'service',
'namespace',
'paused',
'armed',
'last_error',
'relay',
'verifier_salt_cache',
'executor_queue_delay',
'last_result',
'last_quote_status',
'submitted_count',
'salt_unavailable_reject_count',
'last_salt_unavailable_at',
'last_salt_unavailable_state',
'failed_count',
'blocked_count',
]);
case 'operator-dashboard':
return pickFields(state, [
'service',
'namespace',
'source_error_count',
'last_source_error_at',
'last_bootstrap_at',
'source_errors',
]);
default:
return pickFields(state, COMMON_STATE_FIELDS);
}
}
function summarizeInventorySnapshot(snapshot) {
if (!snapshot || typeof snapshot !== 'object') return snapshot || null;
return pickFields(snapshot, [
'inventory_id',
'account_id',
'synced_at',
'spendable',
'pending_inbound',
'pending_outbound',
'reconciliation_status',
]);
}
function pickFields(source, fields) {
const picked = {};
for (const field of fields) {
if (source[field] !== undefined) picked[field] = source[field];
}
return picked;
}