diff --git a/UI/proxy_ui/proxy_ui_server.py b/UI/proxy_ui/proxy_ui_server.py
index 00afb1f..d2daa20 100644
--- a/UI/proxy_ui/proxy_ui_server.py
+++ b/UI/proxy_ui/proxy_ui_server.py
@@ -75,6 +75,11 @@ async def proxy_topology() -> Any:
return await _get_json(DEFAULT_PROXY_CP_URL, "/v1/topology/kdn_links")
+@app.get("/api/proxy/loads")
+async def proxy_loads() -> Any:
+ return await _get_json(DEFAULT_PROXY_CP_URL, "/debug/instance_loads", {"include_dead": "true"})
+
+
@app.get("/api/scheduler/proxy")
async def scheduler_proxy() -> Dict[str, Any]:
if not DEFAULT_PROXY_ID:
diff --git a/UI/proxy_ui/static/app.js b/UI/proxy_ui/static/app.js
index f16e0d4..bcb5449 100644
--- a/UI/proxy_ui/static/app.js
+++ b/UI/proxy_ui/static/app.js
@@ -5,7 +5,7 @@ const state = {
timer: null,
paused: false,
intervalMs: 3000,
- theme: localStorage.getItem('proxy-ui-theme') || 'dark',
+ theme: (typeof localStorage !== 'undefined' && localStorage.getItem('proxy-ui-theme')) || 'dark',
rawExpanded: false,
sortBy: 'state',
filters: {
@@ -30,19 +30,19 @@ function $(id) {
}
function clampPercent(value) {
- const number = Number(value);
- if (!Number.isFinite(number)) {
+ const number = finiteNumber(value);
+ if (number === null) {
return null;
}
return Math.max(0, Math.min(100, number));
}
function fmt(value, digits = 1) {
- if (value === null || value === undefined || value === '') {
+ const number = finiteNumber(value);
+ if (number === null) {
return '—';
}
- const number = Number(value);
- return Number.isFinite(number) ? number.toFixed(digits) : String(value);
+ return number.toFixed(digits);
}
function formatTimestamp(value) {
@@ -136,7 +136,15 @@ async function settleJson(path, options = {}) {
function hasResourceReport(instance) {
const resource = instance.resource || {};
- return Object.values(resource).some((value) => value !== null && value !== undefined);
+ if (finiteNumber(resource.resource_reported_at) !== null) {
+ return true;
+ }
+ const scalarKeys = [
+ 'cpu_util', 'memory_used_mb', 'memory_total_mb', 'memory_free_mb',
+ 'gpu_util_avg', 'gpu_mem_used_mb', 'gpu_mem_total_mb',
+ 'network_rx_mbps', 'network_tx_mbps',
+ ];
+ return scalarKeys.some((key) => finiteNumber(resource[key]) !== null);
}
@@ -294,15 +302,15 @@ function average(values) {
}
function computeMetrics(instances) {
- const cpu = average(instances.map((item) => Number(item.resource?.cpu_util)));
+ const cpu = average(instances.map((item) => finiteNumber(item.resource?.cpu_util)));
const memory = average(instances.map((item) => {
- const used = Number(item.resource?.memory_used_mb);
- const total = Number(item.resource?.memory_total_mb);
- return Number.isFinite(used) && Number.isFinite(total) && total > 0 ? (used / total) * 100 : NaN;
+ const used = finiteNumber(item.resource?.memory_used_mb);
+ const total = finiteNumber(item.resource?.memory_total_mb);
+ return used !== null && total !== null && total > 0 ? (used / total) * 100 : null;
}));
- const gpu = average(instances.map((item) => Number(item.resource?.gpu_util_avg)));
- const rx = average(instances.map((item) => Number(item.resource?.network_rx_mbps)));
- const tx = average(instances.map((item) => Number(item.resource?.network_tx_mbps)));
+ const gpu = average(instances.map((item) => finiteNumber(item.resource?.gpu_util_avg)));
+ const rx = average(instances.map((item) => finiteNumber(item.resource?.network_rx_mbps)));
+ const tx = average(instances.map((item) => finiteNumber(item.resource?.network_tx_mbps)));
return { cpu, memory, gpu, rx, tx };
}
@@ -443,51 +451,307 @@ function renderResourceTable(resources) {
}
-function renderSystemTopology(instances, scheduler) {
+
+function stateLabel(instance) {
+ if (instance?.is_alive === true) return 'alive';
+ if (instance?.is_alive === false) return 'stale';
+ return 'unknown';
+}
+
+function shortText(value, max = 18) {
+ const text = String(value ?? '—');
+ return text.length > max ? `${text.slice(0, Math.max(1, max - 1))}…` : text;
+}
+
+function finiteNumber(value) {
+ if (typeof value === 'number') {
+ return Number.isFinite(value) ? value : null;
+ }
+ if (typeof value === 'string') {
+ const trimmed = value.trim();
+ if (!trimmed) return null;
+ const numberPattern = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
+ if (!numberPattern.test(trimmed)) return null;
+ const number = Number(trimmed);
+ return Number.isFinite(number) ? number : null;
+ }
+ return null;
+}
+
+function percentOf(value, max) {
+ const current = finiteNumber(value);
+ const total = finiteNumber(max);
+ if (current === null || total === null || total <= 0) return null;
+ return clampPercent((current / total) * 100);
+}
+
+function displayNumber(value, digits = 1) {
+ const number = finiteNumber(value);
+ if (number === null) return '—';
+ return Number.isInteger(number) ? String(number) : number.toFixed(digits);
+}
+
+function buildTopologyModel(instances, scheduler, proxyState = {}) {
const [schedulerLabel, schedulerTone] = schedulerText(scheduler);
- const proxyId = state.config?.proxy_id || state.latest.status?.proxy_id || 'current proxy';
- const instanceNodes = instances.map((instance) => `
-
- ${escapeHtml(instance.instance_id || 'unknown')}
- ${instance.is_alive === false ? 'stale' : instance.is_alive === true ? 'alive' : 'unknown'}
-
- `).join('') || 'No connected instances reported.
';
- $('systemTopology').innerHTML = `
- Scheduler${escapeHtml(schedulerLabel)}
- │
- Proxy (observed/local)${escapeHtml(proxyId)}
- ┬
- ${instanceNodes}
- `;
+ const proxyId = proxyState.proxy_id || state.config?.proxy_id || state.latest.status?.proxy_id || 'current proxy';
+ const proxyTone = proxyState?.ok === false ? 'bad' : (proxyState ? 'ok' : 'warn');
+ const sortedInstances = [...(Array.isArray(instances) ? instances : [])]
+ .sort((a, b) => String(a.instance_id || '').localeCompare(String(b.instance_id || '')));
+ const nodes = [
+ { id: 'scheduler', type: 'scheduler', label: 'Scheduler', status: schedulerLabel, tone: schedulerTone, raw: scheduler || {} },
+ { id: 'proxy', type: 'proxy', label: 'Proxy', status: proxyState?.ok === false ? 'error' : String(proxyId), tone: proxyTone, raw: proxyState || {} },
+ ...sortedInstances.map((instance) => ({
+ id: `instance:${instance.instance_id || 'unknown'}`,
+ type: 'instance',
+ instanceId: String(instance.instance_id || 'unknown'),
+ label: String(instance.instance_id || 'unknown'),
+ status: stateLabel(instance),
+ tone: stateLabel(instance) === 'alive' ? 'ok' : stateLabel(instance) === 'stale' ? 'bad' : 'warn',
+ raw: instance,
+ })),
+ ];
+ const links = [
+ { id: 'scheduler-proxy', source: 'scheduler', target: 'proxy', status: scheduler?.ok ? 'active' : 'inactive' },
+ ...sortedInstances.map((instance) => ({
+ id: `proxy-${instance.instance_id || 'unknown'}`,
+ source: 'proxy',
+ target: `instance:${instance.instance_id || 'unknown'}`,
+ status: stateLabel(instance) === 'alive' ? 'active' : stateLabel(instance) === 'stale' ? 'stale' : 'unknown',
+ })),
+ ];
+ return { nodes, links, schedulerLabel, schedulerTone, proxyId, instances: sortedInstances };
+}
+
+function computeTopologyLayout(model, options = {}) {
+ const count = model.instances.length;
+ const width = Math.max(760, options.width || 980);
+ const nodePadding = Number(options.nodePadding ?? 54);
+ const labelPadding = Number(options.labelPadding ?? 70);
+ const positions = { scheduler: { x: width / 2, y: 64 }, proxy: { x: width / 2, y: 178 } };
+ const cols = count === 0 ? 0 : (count <= 4 ? count : count <= 8 ? 4 : count <= 20 ? 5 : 6);
+ const rowGap = count <= 8 ? 130 : 118;
+ const startY = 314;
+ model.instances.forEach((instance, index) => {
+ const row = Math.floor(index / cols);
+ const col = index % cols;
+ const rowCount = Math.min(cols, count - row * cols);
+ const gapX = (width - nodePadding * 2) / Math.max(1, rowCount + 1);
+ positions[`instance:${instance.instance_id || 'unknown'}`] = {
+ x: nodePadding + gapX * (col + 1),
+ y: startY + row * rowGap,
+ };
+ });
+ const xs = Object.values(positions).map((pos) => pos.x);
+ const ys = Object.values(positions).map((pos) => pos.y);
+ const minX = Math.min(...xs) - nodePadding;
+ const maxX = Math.max(...xs) + nodePadding;
+ if (minX < 0 || maxX > width) {
+ Object.values(positions).forEach((pos) => {
+ pos.x = Math.max(nodePadding, Math.min(width - nodePadding, pos.x));
+ });
+ }
+ const height = Math.max(360, Math.max(...ys) + labelPadding);
+ return { width, height, positions, nodePadding, labelPadding };
+}
+
+function nodeTooltip(node) {
+ const raw = node.raw || {};
+ const resource = raw.resource || {};
+ const address = raw.host ? `${raw.host}:${raw.port ?? '—'}` : (node.type === 'proxy' ? String(node.status) : '—');
+ const cpu = resource.cpu_util !== null && resource.cpu_util !== undefined ? `CPU ${fmt(resource.cpu_util)}%` : null;
+ const gpu = resource.gpu_util_avg !== null && resource.gpu_util_avg !== undefined ? `GPU ${fmt(resource.gpu_util_avg)}%` : null;
+ return [`Type: ${node.type}`, `ID: ${node.instanceId || node.label}`, `Address: ${address}`, `State: ${node.status}`, `Last seen: ${formatTimestamp(raw.last_seen_at)}`, cpu, gpu].filter(Boolean).join('\n');
+}
+
+function renderMetricBar({ label, value, max = 100, unit = '', tone = 'accent', secondaryText = '' }) {
+ const current = finiteNumber(value);
+ const total = finiteNumber(max);
+ const percent = current === null ? null : (total && total > 0 ? clampPercent((current / total) * 100) : null);
+ const width = percent === null ? 0 : percent;
+ const primary = current === null ? 'No data' : `${displayNumber(current, 2)}${unit}`;
+ return `${escapeHtml(label)}${escapeHtml(primary)}
${escapeHtml(secondaryText || (percent === null ? '—' : `${percent.toFixed(1)}% of ${displayNumber(total, 2)}${unit}`))} `;
+}
+
+function renderDonutChart({ label, used, total, unit = '' }) {
+ const rawUsed = finiteNumber(used);
+ const rawTotal = finiteNumber(total);
+ if (rawUsed === null || rawTotal === null || rawTotal <= 0) {
+ return `${escapeHtml(label)}
No data
`;
+ }
+ const safeUsed = Math.max(0, Math.min(rawUsed, rawTotal));
+ const percent = (safeUsed / rawTotal) * 100;
+ const free = Math.max(0, rawTotal - safeUsed);
+ const dash = `${percent.toFixed(2)} ${Math.max(0, 100 - percent).toFixed(2)}`;
+ return `${escapeHtml(label)}
used ${escapeHtml(displayNumber(rawUsed, 1))}${escapeHtml(unit)} · free ${escapeHtml(displayNumber(free, 1))}${escapeHtml(unit)}
`;
+}
+
+function extractQueueMetrics(instance) {
+ const paths = [['load', instance?.load], ['resource', instance?.resource], ['meta', instance?.meta], ['queue', instance?.queue], ['queues', instance?.queues], ['stats', instance?.stats]];
+ const keywords = /ready|waiting|queued|pending|running|inflight|prepare|prefill|decode|kv|kvcache|transfer|inject/i;
+ const reject = /time|timestamp|ts|port|util|ratio|percent|age|memory|mem|gpu_util|cpu/i;
+ const seen = new Set();
+ const found = [];
+ function visit(prefix, value, depth = 0) {
+ if (!value || typeof value !== 'object' || depth > 3) return;
+ Object.entries(value).forEach(([key, child]) => {
+ const path = prefix ? `${prefix}.${key}` : key;
+ if (child && typeof child === 'object' && !Array.isArray(child)) visit(path, child, depth + 1);
+ const number = finiteNumber(child);
+ if (number === null || number < 0 || !keywords.test(key) || reject.test(key)) return;
+ if (seen.has(path)) return;
+ seen.add(path);
+ found.push({ key: path, label: key.replaceAll('_', ' '), value: number });
+ });
+ }
+ paths.forEach(([prefix, value]) => visit(prefix, value));
+ return found.sort((a, b) => a.key.localeCompare(b.key));
+}
+
+function hardwareDetails(instance) {
+ const devices = instance.resource?.raw_resource?.devices || {};
+ const cpu = devices.cpu && typeof devices.cpu === 'object' ? devices.cpu : {};
+ const gpus = Array.isArray(devices.gpu) ? devices.gpu : [];
+ const nics = Array.isArray(devices.network) ? devices.network : (Array.isArray(devices.nic) ? devices.nic : []);
+ return { cpu, gpus, nics };
+}
+
+function normalizeLoadSnapshots(loadsPayload) {
+ return Array.isArray(loadsPayload?.instances) ? loadsPayload.instances : [];
+}
+
+function loadSnapshotByInstanceId(loadsPayload, instanceId) {
+ return normalizeLoadSnapshots(loadsPayload).find((item) => String(item.instance_id) === String(instanceId)) || null;
+}
+
+function mergedInstanceLoad(instance, loadsPayload = state.latest.loads) {
+ const snapshot = loadSnapshotByInstanceId(loadsPayload, instance?.instance_id) || {};
+ const baseLoad = instance?.load || {};
+ return { ...baseLoad, ...snapshot, heartbeat_load: baseLoad, debug_load: snapshot };
+}
+
+function nestedNumber(payload, path) {
+ return path.split('.').reduce((acc, key) => (acc && typeof acc === 'object' ? acc[key] : undefined), payload);
+}
+
+function explicitLoadMetrics(load) {
+ return [
+ ['inflight', 'Inflight'],
+ ['qps_1m', 'QPS 1m'],
+ ['gpu_util', 'Heartbeat GPU util'],
+ ['least_load_score.total', 'Least-load score'],
+ ].map(([key, label]) => ({ key, label, value: finiteNumber(nestedNumber(load, key)) }))
+ .filter((item) => item.value !== null);
+}
+
+function explicitDetailedQueueMetrics(load) {
+ return [
+ ['prepare_queue_depth', 'Prepare queue depth'],
+ ['ready_queue_depth', 'Ready queue depth'],
+ ['active_prepare', 'Active prepare'],
+ ['active_ready', 'Active ready'],
+ ].map(([key, label]) => ({ key, label, value: finiteNumber(nestedNumber(load, key)) }))
+ .filter((item) => item.value !== null);
+}
+
+
+function queueMetricsForInstance(instance, loadsPayload = state.latest.loads) {
+ const load = mergedInstanceLoad(instance, loadsPayload);
+ const explicit = explicitDetailedQueueMetrics(load);
+ const explicitKeys = new Set(explicit.map((item) => item.key));
+ const loadOnlyKeys = new Set(['load.inflight', 'load.qps_1m', 'load.gpu_util', 'inflight', 'qps_1m', 'gpu_util', 'least_load_score.total']);
+ const heuristic = extractQueueMetrics(instance)
+ .filter((item) => !explicitKeys.has(item.key) && !loadOnlyKeys.has(item.key));
+ return [...explicit, ...heuristic];
+}
+
+
+function applyPausedTopologyState() {
+ const container = typeof document !== 'undefined' ? $('systemTopology') : null;
+ if (container) {
+ container.classList.toggle('paused', state.paused);
+ }
+}
+
+function gpuName(gpu) {
+ return firstString(gpu.name, gpu.model, gpu.product_name) || 'GPU';
+}
+
+function gpuUtil(gpu) {
+ return finiteNumber(gpu.utilization_pct ?? gpu.utilization_gpu_pct ?? gpu.gpu_util ?? gpu.util);
+}
+
+function nicName(nic) {
+ return firstString(nic.iface, nic.interface, nic.name, nic.model) || 'NIC';
+}
+
+function renderSystemTopology(instances, scheduler) {
+ const model = buildTopologyModel(instances, scheduler, state.latest.status || {});
+ const layout = computeTopologyLayout(model);
+ const linkHtml = model.links.map((link) => {
+ const a = layout.positions[link.source];
+ const b = layout.positions[link.target];
+ if (!a || !b) return '';
+ const midY = (a.y + b.y) / 2;
+ const d = `M ${a.x} ${a.y + 28} C ${a.x} ${midY}, ${b.x} ${midY}, ${b.x} ${b.y - 30}`;
+ return `${escapeHtml(link.source)} to ${escapeHtml(link.target)}: ${escapeHtml(link.status)}`;
+ }).join('');
+ const nodeHtml = model.nodes.map((node) => {
+ const pos = layout.positions[node.id];
+ if (!pos) return '';
+ const isInstance = node.type === 'instance';
+ const aria = `${node.type} ${node.instanceId || node.label} ${node.status}`;
+ return `
+ ${escapeHtml(nodeTooltip(node))}
+
+
+ ${escapeHtml(shortText(node.label, 18))}
+ ${escapeHtml(shortText(node.status, 22))}
+ `;
+ }).join('');
+ $('systemTopology').classList.toggle('paused', state.paused);
+ $('systemTopology').innerHTML = `${model.instances.length ? '' : 'No connected instances reported.
'}`;
}
function renderInstanceDetail(instances) {
const panel = $('instanceDetailView');
- if (!state.selectedInstanceId) {
- panel.classList.add('hidden');
- return;
- }
+ if (!state.selectedInstanceId) { panel.classList.add('hidden'); return; }
const instance = instances.find((item) => String(item.instance_id) === String(state.selectedInstanceId));
if (!instance) {
panel.classList.remove('hidden');
- panel.innerHTML = `Selected instance is not present in the current payload.
`;
+ panel.innerHTML = `Selected instance ${escapeHtml(state.selectedInstanceId)} is not present in the current payload.
`;
return;
}
const resource = instance.resource || {};
- const hw = hardwareSummary(instance);
- const staleNote = instance.is_alive === false ? 'This Instance is stale; values below may reflect the last known report.
' : '';
+ const load = mergedInstanceLoad(instance);
+ const memPercent = percentOf(resource.memory_used_mb, resource.memory_total_mb);
+ const gpuMemPercent = percentOf(resource.gpu_mem_used_mb, resource.gpu_mem_total_mb);
+ const networkMax = Math.max(finiteNumber(resource.network_rx_mbps) || 0, finiteNumber(resource.network_tx_mbps) || 0, 1);
+ const loadMetrics = explicitLoadMetrics(load);
+ const queues = queueMetricsForInstance(instance);
+ const maxQueue = Math.max(1, ...queues.map((item) => item.value));
+ const hw = hardwareDetails(instance);
+ const staleNote = instance.is_alive === false ? 'This Instance is stale; values may reflect the last known report.
' : '';
panel.classList.remove('hidden');
- panel.innerHTML = `
- Instance Detail: ${escapeHtml(instance.instance_id)}
${staleNote}
-
-
Identity
${escapeHtml(instance.host)}:${escapeHtml(instance.port)}
${escapeHtml(stableJson({ endpoints: instance.endpoints, tags: instance.tags, weight: instance.weight, metadata: instance.meta }))}
-
Liveness
${instanceStateBadge(instance)} ${badge(`registered: ${formatTimestamp(instance.registered_at)}`, 'muted')} ${badge(`last seen age: ${formatAge(instance.last_seen_at)}`, instance.is_alive === false ? 'bad' : 'muted')}
-
Current Load
inflight ${fmt(instance.load?.inflight, 0)} · qps ${fmt(instance.load?.qps_1m, 2)} · heartbeat GPU ${fmt(instance.load?.gpu_util)}%
-
Resource Snapshot
CPU ${fmt(resource.cpu_util)}% · memory ${fmt(resource.memory_used_mb,0)}/${fmt(resource.memory_total_mb,0)} MB · GPU ${fmt(resource.gpu_util_avg)}% · GPU memory ${fmt(resource.gpu_mem_used_mb,0)}/${fmt(resource.gpu_mem_total_mb,0)} MB · RX ${fmt(resource.network_rx_mbps,2)} Mbps · TX ${fmt(resource.network_tx_mbps,2)} Mbps · admission ${escapeHtml(resource.admission_state || '—')} · ${resourceAgeTone(resource)[0]}
-
Hardware Summary
${escapeHtml([hw.cpu, hw.gpu, hw.nic].filter(Boolean).join(' · ') || 'device: unknown')}
-
Raw Instance JSON
${escapeHtml(stableJson(instance))}
+ panel.innerHTML = `
+
+ ${[['Status', stateLabel(instance)], ['Instance ID', instance.instance_id], ['Host:port', `${instance.host || '—'}:${instance.port || '—'}`], ['Admission', resource.admission_state || '—'], ['Registered', formatTimestamp(instance.registered_at)], ['Last seen age', formatAge(instance.last_seen_at)], ['Resource age', formatAge(resource.resource_reported_at)], ['Inflight', displayNumber(load.inflight, 0)], ['QPS 1m', displayNumber(load.qps_1m, 2)], ['GPU util', displayNumber(load.gpu_util, 1)], ['Least-load score', displayNumber(nestedNumber(load, 'least_load_score.total'), 2)]].map(([k,v]) => `
${escapeHtml(k)}${escapeHtml(v)}`).join('')}
- `;
+
+
Resource utilization
${renderMetricBar({ label:'CPU utilization', value:resource.cpu_util, max:100, unit:'%', secondaryText:'reported resource.cpu_util' })}${renderMetricBar({ label:'System memory', value:resource.memory_used_mb, max:resource.memory_total_mb, unit:' MB', secondaryText:`${displayNumber(resource.memory_used_mb,0)} / ${displayNumber(resource.memory_total_mb,0)} MB (${memPercent === null ? '—' : memPercent.toFixed(1)+'%'})` })}${renderMetricBar({ label:'GPU utilization', value:resource.gpu_util_avg, max:100, unit:'%', secondaryText:'reported resource.gpu_util_avg' })}${renderMetricBar({ label:'GPU memory', value:resource.gpu_mem_used_mb, max:resource.gpu_mem_total_mb, unit:' MB', secondaryText:`${displayNumber(resource.gpu_mem_used_mb,0)} / ${displayNumber(resource.gpu_mem_total_mb,0)} MB (${gpuMemPercent === null ? '—' : gpuMemPercent.toFixed(1)+'%'})` })}${renderMetricBar({ label:'Network RX', value:resource.network_rx_mbps, max:networkMax, unit:' Mbps', secondaryText:'relative to current RX/TX max' })}${renderMetricBar({ label:'Network TX', value:resource.network_tx_mbps, max:networkMax, unit:' Mbps', secondaryText:'relative to current RX/TX max' })}
+
Resource composition
${renderDonutChart({ label:'System memory', used:resource.memory_used_mb, total:resource.memory_total_mb, unit:' MB' })}${renderDonutChart({ label:'GPU memory', used:resource.gpu_mem_used_mb, total:resource.gpu_mem_total_mb, unit:' MB' })}
+
Load metrics
${loadMetrics.length ? loadMetrics.map((metric) => `${escapeHtml(metric.label)}${escapeHtml(displayNumber(metric.value, 2))}${escapeHtml(metric.key)}`).join('') : 'No load metrics are exposed by the current Instance load snapshot.
'}
+
Detailed queue counters
${queues.length ? queues.map((q) => renderMetricBar({ label:q.label, value:q.value, max:maxQueue, unit:'', secondaryText:q.key })).join('') : 'No detailed queue counters are exposed by the current Instance load snapshot.
'}
+
Hardware
CPU
${escapeHtml(firstString(hw.cpu.model, hw.cpu.model_name, hw.cpu.name, instance.meta?.cpu_model) || 'No CPU details')}
${hw.cpu.cores || hw.cpu.logical_cpus ? `${escapeHtml(`cores ${hw.cpu.cores || '—'} · logical ${hw.cpu.logical_cpus || '—'}`)}` : ''}GPU
${hw.gpus.length ? hw.gpus.map((gpu, i) => `${escapeHtml(`#${gpu.index ?? i} ${gpuName(gpu) || 'GPU'}`)}${gpu.uuid ? ` · ${escapeHtml(gpu.uuid)}` : ''} · mem ${escapeHtml(displayNumber(gpu.memory_used_mb,0))}/${escapeHtml(displayNumber(gpu.memory_total_mb,0))} MB${gpu.memory_free_mb !== undefined ? ` · free ${escapeHtml(displayNumber(gpu.memory_free_mb,0))} MB` : ''} · util ${escapeHtml(displayNumber(gpuUtil(gpu),1))}%${gpu.temperature_c !== undefined ? ` · ${escapeHtml(displayNumber(gpu.temperature_c,1))}°C` : ''}${gpu.power_w !== undefined ? ` · ${escapeHtml(displayNumber(gpu.power_w,1))} W` : ''}
`).join('') : 'No GPU details
'}NIC
${hw.nics.length ? hw.nics.map((nic) => `${escapeHtml(nicName(nic) || 'NIC')}${nic.driver ? ` · ${escapeHtml(nic.driver)}` : ''}${nic.speed_mbps ? ` · ${escapeHtml(displayNumber(nic.speed_mbps,0))} Mbps` : (nic.speed ? ` · ${escapeHtml(nic.speed)}` : '')}${nic.rx_mbps !== undefined ? ` · RX ${escapeHtml(displayNumber(nic.rx_mbps,2))} Mbps` : ''}${nic.tx_mbps !== undefined ? ` · TX ${escapeHtml(displayNumber(nic.tx_mbps,2))} Mbps` : ''}
`).join('') : 'No NIC details
'}
+
Raw Instance JSON
${escapeHtml(stableJson(instance))}
+
`;
}
function renderTopology(payload) {
@@ -508,6 +772,7 @@ function renderRawPanels() {
['Proxy status', state.latest.status],
['Instances', state.latest.instances],
['Resources', state.latest.resources],
+ ['Loads', state.latest.loads],
['Topology', state.latest.topology],
['Scheduler', state.latest.scheduler],
];
@@ -639,16 +904,17 @@ async function refresh() {
}
}
- const [health, status, instances, resources, topology, scheduler] = await Promise.all([
+ const [health, status, instances, resources, loads, topology, scheduler] = await Promise.all([
settleJson('/api/proxy/healthz'),
settleJson('/api/proxy/status'),
settleJson('/api/proxy/instances?include_dead=true'),
settleJson('/api/proxy/resources?include_dead=true'),
+ settleJson('/api/proxy/loads', { optional: true }),
settleJson('/api/proxy/topology', { optional: true }),
settleJson('/api/scheduler/proxy', { optional: true }),
]);
- state.latest = { health, status, instances, resources, topology, scheduler };
+ state.latest = { health, status, instances, resources, loads, topology, scheduler };
pushHistory(Array.isArray(instances) ? instances : [], normalizeResources(resources), topology);
$('lastUpdated').textContent = `Last refresh: ${new Date().toLocaleTimeString()}`;
renderAll();
@@ -664,7 +930,7 @@ function restartTimer() {
function setTheme(theme) {
state.theme = theme;
document.documentElement.dataset.theme = theme;
- localStorage.setItem('proxy-ui-theme', theme);
+ if (typeof localStorage !== 'undefined') localStorage.setItem('proxy-ui-theme', theme);
$('themeBtn').textContent = theme === 'dark' ? 'Light theme' : 'Dark theme';
}
@@ -674,6 +940,7 @@ function setupEventHandlers() {
state.paused = !state.paused;
$('pauseBtn').textContent = state.paused ? 'Resume polling' : 'Pause polling';
$('pollingState').outerHTML = badge(state.paused ? 'Paused' : 'Polling', state.paused ? 'warn' : 'ok').replace('
activateTab(tab.dataset.tab));
});
document.addEventListener('click', (event) => {
- const card = event.target.closest('.instance-card[data-instance-id]');
+ const card = event.target.closest('.instance-card[data-instance-id], .topology-svg-node[data-instance-id]');
if (card) {
window.location.hash = `#/instances/${encodeURIComponent(card.dataset.instanceId)}`;
return;
@@ -734,6 +1001,13 @@ function setupEventHandlers() {
window.location.hash = '#/';
return;
}
+ const instanceCopy = event.target.closest('[data-instance-copy]');
+ if (instanceCopy) {
+ const instances = Array.isArray(state.latest.instances) ? state.latest.instances : [];
+ const selected = instances.find((item) => String(item.instance_id) === String(instanceCopy.dataset.instanceCopy));
+ copyText(stableJson(selected || {}));
+ return;
+ }
const copyButton = event.target.closest('[data-copy], [data-copy-key]');
if (!copyButton) {
return;
@@ -746,13 +1020,14 @@ function setupEventHandlers() {
'Proxy status': state.latest.status,
Instances: state.latest.instances,
Resources: state.latest.resources,
+ Loads: state.latest.loads,
Topology: state.latest.topology,
Scheduler: state.latest.scheduler,
};
copyText(stableJson(payloads[key] || state.latest));
});
document.addEventListener('keydown', (event) => {
- const card = event.target.closest?.('.instance-card[data-instance-id]');
+ const card = event.target.closest?.('.instance-card[data-instance-id], .topology-svg-node[data-instance-id]');
if (card && (event.key === 'Enter' || event.key === ' ')) {
event.preventDefault();
window.location.hash = `#/instances/${encodeURIComponent(card.dataset.instanceId)}`;
@@ -785,6 +1060,10 @@ async function copyText(text) {
}
}
-setTheme(state.theme);
-setupEventHandlers();
-refresh().then(restartTimer);
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = { buildTopologyModel, computeTopologyLayout, renderMetricBar, renderDonutChart, extractQueueMetrics, queueMetricsForInstance, computeMetrics, hasResourceReport, finiteNumber, clampPercent, percentOf, fmt, stateLabel, hardwareDetails, mergedInstanceLoad, applyPausedTopologyState, renderInstanceDetail, renderSystemTopology, state };
+} else {
+ setTheme(state.theme);
+ setupEventHandlers();
+ refresh().then(restartTimer);
+}
diff --git a/UI/proxy_ui/static/style.css b/UI/proxy_ui/static/style.css
index 546b6c6..ca77575 100644
--- a/UI/proxy_ui/static/style.css
+++ b/UI/proxy_ui/static/style.css
@@ -605,65 +605,225 @@ summary {
font-weight: 800;
}
+
+:root {
+ --topology-scheduler: var(--accent-2);
+ --topology-proxy: var(--accent);
+ --topology-instance: var(--ok);
+ --topology-link: color-mix(in srgb, var(--accent) 58%, var(--line));
+ --chart-free: color-mix(in srgb, var(--muted) 30%, transparent);
+}
+
.topology-diagram {
+ min-height: 360px;
+}
+
+.topology-scroll {
+ width: 100%;
+ overflow: auto;
+ border: 1px solid var(--line);
+ border-radius: 16px;
+ background: radial-gradient(circle at 50% 10%, color-mix(in srgb, var(--accent) 10%, transparent), transparent 24rem), var(--surface-2);
+}
+
+.topology-svg {
+ display: block;
+ width: 100%;
+ min-width: 720px;
+ height: auto;
+}
+
+.topology-link {
+ fill: none;
+ stroke: var(--topology-link);
+ stroke-width: 3;
+ stroke-linecap: round;
+ stroke-dasharray: 10 8;
+ animation: topology-flow 2.8s linear infinite;
+ opacity: 0.86;
+}
+
+.topology-link.inactive,
+.topology-link.unknown {
+ stroke: var(--muted);
+ stroke-dasharray: 4 8;
+ animation: none;
+ opacity: 0.48;
+}
+
+.topology-link.stale {
+ stroke: var(--bad);
+ animation: none;
+ opacity: 0.62;
+}
+
+.topology-diagram.paused .topology-link {
+ animation-play-state: paused;
+}
+
+@keyframes topology-flow {
+ to { stroke-dashoffset: -36; }
+}
+
+.topology-svg-node {
+ cursor: default;
+}
+
+.topology-svg-node[role='button'] {
+ cursor: pointer;
+}
+
+.topology-svg-node[role='button']:focus-visible .node-halo,
+.topology-svg-node[role='button']:hover .node-halo {
+ stroke-width: 4;
+ filter: drop-shadow(0 0 10px color-mix(in srgb, var(--accent) 70%, transparent));
+}
+
+.topology-svg-node .node-halo {
+ fill: var(--surface);
+ stroke: var(--line);
+ stroke-width: 2;
+}
+
+.topology-svg-node.scheduler .node-halo { stroke: var(--topology-scheduler); }
+.topology-svg-node.scheduler.ok .node-halo { stroke: var(--ok); }
+.topology-svg-node.scheduler.bad .node-halo { stroke: var(--bad); }
+.topology-svg-node.scheduler.warn .node-halo { stroke: var(--warn); }
+.topology-svg-node.scheduler.muted .node-halo { stroke: var(--muted); }
+.topology-svg-node.proxy .node-halo { stroke: var(--topology-proxy); }
+.topology-svg-node.proxy.bad .node-halo { stroke: var(--bad); }
+.topology-svg-node.proxy.warn .node-halo { stroke: var(--warn); }
+.topology-svg-node.instance.ok .node-halo { stroke: var(--topology-instance); }
+.topology-svg-node.instance.bad .node-halo { stroke: var(--bad); }
+.topology-svg-node.instance.warn .node-halo { stroke: var(--warn); }
+
+.topology-svg-node use {
+ fill: none;
+ stroke: currentColor;
+ stroke-width: 3;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+}
+
+.topology-svg-node.scheduler { color: var(--topology-scheduler); }
+.topology-svg-node.scheduler.ok { color: var(--ok); }
+.topology-svg-node.scheduler.bad { color: var(--bad); }
+.topology-svg-node.scheduler.warn { color: var(--warn); }
+.topology-svg-node.scheduler.muted { color: var(--muted); }
+.topology-svg-node.proxy { color: var(--topology-proxy); }
+.topology-svg-node.proxy.bad { color: var(--bad); }
+.topology-svg-node.proxy.warn { color: var(--warn); }
+.topology-svg-node.instance.ok { color: var(--topology-instance); }
+.topology-svg-node.instance.bad { color: var(--bad); }
+.topology-svg-node.instance.warn { color: var(--warn); }
+
+.node-label,
+.node-status {
+ fill: var(--text);
+ font-weight: 800;
+ font-size: 13px;
+ text-anchor: middle;
+}
+
+.node-status {
+ fill: var(--muted);
+ font-size: 11px;
+ font-weight: 700;
+}
+
+.kpi-grid {
display: grid;
- justify-items: center;
- gap: 8px;
- min-height: 260px;
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
+ gap: 12px;
+ margin-bottom: 14px;
}
-.topology-node {
- width: min(100%, 320px);
+.kpi-card,
+.donut-card,
+.hardware-grid article {
padding: 12px;
- text-align: center;
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: 14px;
}
-.topology-node strong,
-.topology-node span {
+.kpi-card span,
+.viz-metric small,
+.donut-card p,
+.hardware-grid small {
+ color: var(--muted);
+}
+
+.kpi-card strong {
display: block;
+ margin-top: 6px;
+ overflow-wrap: anywhere;
}
-.topology-node span {
- color: var(--muted);
- font-size: 12px;
+.viz-metric {
+ margin-top: 12px;
}
-.topology-node.proxy {
- border-color: color-mix(in srgb, var(--accent) 65%, var(--line));
+.viz-metric.bad .progress span { background: linear-gradient(90deg, var(--bad), var(--warn)); }
+
+.donut-grid,
+.hardware-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
+ gap: 12px;
}
-.topology-node.alive,
-.topology-node.ok {
- border-color: color-mix(in srgb, var(--ok) 65%, var(--line));
+.donut {
+ width: 150px;
+ max-width: 100%;
+ margin: 10px auto;
+ display: block;
}
-.topology-node.stale,
-.topology-node.bad {
- border-color: color-mix(in srgb, var(--bad) 65%, var(--line));
+.donut-free,
+.donut-used {
+ fill: none;
+ stroke-width: 5;
}
-.topology-node.warn,
-.topology-node.unknown {
- border-color: color-mix(in srgb, var(--warn) 65%, var(--line));
+.donut-free { stroke: var(--chart-free); }
+.donut-used {
+ stroke: var(--accent);
+ stroke-linecap: round;
+ transform: rotate(-90deg);
+ transform-origin: 50% 50%;
}
-.topology-edge {
- color: var(--muted);
+.donut text {
+ fill: var(--text);
+ font-size: 8px;
font-weight: 900;
+ text-anchor: middle;
}
-.topology-instances {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
- gap: 10px;
- width: 100%;
+.dot {
+ display: inline-block;
+ width: 9px;
+ height: 9px;
+ border-radius: 50%;
}
-.topology-instances .topology-node {
- width: 100%;
+.dot.used { background: var(--accent); }
+.dot.free { background: var(--chart-free); }
+
+.empty-state.compact {
+ padding: 14px;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .topology-link,
+ .progress span,
+ button,
+ .button-link,
+ .instance-card {
+ animation: none !important;
+ transition: none !important;
+ }
}
@media (max-width: 1200px) {
diff --git a/UI/proxy_ui/test_proxy_ui_pure.js b/UI/proxy_ui/test_proxy_ui_pure.js
new file mode 100644
index 0000000..5f4298b
--- /dev/null
+++ b/UI/proxy_ui/test_proxy_ui_pure.js
@@ -0,0 +1,177 @@
+const assert = require('assert');
+const ui = require('./static/app.js');
+
+function inst(id, alive, extra = {}) {
+ return {
+ instance_id: id,
+ host: '127.0.0.1',
+ port: 9000,
+ is_alive: alive,
+ registered_at: 1700000000,
+ last_seen_at: Date.now() / 1000,
+ load: { inflight: 2, qps_1m: 1.5, gpu_util: 30, ...(extra.load || {}) },
+ resource: { ...(extra.resource || {}) },
+ meta: { ...(extra.meta || {}) },
+ };
+}
+
+function testNullSemantics() {
+ const cases = [null, undefined, '', ' ', true, false, NaN, Infinity, -Infinity, [], [1], {}, new Date()];
+ for (const value of cases) assert.strictEqual(ui.finiteNumber(value), null, `expected null for ${String(value)}`);
+ assert.strictEqual(ui.finiteNumber(0), 0);
+ assert.strictEqual(ui.finiteNumber(-3), -3);
+ assert.strictEqual(ui.finiteNumber('0'), 0);
+ assert.strictEqual(ui.finiteNumber('42'), 42);
+ assert.strictEqual(ui.finiteNumber(' 42.5 '), 42.5);
+ assert.strictEqual(ui.fmt(null), '—');
+ assert.strictEqual(ui.percentOf('', 100), null);
+ assert(!ui.renderMetricBar({ label: 'null', value: null, max: 100 }).includes('0.00'));
+}
+
+
+function testComputeMetricsNullAverages() {
+ let metrics = ui.computeMetrics([
+ inst('missing', true, { resource: { cpu_util: null, gpu_util_avg: null, network_rx_mbps: null, network_tx_mbps: null, memory_used_mb: null, memory_total_mb: null } }),
+ inst('valid', true, { resource: { cpu_util: 80, gpu_util_avg: 60, network_rx_mbps: 10, network_tx_mbps: 5, memory_used_mb: 50, memory_total_mb: 100 } }),
+ ]);
+ assert.strictEqual(metrics.cpu, 80);
+ assert.strictEqual(metrics.gpu, 60);
+ assert.strictEqual(metrics.rx, 10);
+ assert.strictEqual(metrics.tx, 5);
+ assert.strictEqual(metrics.memory, 50);
+
+ metrics = ui.computeMetrics([
+ inst('all-null-a', true, { resource: { cpu_util: null, gpu_util_avg: null, network_rx_mbps: null, network_tx_mbps: null, memory_used_mb: null, memory_total_mb: null } }),
+ inst('all-null-b', true, { resource: { cpu_util: '', gpu_util_avg: undefined, network_rx_mbps: false, network_tx_mbps: {}, memory_used_mb: 1, memory_total_mb: 0 } }),
+ ]);
+ assert.strictEqual(metrics.cpu, null);
+ assert.strictEqual(metrics.gpu, null);
+ assert.strictEqual(metrics.rx, null);
+ assert.strictEqual(metrics.tx, null);
+ assert.strictEqual(metrics.memory, null);
+}
+
+function testHasResourceReport() {
+ assert.strictEqual(ui.hasResourceReport(inst('raw-empty', true, { resource: { raw_resource: {} } })), false);
+ assert.strictEqual(ui.hasResourceReport(inst('reported-null', true, { resource: { resource_reported_at: null, raw_resource: { devices: {} } } })), false);
+ assert.strictEqual(ui.hasResourceReport(inst('reported', true, { resource: { resource_reported_at: 1700000000, raw_resource: {} } })), true);
+ assert.strictEqual(ui.hasResourceReport(inst('scalar', true, { resource: { cpu_util: 0, resource_reported_at: null } })), true);
+ assert.strictEqual(ui.hasResourceReport(inst('unavailable', true, { resource: { cpu_util: null, memory_total_mb: '', gpu_util_avg: false, network_rx_mbps: {}, raw_resource: {} } })), false);
+}
+
+function testTopologyScenarios() {
+ let model = ui.buildTopologyModel([], { error: 'proxy_id_not_configured' }, { proxy_id: 'proxy-a' });
+ assert.strictEqual(model.instances.length, 0);
+ assert.strictEqual(model.links[0].status, 'inactive');
+
+ model = ui.buildTopologyModel([inst('one', true)], { ok: true }, { proxy_id: 'proxy-a', ok: true });
+ assert.strictEqual(model.links[0].status, 'active');
+ assert.strictEqual(model.links[1].status, 'active');
+ assert.strictEqual(model.nodes.find((n) => n.type === 'proxy').tone, 'ok');
+ assert.strictEqual(ui.stateLabel(model.instances[0]), 'alive');
+
+ model = ui.buildTopologyModel([inst('alive', true), inst('stale', false), inst('unknown', undefined)], { ok: true }, { ok: false });
+ assert.deepStrictEqual(model.instances.map((i) => i.instance_id), ['alive', 'stale', 'unknown']);
+ assert.deepStrictEqual(model.links.slice(1).map((l) => l.status), ['active', 'stale', 'unknown']);
+ assert.strictEqual(model.nodes.find((n) => n.type === 'proxy').tone, 'bad');
+
+ for (let count = 0; count <= 30; count += 1) {
+ const items = Array.from({ length: count }, (_, i) => inst(`node-${String(i).padStart(2, '0')}`, i % 2 === 0));
+ const layout = ui.computeTopologyLayout(ui.buildTopologyModel(items, { ok: true }, { ok: true }));
+ const nodePadding = layout.nodePadding;
+ const labelPadding = layout.labelPadding;
+ for (const pos of Object.values(layout.positions)) {
+ assert(pos.x - nodePadding >= 0, `count=${count} left bound`);
+ assert(pos.x + nodePadding <= layout.width, `count=${count} right bound`);
+ assert(pos.y - nodePadding >= 0, `count=${count} top bound`);
+ assert(pos.y + labelPadding <= layout.height, `count=${count} bottom bound`);
+ }
+ }
+ for (const count of [2, 3, 4, 5, 6, 7, 8]) {
+ const layout = ui.computeTopologyLayout(ui.buildTopologyModel(Array.from({ length: count }, (_, i) => inst(`arc-${i}`, true)), { ok: true }, {}));
+ assert(layout.height >= 360, `count=${count} height`);
+ }
+}
+
+function testMetricsAndMissingData() {
+ assert.strictEqual(ui.clampPercent(-5), 0);
+ assert.strictEqual(ui.clampPercent(105), 100);
+ assert.strictEqual(ui.clampPercent('bad'), null);
+ assert.strictEqual(ui.percentOf(5, 0), null);
+ assert.strictEqual(ui.percentOf(150, 100), 100);
+ assert(!ui.renderMetricBar({ label: 'Memory', value: 1, max: 0, unit: ' MB' }).includes('NaN'));
+ assert(ui.renderMetricBar({ label: 'GPU', value: undefined }).includes('No data'));
+ assert(ui.renderDonutChart({ label: 'GPU memory', used: undefined, total: undefined }).includes('No data'));
+ assert(ui.renderDonutChart({ label: 'Memory', used: 120, total: 100, unit: ' MB' }).includes('120'));
+}
+
+function testQueueExtractionAndLoadMerge() {
+ const loads = { ok: true, metric_source: { queue_depth: 'proxy_queue_manager' }, instances: [{ instance_id: 'known', inflight: null, qps_1m: '2.5', prepare_queue_depth: 3, ready_queue_depth: 4, active_prepare: 1, active_ready: 0, least_load_score: { total: 9.25 } }] };
+ const metrics = ui.queueMetricsForInstance(inst('known', true, { load: { inflight: null, qps_1m: null } }), loads);
+ assert(metrics.some((q) => q.key === 'prepare_queue_depth' && q.value === 3));
+ assert(metrics.some((q) => q.key === 'active_ready' && q.value === 0));
+ assert(!metrics.some((q) => q.key === 'least_load_score.total'));
+ assert(!metrics.some((q) => q.key === 'inflight'));
+ assert.deepStrictEqual(ui.queueMetricsForInstance(inst('only-load', true)).map((q) => q.key), []);
+
+ assert.deepStrictEqual(ui.extractQueueMetrics(inst('none', true)).map((q) => q.key), ['load.inflight']);
+ const nested = inst('nested', true, {
+ meta: { queues: { ready: 3, waiting: 2, port: 7000, decode_time_ms: 55, gpu_util: 90 } },
+ resource: { cpu_util: 70, memory_total_mb: 0 },
+ });
+ const keys = ui.extractQueueMetrics(nested).map((q) => q.key);
+ assert(keys.includes('meta.queues.ready'));
+ assert(keys.includes('meta.queues.waiting'));
+ assert(!keys.includes('meta.queues.port'));
+ assert(!keys.includes('meta.queues.decode_time_ms'));
+ assert(!keys.includes('resource.cpu_util'));
+}
+
+function withFakeDocument(elements, fn) {
+ const original = global.document;
+ global.document = { getElementById: (id) => elements[id] || null };
+ try { fn(); } finally { global.document = original; }
+}
+
+function testHardwareAndPausedDom() {
+ const panel = { classList: { add() {}, remove() {} }, innerHTML: '' };
+ const instance = inst('gpu-real', true, { resource: { raw_resource: { devices: { gpu: [{ index: 0, name: 'NVIDIA H100', uuid: 'GPU-1', utilization_pct: 77, memory_used_mb: 40960, memory_total_mb: 81920, memory_free_mb: 40960, temperature_c: 61, power_w: 350 }], network: [{ iface: 'eth0', rx_mbps: 12.5, tx_mbps: 7.25, speed_mbps: 100000 }] } } } });
+ ui.state.selectedInstanceId = 'gpu-real';
+ ui.state.latest.loads = { instances: [] };
+ withFakeDocument({ instanceDetailView: panel }, () => ui.renderInstanceDetail([instance]));
+ assert(panel.innerHTML.includes('NVIDIA H100'));
+ assert(panel.innerHTML.includes('40960/81920'));
+ assert(panel.innerHTML.includes('util 77%'));
+ assert(panel.innerHTML.includes('GPU-1'));
+ assert(panel.innerHTML.includes('61°C'));
+ assert(panel.innerHTML.includes('350 W'));
+ assert(panel.innerHTML.includes('eth0'));
+ assert(panel.innerHTML.includes('100000 Mbps'));
+ assert(panel.innerHTML.includes('No detailed queue counters are exposed by the current Instance load snapshot.'));
+
+ const container = { classList: { value: false, toggle(cls, on) { this.value = cls === 'paused' && on; } } };
+ ui.state.paused = true;
+ withFakeDocument({ systemTopology: container }, () => ui.applyPausedTopologyState());
+ assert.strictEqual(container.classList.value, true);
+ ui.state.paused = false;
+ withFakeDocument({ systemTopology: container }, () => ui.applyPausedTopologyState());
+ assert.strictEqual(container.classList.value, false);
+}
+
+function testThemeAndReducedMotionStaticHooks() {
+ const fs = require('fs');
+ const css = fs.readFileSync(require('path').join(__dirname, 'static/style.css'), 'utf8');
+ assert(css.includes("[data-theme='light']"));
+ assert(css.includes('@media (prefers-reduced-motion: reduce)'));
+ assert(css.includes('--topology-scheduler'));
+}
+
+testNullSemantics();
+testComputeMetricsNullAverages();
+testHasResourceReport();
+testTopologyScenarios();
+testMetricsAndMissingData();
+testQueueExtractionAndLoadMerge();
+testHardwareAndPausedDom();
+testThemeAndReducedMotionStaticHooks();
+console.log('proxy-ui pure function tests passed');