Surface NEAR Intents upstream status truth
All checks were successful
deploy / deploy (push) Successful in 33s

Proof: npm test; npm run operator-dashboard:build; node --test test/near-intents-status.test.mjs test/operator-dashboard.test.mjs test/operator-dashboard-ui-static.test.mjs; PYTHONPATH=. python3 test/repo_deployments_test.py; kubectl kustomize deploy/k8s/base; live normalization against https://status.near-intents.org returned disrupted/upstream paused for the current 1Click quoting pause.

Assumptions: NEAR Intents public status page API is the official upstream disruption source for operator display; relay websocket reachability remains separately observed by ingest and executor state.

Still fake: This does not add an alternate quote source or recover trading while NEAR Intents quoting is paused; it only makes the upstream disruption explicit and separates it from local service freshness.
This commit is contained in:
philipp 2026-04-16 16:03:31 +02:00
parent 8641c60ab7
commit 99ca09b69e
9 changed files with 399 additions and 6 deletions

View file

@ -24,6 +24,7 @@ import {
resolveDashboardRequestAuth,
} from '../core/operator-dashboard-auth.mjs';
import { createLogger, serializeError } from '../core/log.mjs';
import { normalizeNearIntentsStatus } from '../core/near-intents-status.mjs';
import { readJsonBody, sendJson } from '../core/control-api.mjs';
import { loadConfig } from '../lib/config.mjs';
import { fetchJson } from '../lib/http.mjs';
@ -402,6 +403,7 @@ async function loadBootstrapPayload({ auth, page, pageSize }) {
recentIntentRequests,
recentAlertTransitions,
serviceSnapshots,
nearIntentsStatus,
] = await Promise.all([
safeSourceLoad('portfolio_metric', () => loadLatestPortfolioMetric(pool), null, sourceErrors),
safeSourceLoad('latest_inventory', () => loadLatestInventorySnapshot(pool), null, sourceErrors),
@ -483,6 +485,7 @@ async function loadBootstrapPayload({ auth, page, pageSize }) {
sourceErrors,
),
loadServiceSnapshots(),
safeSourceLoad('near_intents_status', () => loadNearIntentsStatus(), null, sourceErrors),
]);
const payload = buildDashboardBootstrap({
@ -503,6 +506,7 @@ async function loadBootstrapPayload({ auth, page, pageSize }) {
recentIntentRequests,
recentAlertTransitions,
serviceSnapshots,
nearIntentsStatus,
sourceErrors,
});
dashboardRuntimeState.last_bootstrap_at = new Date().toISOString();
@ -544,6 +548,27 @@ async function fetchUpstreamJson(url) {
});
}
async function loadNearIntentsStatus() {
const [servicesResponse, postsResponse, postEnumsResponse] = await Promise.all([
fetchNearIntentsStatusJson(config.nearIntentsStatusServicesUrl),
fetchNearIntentsStatusJson(config.nearIntentsStatusPostsUrl),
fetchNearIntentsStatusJson(config.nearIntentsStatusPostEnumsUrl),
]);
return normalizeNearIntentsStatus({
servicesResponse,
postsResponse,
postEnumsResponse,
observedAt: new Date().toISOString(),
});
}
async function fetchNearIntentsStatusJson(url) {
return fetchJson(url, {
signal: AbortSignal.timeout(config.nearIntentsStatusTimeoutMs),
});
}
async function invokeControl(control, body) {
const response = await fetchJson(
`${lookupServiceBaseUrl(control.service)}${control.path}`,

View file

@ -0,0 +1,116 @@
const TERMINAL_STATUS_NAMES = new Set([
'resolved',
'completed',
'complete',
'done',
]);
export function normalizeNearIntentsStatus({
postsResponse = null,
servicesResponse = null,
postEnumsResponse = null,
observedAt = new Date().toISOString(),
} = {}) {
const posts = Array.isArray(postsResponse?.posts)
? postsResponse.posts
: Array.isArray(postsResponse)
? postsResponse
: [];
const services = Array.isArray(servicesResponse?.services)
? servicesResponse.services
: Array.isArray(servicesResponse)
? servicesResponse
: [];
const postEnums = Array.isArray(postEnumsResponse?.post_enums)
? postEnumsResponse.post_enums
: Array.isArray(postEnumsResponse)
? postEnumsResponse
: [];
const statusById = new Map(
postEnums
.filter((entry) => entry?.post_enum_type === 'status')
.map((entry) => [entry.id, entry]),
);
const severityById = new Map(
postEnums
.filter((entry) => entry?.post_enum_type === 'severity')
.map((entry) => [entry.id, entry]),
);
const serviceById = new Map(services.map((entry) => [entry.id, entry]));
const incidents = posts
.map((post) => normalizePost(post, { statusById, severityById, serviceById }))
.filter(Boolean)
.filter((post) => post.active);
const affectedServices = [...new Set(
incidents.flatMap((incident) => incident.impacts.map((impact) => impact.service_name || impact.service_id)),
)].filter(Boolean);
const primaryIncident = incidents[0] || null;
return {
observed_at: observedAt,
source: 'near_intents_status_page',
status: incidents.length > 0 ? 'disrupted' : 'operational',
label: incidents.length > 0 ? 'upstream paused' : 'operational',
current_incident_count: incidents.length,
current_incidents: incidents,
affected_services: affectedServices,
quoting_stopped: incidents.some((incident) => /1click|quoting|solver|swap/i.test(
`${incident.title || ''} ${incident.message_text || ''}`,
)),
decisive_reason: primaryIncident
? [primaryIncident.title, primaryIncident.message_text].filter(Boolean).join(': ')
: 'NEAR Intents status page reports no active incident.',
};
}
function normalizePost(post, { statusById, severityById, serviceById }) {
if (!post || typeof post !== 'object') return null;
const latestUpdate = post.latest_update || [...(post.updates || [])].pop() || {};
const status = statusById.get(latestUpdate.status_id) || {};
const severity = severityById.get(latestUpdate.severity_id) || {};
const statusName = normalizeName(status.name || status.description || latestUpdate.status || 'unknown');
const ended = post.ends_at && Number(post.ends_at) <= Date.now();
const active = !ended && !TERMINAL_STATUS_NAMES.has(statusName);
return {
id: post.id || null,
title: post.title || null,
post_type: post.post_type || null,
status: statusName,
severity: normalizeName(severity.name || severity.description || 'unknown'),
active,
first_update_at: toIso(post.first_update_at || post.starts_at),
last_update_at: toIso(post.last_update_at || latestUpdate.reported_at),
message_text: stripHtml(latestUpdate.message || post.message || ''),
impacts: (latestUpdate.impacts || []).map((impact) => {
const service = serviceById.get(impact.service_id) || {};
const impactSeverity = severityById.get(impact.severity_id) || {};
return {
service_id: impact.service_id || null,
service_name: service.display_name || service.name || impact.service_id || null,
severity: normalizeName(impactSeverity.name || impactSeverity.description || 'unknown'),
};
}),
};
}
function normalizeName(value) {
return String(value || '').trim().toLowerCase().replaceAll(' ', '_') || 'unknown';
}
function stripHtml(value) {
return String(value || '')
.replace(/<[^>]*>/g, ' ')
.replace(/\s+/g, ' ')
.trim();
}
function toIso(value) {
if (value == null || value === '') return null;
const numeric = Number(value);
const date = Number.isFinite(numeric) ? new Date(numeric) : new Date(value);
return Number.isNaN(date.getTime()) ? null : date.toISOString();
}

View file

@ -454,6 +454,7 @@ export function buildDashboardBootstrap({
recentIntentRequests = [],
recentAlertTransitions,
serviceSnapshots,
nearIntentsStatus = null,
sourceErrors = [],
} = {}) {
const servicesByName = Object.fromEntries(
@ -498,6 +499,7 @@ export function buildDashboardBootstrap({
marketPrice,
activeAlerts,
servicesByName,
nearIntentsStatus,
}),
funds: {
profitability,
@ -536,6 +538,7 @@ export function buildDashboardBootstrap({
servicesByName,
activeAlerts,
recentAlerts,
nearIntentsStatus,
}),
};
}
@ -653,9 +656,14 @@ function buildStatusBar({
marketPrice,
activeAlerts,
servicesByName,
nearIntentsStatus = null,
}) {
return {
active_pair: config.activePair,
near_intents_upstream_status: nearIntentsStatus?.status || null,
near_intents_upstream_label: nearIntentsStatus?.label || null,
near_intents_upstream_reason: nearIntentsStatus?.decisive_reason || null,
near_intents_upstream_observed_at: nearIntentsStatus?.observed_at || null,
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),
@ -1445,7 +1453,7 @@ function summarizeGrossEdgeEstimate(rows = []) {
};
}
function buildSystemSummary({ servicesByName, activeAlerts, recentAlerts }) {
function buildSystemSummary({ servicesByName, activeAlerts, recentAlerts, nearIntentsStatus = null }) {
const historyWriterState = servicesByName['history-writer']?.state || {};
void activeAlerts;
void recentAlerts;
@ -1455,6 +1463,7 @@ function buildSystemSummary({ servicesByName, activeAlerts, recentAlerts }) {
summarizeServiceSnapshot(snapshot, {
authoritativeHealth: null,
activeAlerts: [],
nearIntentsStatus,
})
)),
alerts: {
@ -1478,7 +1487,7 @@ function buildSystemSummary({ servicesByName, activeAlerts, recentAlerts }) {
};
}
function summarizeServiceSnapshot(snapshot, { authoritativeHealth = null, activeAlerts = [] } = {}) {
function summarizeServiceSnapshot(snapshot, { authoritativeHealth = null, activeAlerts = [], nearIntentsStatus = null } = {}) {
const state = snapshot.state || {};
const health = snapshot.health || {};
void authoritativeHealth;
@ -1486,17 +1495,30 @@ function summarizeServiceSnapshot(snapshot, { authoritativeHealth = null, active
const freshnessAt = inferServiceFreshnessTimestamp(snapshot.service, state, health);
const reachable = snapshot.reachable !== false;
const online = reachable && health.ok !== false;
const healthStatus = online ? 'online' : reachable ? 'reachable' : 'offline';
const upstreamStatus = resolveServiceUpstreamStatus(snapshot.service, nearIntentsStatus);
const upstreamDisrupted = upstreamStatus?.status === 'disrupted';
const healthStatus = upstreamDisrupted
? 'upstream_paused'
: online
? 'online'
: reachable
? 'reachable'
: 'offline';
const healthLabel = upstreamDisrupted ? 'upstream paused' : healthStatus;
const healthReasons = upstreamDisrupted && upstreamStatus.decisive_reason
? [upstreamStatus.decisive_reason]
: [];
return {
service: snapshot.service,
label: snapshot.label,
base_url: snapshot.base_url,
reachable,
health_ok: online,
health_ok: healthStatus === 'online',
health_status: healthStatus,
health_label: healthStatus,
health_reasons: [],
health_label: healthLabel,
health_reasons: healthReasons,
upstream_status: upstreamStatus,
highest_alert_severity: null,
paused: state.paused ?? health.paused ?? null,
armed: state.armed ?? null,
@ -1508,6 +1530,22 @@ function summarizeServiceSnapshot(snapshot, { authoritativeHealth = null, active
};
}
const NEAR_INTENTS_RELAY_SERVICES = new Set(['near-intents-ingest', 'trade-executor']);
function resolveServiceUpstreamStatus(service, nearIntentsStatus) {
if (!NEAR_INTENTS_RELAY_SERVICES.has(service) || !nearIntentsStatus) return null;
return {
source: nearIntentsStatus.source || 'near_intents_status_page',
status: nearIntentsStatus.status || 'unknown',
label: nearIntentsStatus.label || nearIntentsStatus.status || 'unknown',
observed_at: nearIntentsStatus.observed_at || null,
decisive_reason: nearIntentsStatus.decisive_reason || null,
current_incident_count: nearIntentsStatus.current_incident_count || 0,
affected_services: nearIntentsStatus.affected_services || [],
quoting_stopped: nearIntentsStatus.quoting_stopped ?? null,
};
}
function buildServiceSummary(service, state) {
switch (service) {
case 'near-intents-ingest':

View file

@ -105,6 +105,10 @@ const DEFAULTS = {
operatorDashboardQuoteLimit: 10,
operatorDashboardTradePageSize: 20,
operatorDashboardUpstreamTimeoutMs: 3_000,
nearIntentsStatusServicesUrl: 'https://status.near-intents.org/api/services',
nearIntentsStatusPostsUrl: 'https://status.near-intents.org/api/posts?is_featured=true&limit=500',
nearIntentsStatusPostEnumsUrl: 'https://status.near-intents.org/api/post_enums',
nearIntentsStatusTimeoutMs: 3_000,
notificationNtfyBaseUrl: '',
notificationNtfyTopic: 'unrip',
notificationNtfyToken: '',
@ -575,6 +579,16 @@ export function loadConfig({ envPath = '.env' } = {}) {
process.env.OPERATOR_DASHBOARD_UPSTREAM_TIMEOUT_MS,
DEFAULTS.operatorDashboardUpstreamTimeoutMs,
),
nearIntentsStatusServicesUrl:
process.env.NEAR_INTENTS_STATUS_SERVICES_URL || DEFAULTS.nearIntentsStatusServicesUrl,
nearIntentsStatusPostsUrl:
process.env.NEAR_INTENTS_STATUS_POSTS_URL || DEFAULTS.nearIntentsStatusPostsUrl,
nearIntentsStatusPostEnumsUrl:
process.env.NEAR_INTENTS_STATUS_POST_ENUMS_URL || DEFAULTS.nearIntentsStatusPostEnumsUrl,
nearIntentsStatusTimeoutMs: parseNumber(
process.env.NEAR_INTENTS_STATUS_TIMEOUT_MS,
DEFAULTS.nearIntentsStatusTimeoutMs,
),
notificationNtfyBaseUrl:
process.env.NOTIFICATION_NTFY_BASE_URL || DEFAULTS.notificationNtfyBaseUrl,
notificationNtfyTopic:

View file

@ -33,6 +33,15 @@ export default function ServiceCard({ service }) {
<div>{`Armed ${formatBoolean(service.armed)}`}</div>
<div>{`Freshness ${freshnessAge}${freshnessAge === 'Unavailable' ? '' : ' ago'}`}</div>
<div>{`Freshness at ${formatTimestamp(service.freshness_at)}`}</div>
{service.upstream_status ? (
<>
<div>{`Upstream ${service.upstream_status.label || service.upstream_status.status || 'unknown'}`}</div>
<div>{`Upstream at ${formatTimestamp(service.upstream_status.observed_at)}`}</div>
{service.upstream_status.decisive_reason ? (
<div>{service.upstream_status.decisive_reason}</div>
) : null}
</>
) : null}
<div className="mono">{service.base_url}</div>
{service.last_error ? <div>{JSON.stringify(service.last_error)}</div> : null}
</div>

View file

@ -9,6 +9,10 @@ function statusSubtitle(label, status, websocketState) {
return formatTimestamp(status.market_observed_at);
case 'Inventory Freshness':
return formatTimestamp(status.inventory_observed_at);
case 'NEAR Intents':
return status.near_intents_upstream_observed_at
? `Official status at ${formatTimestamp(status.near_intents_upstream_observed_at)}`
: 'Official status page';
case SUBMISSION_COPY.statusTileLabel:
return SUBMISSION_COPY.statusTileSubtitle;
default:
@ -17,8 +21,16 @@ function statusSubtitle(label, status, websocketState) {
}
export default function StatusBar({ status, websocketState }) {
const nearIntentsTile = status.near_intents_upstream_label
? [[
'NEAR Intents',
status.near_intents_upstream_label,
status.near_intents_upstream_reason || status.near_intents_upstream_label,
]]
: [];
const tiles = [
['Pair', truncateMiddle(status.active_pair, 40), status.active_pair],
...nearIntentsTile,
['Portfolio', formatEur(status.current_total_portfolio_value_eure)],
['Reference BTC/EUR', formatEur(status.latest_reference_price_eure_per_btc)],
['Market Freshness', formatAge(status.market_freshness_ms)],

View file

@ -0,0 +1,83 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { normalizeNearIntentsStatus } from '../src/core/near-intents-status.mjs';
const postEnumsResponse = {
post_enums: [
{ id: 'PSCS3IV', post_enum_type: 'status', name: 'investigating' },
{ id: 'PP34365', post_enum_type: 'status', name: 'detected' },
{ id: 'P8TG2TF', post_enum_type: 'status', name: 'resolved' },
{ id: 'P187122', post_enum_type: 'severity', name: 'minor' },
{ id: 'PCIGMKW', post_enum_type: 'severity', name: 'degraded' },
],
};
const servicesResponse = {
services: [
{ id: 'PXQFSY1', name: 'Cross-Chain Bridging', display_name: 'Cross-Chain Bridging' },
{ id: 'PLT88AT', name: 'Solvers Network', display_name: 'Solvers Network' },
],
};
test('NEAR Intents status normalizer exposes current quoting disruption as upstream paused evidence', () => {
const normalized = normalizeNearIntentsStatus({
observedAt: '2026-04-16T12:40:00.000Z',
servicesResponse,
postEnumsResponse,
postsResponse: {
posts: [{
id: 'PM7LK6N',
title: '1Click Quoting is temporarily stopped',
post_type: 'incident',
latest_update: {
status_id: 'PSCS3IV',
severity_id: 'P187122',
reported_at: 1776342420000,
impacts: [{ service_id: 'PXQFSY1', severity_id: 'PCIGMKW' }],
message: '<p>The protocol is paused due to a security incident. Swaps are paused.</p>',
},
}],
},
});
assert.equal(normalized.source, 'near_intents_status_page');
assert.equal(normalized.status, 'disrupted');
assert.equal(normalized.label, 'upstream paused');
assert.equal(normalized.quoting_stopped, true);
assert.deepEqual(normalized.affected_services, ['Cross-Chain Bridging']);
assert.equal(normalized.current_incident_count, 1);
assert.equal(normalized.current_incidents[0].status, 'investigating');
assert.equal(normalized.current_incidents[0].severity, 'minor');
assert.equal(normalized.current_incidents[0].impacts[0].severity, 'degraded');
assert.match(normalized.decisive_reason, /1Click Quoting is temporarily stopped/);
assert.match(normalized.decisive_reason, /Swaps are paused/);
});
test('resolved NEAR Intents status posts do not make the relay look disrupted', () => {
const normalized = normalizeNearIntentsStatus({
observedAt: '2026-04-16T13:00:00.000Z',
servicesResponse,
postEnumsResponse,
postsResponse: {
posts: [{
id: 'PM7LK6N',
title: '1Click Quoting is temporarily stopped',
post_type: 'incident',
latest_update: {
status_id: 'P8TG2TF',
severity_id: 'P187122',
reported_at: 1776346020000,
impacts: [{ service_id: 'PXQFSY1', severity_id: 'PCIGMKW' }],
message: '<p>Resolved.</p>',
},
}],
},
});
assert.equal(normalized.status, 'operational');
assert.equal(normalized.label, 'operational');
assert.equal(normalized.quoting_stopped, false);
assert.equal(normalized.current_incident_count, 0);
assert.match(normalized.decisive_reason, /no active incident/i);
});

View file

@ -6,6 +6,7 @@ const strategySource = readFileSync(new URL('../src/operator-dashboard/static/pa
const fundsSource = readFileSync(new URL('../src/operator-dashboard/static/pages/FundsPage.jsx', import.meta.url), 'utf8');
const stylesSource = readFileSync(new URL('../src/operator-dashboard/static/styles.css', import.meta.url), 'utf8');
const serviceCardSource = readFileSync(new URL('../src/operator-dashboard/static/components/ServiceCard.jsx', import.meta.url), 'utf8');
const statusBarSource = readFileSync(new URL('../src/operator-dashboard/static/components/StatusBar.jsx', import.meta.url), 'utf8');
test('strategy page owns consolidated quote lifecycle and successful trade tables', () => {
assert.match(strategySource, /Quote lifecycle/);
@ -43,3 +44,14 @@ test('mobile status bar uses normal document flow instead of sticky viewport pos
/@media \(max-width: 720px\)[\s\S]*?\.status-bar \{[\s\S]*?position: static;[\s\S]*?top: auto;[\s\S]*?z-index: auto;[\s\S]*?\}/,
);
});
test('dashboard UI exposes official NEAR upstream status separately from local freshness', () => {
assert.match(statusBarSource, /NEAR Intents/);
assert.match(statusBarSource, /near_intents_upstream_label/);
assert.match(statusBarSource, /near_intents_upstream_reason/);
assert.match(statusBarSource, /Official status at/);
assert.match(serviceCardSource, /upstream_status/);
assert.match(serviceCardSource, /Upstream at/);
assert.match(serviceCardSource, /decisive_reason/);
});

View file

@ -1533,3 +1533,87 @@ test('own request dashboard rows do not label relay accepted evidence as complet
/successful trade|completed trade|asset delta/i,
);
});
test('dashboard surfaces NEAR upstream disruption without calling submitted work completed', () => {
const config = buildConfig();
const nearIntentsStatus = {
source: 'near_intents_status_page',
status: 'disrupted',
label: 'upstream paused',
observed_at: '2026-04-16T12:40:00.000Z',
decisive_reason: '1Click Quoting is temporarily stopped: The protocol is paused.',
current_incident_count: 1,
affected_services: ['Cross-Chain Bridging'],
quoting_stopped: true,
};
const dashboard = buildDashboardBootstrap({
config,
auth: { authenticated: true },
portfolioMetric: null,
inventorySnapshot: null,
marketPrice: null,
recentQuotes: [],
submissionPage: { page: 1, page_size: 20, total: 0, total_pages: 1, items: [] },
submissionSummary: { total: 0, last_submission_at: null },
fundingObservations: [],
recentDepositStatuses: [],
recentTradeDecisions: [],
recentExecuteTradeCommands: [],
recentExecutionResults: [{
command_id: 'cmd-submitted',
decision_id: 'decision-submitted',
quote_id: 'quote-submitted',
status: 'submitted',
result_code: 'quote_response_ok',
}],
recentQuoteOutcomes: [],
recentIntentRequests: [],
recentAlertTransitions: [],
nearIntentsStatus,
serviceSnapshots: [
{
service: 'near-intents-ingest',
label: 'NEAR Intents Ingest',
base_url: 'http://near-intents-ingest',
reachable: true,
health: { ok: true },
state: { ingest: { connected: false, last_message_at: null } },
},
{
service: 'trade-executor',
label: 'Trade Executor',
base_url: 'http://trade-executor',
reachable: true,
health: { ok: true },
state: { relay: { connected: false } },
},
{
service: 'history-writer',
label: 'History Writer',
base_url: 'http://history-writer',
reachable: true,
health: { ok: true },
state: {},
},
],
});
assert.equal(dashboard.status_bar.near_intents_upstream_status, 'disrupted');
assert.equal(dashboard.status_bar.near_intents_upstream_label, 'upstream paused');
assert.match(dashboard.status_bar.near_intents_upstream_reason, /protocol is paused/);
const services = Object.fromEntries(
dashboard.system.service_health.map((service) => [service.service, service]),
);
assert.equal(services['near-intents-ingest'].health_status, 'upstream_paused');
assert.equal(services['near-intents-ingest'].health_label, 'upstream paused');
assert.equal(services['near-intents-ingest'].health_ok, false);
assert.match(services['near-intents-ingest'].health_reasons[0], /1Click Quoting/);
assert.equal(services['near-intents-ingest'].upstream_status.status, 'disrupted');
assert.equal(services['trade-executor'].health_status, 'upstream_paused');
assert.equal(services['trade-executor'].upstream_status.quoting_stopped, true);
assert.equal(services['history-writer'].health_status, 'online');
assert.equal(services['history-writer'].upstream_status, null);
});