Catastrophe Rate
Desired slope: downward as the policy learns permanence.
import React, { useEffect, useMemo, useState } from 'react';
import { CartesianGrid, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
import DecisionGraph from './DecisionGraph';
const API_URL = (() => {
// Prefer explicit override via ?api=... query param or env var
const q = new URLSearchParams(window.location.search);
const override = q.get('api');
if (override) return override.replace(/\/$/, '') + '/api/state';
// If the dashboard is served from an HF Space, connect to the same origin
if (window.location.hostname.endsWith('.hf.space')) {
return window.location.origin + '/api/state';
}
return 'http://localhost:5000/api/state';
})();
function normalizeRecentActions(actions = []) {
return actions
.map((action, index) => {
if (typeof action === 'string') {
return {
id: `${index}-${action}`,
label: action,
level: 'R2',
step: index + 1,
};
}
return {
id: `${index}-${action.action || action.action_id || 'action'}`,
label: action.action || action.action_id || 'unknown_action',
level: action.reversibility || action.level || `R${action.r_level ?? action.actual_r_level ?? 2}`,
step: action.step ?? index + 1,
};
})
.reverse();
}
function normalizeCatastropheSeries(raw = []) {
if (!Array.isArray(raw)) {
return [];
}
return raw.map((point, index) => {
if (typeof point === 'number') {
return { step: index + 1, catastrophe_rate: point };
}
if (typeof point === 'object' && point !== null) {
return {
step: point.step ?? index + 1,
catastrophe_rate: point.catastrophe_rate ?? point.value ?? 0,
};
}
return { step: index + 1, catastrophe_rate: 0 };
});
}
function normalizeLockedActions(rawLockedActions = {}) {
if (Array.isArray(rawLockedActions)) {
return Object.fromEntries(rawLockedActions.map((actionId) => [actionId, 'Locked by prior irreversible action']));
}
if (rawLockedActions && typeof rawLockedActions === 'object') {
return rawLockedActions;
}
return {};
}
function normalizeThinking(rawThinking) {
if (Array.isArray(rawThinking)) {
return rawThinking.map((entry) => String(entry)).filter(Boolean);
}
if (typeof rawThinking === 'string') {
return rawThinking
.split(/\r?\n+/)
.map((line) => line.trim())
.filter(Boolean);
}
if (rawThinking && typeof rawThinking === 'object') {
const values = Object.values(rawThinking)
.flatMap((value) => (Array.isArray(value) ? value : [value]))
.map((value) => String(value).trim())
.filter(Boolean);
return values;
}
return [];
}
function clamp(value, min, max) {
return Math.min(max, Math.max(min, value));
}
function TrustGauge({ catastropheSeries, lockedCount, recentThinking }) {
const latestCatastrophe = catastropheSeries.length ? catastropheSeries[catastropheSeries.length - 1].catastrophe_rate : 0;
const trustValue = clamp(Math.round(100 - latestCatastrophe * 72 - lockedCount * 1.7), 0, 100);
const flash = latestCatastrophe > 0.35 || lockedCount > 6;
const warning = trustValue < 55;
return (
Live reputation pressure from catastrophe spikes and action lockout. {recentThinking.length ? recentThinking[0] : 'Awaiting raw_thinking from the training loop...'} Streaming raw_thinking text from the live training process.Board Trust
Reasoning Ticker
PermanenceEnv Command Center
Tracking irreversible choices, option lockout, and catastrophe decay in real time.
Desired slope: downward as the policy learns permanence.