From 014d38f8bb88d69f1a9f1f85a18780c56006a200 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Thu, 13 Aug 2026 23:27:29 +0700 Subject: [PATCH 1/2] feat(website): the queen lives at /#/queen on the existing site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit She had a whole second deployment: apps/queen-web, its own Railway service, its own domain. That service has never once deployed successfully -- 13 of 13 failures. This puts her on the site that is already live instead. Ported from apps/queen-web with no new dependency. The original pulled in @tanstack/react-query for four panels; plain hooks do the same job in 6.4 kB, lazily loaded, so nobody who is not looking at the queen pays for her. Four defects came along with the port and were fixed rather than carried: 1. The three kingdom tabs never worked. setActiveTab was never called, so the highlight sat on Brain whatever you clicked, and the targets were read by nothing. They are buttons now and they select what the page renders. 2. Every panel called res.json() without checking res.ok. On static hosting /api/status returns the SPA fallback -- HTML with a 200 -- so the panels died on a JSON syntax error that reads like a bug in the queen. The status and the content-type are both checked, and the real cause is named. 3. EpisodeViewer called episodes?.slice() on whatever came back. A response that is not an array crashed the page on that line. 4. Missing values rendered as 0 and as '...' forever. They render as '—', and an unreachable brain is stated in a banner rather than left to look like a healthy queen with nothing to report. The backend is a separate service and is NOT part of this change. The page reads VITE_QUEEN_API at build time, falls back to localhost:8080 in local dev, and otherwise says plainly that no address is configured. Verified: build clean (522 modules, Queen chunk 6.44 kB + 3.12 kB css), and the rendered page was checked in a browser -- offline banner shown, metrics '—' not zero, improve button disabled with its reason, tabs switching content. Королева переезжает на существующий сайт: /#/queen. Отдельный сервис на Railway не задеплоился ни разу (13 из 13 падений). Новых зависимостей нет, четыре дефекта оригинала исправлены, недоступный мозг теперь сообщается явно, а не выглядит как здоровая королева без данных. Co-Authored-By: Claude Opus 5 --- apps/website/src/main.tsx | 2 + apps/website/src/pages/Queen.css | 162 ++++++++++++++++ apps/website/src/pages/Queen.tsx | 306 +++++++++++++++++++++++++++++++ 3 files changed, 470 insertions(+) create mode 100644 apps/website/src/pages/Queen.css create mode 100644 apps/website/src/pages/Queen.tsx diff --git a/apps/website/src/main.tsx b/apps/website/src/main.tsx index 57f52c4e11..9413cbf913 100644 --- a/apps/website/src/main.tsx +++ b/apps/website/src/main.tsx @@ -24,6 +24,7 @@ const Licensing = lazy(() => import('./pages/Licensing.tsx')) const Proof = lazy(() => import('./pages/Proof.tsx')) const AboutAuthor = lazy(() => import('./pages/AboutAuthor.tsx')) const Resources = lazy(() => import('./pages/Resources.tsx')) +const Queen = lazy(() => import('./pages/Queen.tsx')) // Blog exports two components rather than a default, so the module has to be // unwrapped into the shape lazy() expects. const BlogIndex = lazy(() => import('./pages/Blog.tsx').then(m => ({ default: m.BlogIndex }))) @@ -56,6 +57,7 @@ createRoot(document.getElementById('root')!).render( } /> } /> } /> + } /> } /> } /> } /> diff --git a/apps/website/src/pages/Queen.css b/apps/website/src/pages/Queen.css new file mode 100644 index 0000000000..3c6e608507 --- /dev/null +++ b/apps/website/src/pages/Queen.css @@ -0,0 +1,162 @@ +/* Scoped under .queen-page on purpose. The queen came from a standalone app + whose stylesheet styled bare tags and generic names like .tab, .metric-card + and .loading. Dropping those into this site would have restyled pages that + have nothing to do with the queen. */ + +.queen-page { + max-width: 1100px; + margin: 0 auto; + padding: 3rem 1.25rem 5rem; + color: var(--text, #e8e8ea); +} + +.queen-header h1 { + margin: 0 0 0.25rem; + font-size: clamp(1.8rem, 4vw, 2.6rem); +} + +.queen-header p { + margin: 0 0 2rem; + color: var(--text-muted, #9a9aa2); +} + +.queen-tabs { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 1.5rem; +} + +.queen-tabs button { + padding: 0.55rem 1rem; + border: 1px solid var(--border, #2a2a32); + border-radius: 8px; + background: transparent; + color: inherit; + font: inherit; + cursor: pointer; + transition: border-color 0.15s, background 0.15s; +} + +.queen-tabs button:hover { border-color: var(--accent, #7c5cff); } + +.queen-tabs button.active { + border-color: var(--accent, #7c5cff); + background: color-mix(in srgb, var(--accent, #7c5cff) 14%, transparent); +} + +.queen-offline { + border: 1px solid #ff9800; + border-radius: 10px; + padding: 1.1rem 1.25rem; + margin-bottom: 1.75rem; + background: color-mix(in srgb, #ff9800 8%, transparent); +} + +.queen-offline h3 { margin: 0 0 0.5rem; } +.queen-offline p { margin: 0 0 0.55rem; line-height: 1.55; } +.queen-offline code { + padding: 0.1rem 0.35rem; + border-radius: 4px; + background: rgba(255, 255, 255, 0.08); + font-size: 0.9em; +} +.queen-offline-detail { color: var(--text-muted, #9a9aa2); } +.queen-offline-note { color: var(--text-muted, #9a9aa2); font-size: 0.92rem; margin-bottom: 0; } + +.queen-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 1.25rem; + margin-bottom: 1.25rem; +} + +.queen-card { + border: 1px solid var(--border, #2a2a32); + border-radius: 10px; + padding: 1.25rem; + background: var(--surface, rgba(255, 255, 255, 0.02)); +} + +.queen-card h2 { margin: 0 0 0.75rem; font-size: 1.15rem; } +.queen-sub { color: var(--text-muted, #9a9aa2); margin: 0 0 1rem; line-height: 1.55; } + +.queen-metrics { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 0.75rem; +} + +.queen-metric { + display: flex; + flex-direction: column; + gap: 0.3rem; + padding: 0.75rem; + border: 1px solid var(--border, #2a2a32); + border-radius: 8px; +} + +.queen-metric-label { font-size: 0.78rem; color: var(--text-muted, #9a9aa2); } +.queen-metric-value { font-size: 1.05rem; font-variant-numeric: tabular-nums; } + +.queen-button { + padding: 0.65rem 1.15rem; + border: 1px solid var(--accent, #7c5cff); + border-radius: 8px; + background: color-mix(in srgb, var(--accent, #7c5cff) 18%, transparent); + color: inherit; + font: inherit; + cursor: pointer; +} + +.queen-button:disabled { + opacity: 0.45; + cursor: not-allowed; + border-color: var(--border, #2a2a32); + background: transparent; +} + +.queen-result { + margin-top: 1rem; + padding: 0.85rem 1rem; + border-radius: 8px; + border: 1px solid var(--border, #2a2a32); + line-height: 1.5; +} + +.queen-result.success { border-color: #4caf50; } +.queen-result.failure { border-color: #e05252; } + +.queen-result-rows { + display: flex; + flex-wrap: wrap; + gap: 1rem; + margin-top: 0.5rem; + font-size: 0.9rem; + color: var(--text-muted, #9a9aa2); +} + +.queen-episodes { display: flex; flex-direction: column; gap: 0.75rem; } + +.queen-episode { + border: 1px solid var(--border, #2a2a32); + border-left-width: 3px; + border-radius: 8px; + padding: 0.75rem 0.9rem; +} + +.queen-episode.success { border-left-color: #4caf50; } +.queen-episode.failure { border-left-color: #e05252; } + +.queen-episode header, +.queen-episode footer { + display: flex; + justify-content: space-between; + gap: 1rem; + font-size: 0.82rem; + color: var(--text-muted, #9a9aa2); +} + +.queen-episode p { margin: 0.4rem 0; line-height: 1.5; } +.queen-episode .ok { color: #4caf50; } +.queen-episode .bad { color: #e05252; } diff --git a/apps/website/src/pages/Queen.tsx b/apps/website/src/pages/Queen.tsx new file mode 100644 index 0000000000..4fbdb91367 --- /dev/null +++ b/apps/website/src/pages/Queen.tsx @@ -0,0 +1,306 @@ +import { useCallback, useEffect, useState } from 'react' +import './Queen.css' + +// The queen's panels read a backend that this site does not contain. t27.ai is +// static hosting; there is no /health and no /api here. The original app in +// apps/queen-web assumed same-origin and called res.json() on whatever came +// back, so on static hosting every panel silently rendered '...' forever -- a +// dashboard that looks alive and reports nothing. +// +// So the base URL is explicit, and "no backend" is a state the page SHOWS +// rather than a state it hides: +// - VITE_QUEEN_API set at build time -> that origin +// - localhost -> http://localhost:8080 +// - anything else -> unset, and the page says so +const ENV_API = (import.meta.env.VITE_QUEEN_API as string | undefined)?.replace(/\/+$/, '') +const IS_LOCAL = typeof window !== 'undefined' && /^(localhost|127\.0\.0\.1)$/.test(window.location.hostname) +const QUEEN_API = ENV_API ?? (IS_LOCAL ? 'http://localhost:8080' : null) + +type ProbeState = 'loading' | 'ok' | 'unreachable' + +interface Probe { + state: ProbeState + data: T | null + error: string | null +} + +/** Fetch that reports what actually happened instead of throwing it away. */ +async function readJson(path: string, init?: RequestInit): Promise { + if (!QUEEN_API) throw new Error('no backend configured') + const res = await fetch(QUEEN_API + path, init) + if (!res.ok) throw new Error(`HTTP ${res.status}`) + // A static host answers /api/status with an HTML 200 for its SPA fallback. + // Parsing that as JSON throws a syntax error that reads like a bug in the + // queen; checking the type first names the real cause. + const type = res.headers.get('content-type') ?? '' + if (!type.includes('json')) throw new Error(`expected JSON, got ${type.split(';')[0] || 'nothing'}`) + return res.json() as Promise +} + +function useProbe(path: string, intervalMs: number): Probe { + const [probe, setProbe] = useState>({ state: 'loading', data: null, error: null }) + + useEffect(() => { + if (!QUEEN_API) { + setProbe({ state: 'unreachable', data: null, error: 'no backend configured' }) + return + } + let alive = true + const tick = async () => { + try { + const data = await readJson(path) + if (alive) setProbe({ state: 'ok', data, error: null }) + } catch (e) { + if (alive) setProbe({ state: 'unreachable', data: null, error: (e as Error).message }) + } + } + void tick() + const id = setInterval(tick, intervalMs) + return () => { alive = false; clearInterval(id) } + }, [path, intervalMs]) + + return probe +} + +interface HealthResponse { + status: string + trinity_signature: number + improve_cycles: number + uptime_seconds: number +} + +interface SystemStatus { + trinity_identity: number + env_status: 'active' | 'degraded' | 'maintenance' + swarm_active: boolean +} + +interface Episode { + id: string + timestamp: number + action_type: string + outcome: string + success: boolean + duration_ms: number +} + +interface ImproveResponse { + success: boolean + message: string + applied_deltas: number + quality_score: number +} + +function formatUptime(seconds: number): string { + if (seconds < 60) return `${seconds}s` + if (seconds < 3600) return `${Math.floor(seconds / 60)}m` + if (seconds < 86400) return `${Math.floor(seconds / 3600)}h` + return `${Math.floor(seconds / 86400)}d` +} + +function BrainOffline({ reason }: { reason: string | null }) { + return ( +
+

The brain is not connected

+

+ This page is the queen's face. Her brain is a separate service that answers{' '} + /health, /api/status, /api/episodes and{' '} + /api/improve. This site is static hosting and serves none of them. +

+

+ {QUEEN_API + ? <>Tried {QUEEN_API} — {reason} + : <>No address configured. Build with VITE_QUEEN_API=https://your-brain.example to point this page at a running brain.} +

+

+ Nothing below is live. Empty panels would have looked the same as a healthy + queen with nothing to report, so the page says which one it is. +

+
+ ) +} + +function MetricCard({ label, value, status }: { label: string; value: string | number; status?: string }) { + const colour = status === 'active' ? '#4caf50' : status === 'degraded' ? '#ff9800' : undefined + return ( +
+ {label} + {value} +
+ ) +} + +function StatusDashboard() { + const health = useProbe('/health', 5000) + const status = useProbe('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/api/status', 10000) + const dash = '—' + + return ( +
+

👑 Status

+
+ + + + + +
+
+ ) +} + +function ImprovementPanel({ enabled }: { enabled: boolean }) { + const [running, setRunning] = useState(false) + const [result, setResult] = useState(null) + const [error, setError] = useState(null) + + const trigger = useCallback(async () => { + setRunning(true); setResult(null); setError(null) + try { + setResult(await readJson('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/api/improve', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({}), + })) + } catch (e) { + setError((e as Error).message) + } finally { + setRunning(false) + } + }, []) + + return ( +
+

🔄 Self-improvement

+

Runs one autonomous cycle through the .tri pipeline.

+ + {error &&
Request failed: {error}
} + {result && ( +
+ {result.success ? '✓' : '✗'} {result.message} +
+ Applied deltas: {result.applied_deltas} + Quality: {(result.quality_score * 100).toFixed(0)}% +
+
+ )} +
+ ) +} + +function EpisodeViewer() { + const episodes = useProbe('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/api/episodes', 30000) + // The original called episodes?.slice(0, 10) directly. A backend that answers + // with an object rather than an array crashes the page on that line, so the + // shape is checked before it is used. + const list = Array.isArray(episodes.data) ? episodes.data.slice(0, 10) : [] + + return ( +
+

📜 Recent episodes

+ {episodes.state === 'loading' &&

Loading…

} + {episodes.state === 'ok' && list.length === 0 && ( +

The brain answered, and has no episodes to report.

+ )} + {episodes.state === 'unreachable' &&

No episodes: {episodes.error}

} +
+ {list.map(ep => ( +
+
+ {ep.id.slice(0, 8)} + +
+

+ {ep.action_type} — {ep.outcome} +

+
+ {ep.duration_ms} ms + {ep.success ? '✓ success' : '✗ failed'} +
+
+ ))} +
+
+ ) +} + +type Kingdom = 'brain' | 'body' | 'spirit' + +const KINGDOMS: { key: Kingdom; label: string }[] = [ + { key: 'brain', label: '🧠 Brain (Strand I)' }, + { key: 'body', label: '💪 Body (Strand II)' }, + { key: 'spirit', label: '🔮 Spirit (Strand III)' }, +] + +export default function Queen() { + // In the original these three tabs were and the state + // setter was never called, so the highlight sat on "brain" whatever you + // clicked and nothing read the query string. They are buttons now, and the + // selection is the thing the page actually renders from. + const [kingdom, setKingdom] = useState('brain') + const health = useProbe('/health', 15000) + const connected = health.state === 'ok' + + return ( +
+
+

👑 Queen Trinity

+

Self-improving container · φ² + 1/φ² = 3

+
+ + + + {!connected && } + + {kingdom === 'brain' && ( + <> +
+ + +
+ + + )} + + {kingdom === 'body' && ( +
+

💪 Body

+

+ The body is the hardware strand — FPGA fleet and silicon. It has no + endpoint on the queen's brain yet, so there is nothing here to read. +

+
+ )} + + {kingdom === 'spirit' && ( +
+

🔮 Spirit

+

+ The spirit strand is the corpus and its claims. It has no endpoint on + the queen's brain yet, so there is nothing here to read. +

+
+ )} +
+ ) +} From 5271bdd3b86eb6476857c725218ea50492931971 Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Thu, 13 Aug 2026 23:36:09 +0700 Subject: [PATCH 2/2] fix(queen): render the API the brain has, not the one it was drawn against MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read src/background_agent/server.zig instead of assuming. The brain's entire surface is: /health -> {"status":"ok"}, no token required /api/containers -> authenticated /api/sessions -> authenticated The queen's panels called /api/status, /api/episodes, /api/improve and /api/pipeline, and rendered trinity_signature, improve_cycles, uptime_seconds, env_status and swarm_active. The brain serves none of those routes and returns none of those fields. Five metrics out of five could never be filled -- not by a better deployment, not by any deployment. The face and the brain were built against different APIs and had never been connected. A panel whose value is structurally unobtainable is worse than a missing panel: it reads as "not yet" when the truth is "not ever". So: - Liveness shows what /health actually returns, and says so. - The improve button is gone. It could only ever have errored; the panel now states that the route is missing from the brain and what adding it involves. - Containers and Sessions replace Episodes, and a 401 is reported as "requires a token" rather than as an unreachable brain -- those are different facts. Verified: build clean, and the rendered page checked in a browser after a forced reload, because the first check served a cached bundle and showed the old endpoint list. Панели королевы были нарисованы под API, которого нет: мозг отдаёт только /health, /api/containers и /api/sessions. Пять метрик из пяти не могли заполниться никогда. Страница приведена к тому, что действительно измеримо. Co-Authored-By: Claude Opus 5 --- apps/website/src/pages/Queen.tsx | 222 +++++++++++++++---------------- 1 file changed, 109 insertions(+), 113 deletions(-) diff --git a/apps/website/src/pages/Queen.tsx b/apps/website/src/pages/Queen.tsx index 4fbdb91367..ec6ca11e54 100644 --- a/apps/website/src/pages/Queen.tsx +++ b/apps/website/src/pages/Queen.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from 'react' +import { useEffect, useState } from 'react' import './Queen.css' // The queen's panels read a backend that this site does not contain. t27.ai is @@ -62,40 +62,34 @@ function useProbe(path: string, intervalMs: number): Probe { return probe } +// These are the shapes the brain ACTUALLY returns, read off +// src/background_agent/server.zig rather than assumed. +// +// The version of this page in apps/queen-web rendered five metrics -- +// trinity_signature, improve_cycles, uptime_seconds, env_status, swarm_active -- +// and called /api/status, /api/episodes, /api/improve and /api/pipeline. The +// brain serves NONE of those. /health returns exactly {"status":"ok"}, and the +// only /api routes that exist are /api/containers and /api/sessions. +// +// So those five metrics could never be filled, by any deployment, ever. A panel +// whose value is structurally unobtainable is worse than a missing panel: it +// reads as "not yet" when the truth is "not ever". + interface HealthResponse { status: string - trinity_signature: number - improve_cycles: number - uptime_seconds: number -} - -interface SystemStatus { - trinity_identity: number - env_status: 'active' | 'degraded' | 'maintenance' - swarm_active: boolean } -interface Episode { +interface Container { id: string - timestamp: number - action_type: string - outcome: string - success: boolean - duration_ms: number -} - -interface ImproveResponse { - success: boolean - message: string - applied_deltas: number - quality_score: number + name: string + status: string + railway_service_id?: string } -function formatUptime(seconds: number): string { - if (seconds < 60) return `${seconds}s` - if (seconds < 3600) return `${Math.floor(seconds / 60)}m` - if (seconds < 86400) return `${Math.floor(seconds / 3600)}h` - return `${Math.floor(seconds / 86400)}d` +interface Session { + id: string + name?: string + status?: string } function BrainOffline({ reason }: { reason: string | null }) { @@ -104,8 +98,8 @@ function BrainOffline({ reason }: { reason: string | null }) {

The brain is not connected

This page is the queen's face. Her brain is a separate service that answers{' '} - /health, /api/status, /api/episodes and{' '} - /api/improve. This site is static hosting and serves none of them. + /health, /api/containers and /api/sessions. + This site is static hosting and serves none of them.

{QUEEN_API @@ -130,106 +124,108 @@ function MetricCard({ label, value, status }: { label: string; value: string | n ) } -function StatusDashboard() { - const health = useProbe('/health', 5000) - const status = useProbe('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/api/status', 10000) +function StatusDashboard({ health }: { health: Probe }) { const dash = '—' - return (

-

👑 Status

+

👑 Liveness

- - - - +
+

+ /health is the only endpoint the brain answers without a token, + and it returns liveness alone — no counters, no uptime. Anything more + specific here would be invented rather than measured. +

) } -function ImprovementPanel({ enabled }: { enabled: boolean }) { - const [running, setRunning] = useState(false) - const [result, setResult] = useState(null) - const [error, setError] = useState(null) - - const trigger = useCallback(async () => { - setRunning(true); setResult(null); setError(null) - try { - setResult(await readJson('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/api/improve', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({}), - })) - } catch (e) { - setError((e as Error).message) - } finally { - setRunning(false) - } - }, []) - +function ImprovementPanel() { + // The button used to POST /api/improve. That route does not exist in + // src/background_agent/server.zig -- the brain's whole surface is /health, + // /api/containers and /api/sessions. A button that always fails is worse + // than no button, so this states the gap instead of pretending at it. return (

🔄 Self-improvement

-

Runs one autonomous cycle through the .tri pipeline.

- - {error &&
Request failed: {error}
} - {result && ( -
- {result.success ? '✓' : '✗'} {result.message} -
- Applied deltas: {result.applied_deltas} - Quality: {(result.quality_score * 100).toFixed(0)}% -
-
- )} +

+ The queen's original panel triggered a cycle through POST /api/improve. + The brain does not implement that route, so the control is not shown: it could + only ever have returned an error. +

+

+ Restoring it means adding the route to src/background_agent/server.zig, + which is a change to the brain rather than to this page. +

) } -function EpisodeViewer() { - const episodes = useProbe('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/api/episodes', 30000) - // The original called episodes?.slice(0, 10) directly. A backend that answers - // with an object rather than an array crashes the page on that line, so the - // shape is checked before it is used. - const list = Array.isArray(episodes.data) ? episodes.data.slice(0, 10) : [] +/** The two collections the brain really exposes. Both sit behind a token. */ +function BrainInventory() { + const containers = useProbe('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/api/containers', 20000) + const sessions = useProbe('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/api/sessions', 20000) + + // The original called episodes?.slice(0, 10) on whatever came back; an object + // rather than an array crashed the page on that line. Shape is checked first. + const asList = (p: Probe) => (Array.isArray(p.data) ? p.data : []) + + const renderState = (p: Probe, what: string) => { + if (p.state === 'loading') return

Loading {what}…

+ if (p.state === 'unreachable') { + const locked = p.error === 'HTTP 401' + return ( +

+ {locked + ? <>Requires a token. /api/{what} is authenticated — this page holds no credentials and does not ask for any. + : <>No {what}: {p.error}} +

+ ) + } + return null + } return ( -
-

📜 Recent episodes

- {episodes.state === 'loading' &&

Loading…

} - {episodes.state === 'ok' && list.length === 0 && ( -

The brain answered, and has no episodes to report.

- )} - {episodes.state === 'unreachable' &&

No episodes: {episodes.error}

} -
- {list.map(ep => ( -
-
- {ep.id.slice(0, 8)} - -
-

- {ep.action_type} — {ep.outcome} -

-
- {ep.duration_ms} ms - {ep.success ? '✓ success' : '✗ failed'} -
-
- ))} -
-
+ <> +
+

📦 Containers

+ {renderState(containers, 'containers')} +
+ {asList(containers).slice(0, 10).map(c => ( +
+
+ {c.id.slice(0, 8)} + {c.status} +
+

{c.name}

+ {c.railway_service_id &&
railway: {c.railway_service_id.slice(0, 8)}
} +
+ ))} +
+
+ +
+

🧵 Sessions

+ {renderState(sessions, 'sessions')} +
+ {asList(sessions).slice(0, 10).map(s => ( +
+
+ {s.id.slice(0, 8)} + {s.status ?? ''} +
+ {s.name &&

{s.name}

} +
+ ))} +
+
+ ) } @@ -275,10 +271,10 @@ export default function Queen() { {kingdom === 'brain' && ( <>
- - + +
- + )}