From ce8d9dfff7d6e6f88b2db7ae826e3934a09eec81 Mon Sep 17 00:00:00 2001 From: Francis Li Date: Fri, 16 Oct 2026 05:17:03 -0700 Subject: [PATCH] feat(scaling): ceiling cards and guardrails Co-authored-by: Toshi --- app/scaling/components/CeilingCards.tsx | 46 +++++++++++++++++ app/scaling/components/Guardrails.tsx | 57 +++++++++++++++++++++ app/scaling/components/Ladder.tsx | 4 +- app/scaling/components/Tag.tsx | 11 ++++ app/scaling/components/firstScreen.test.tsx | 50 ++++++++++++++++++ app/scaling/page.tsx | 4 ++ 6 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 app/scaling/components/CeilingCards.tsx create mode 100644 app/scaling/components/Guardrails.tsx create mode 100644 app/scaling/components/Tag.tsx create mode 100644 app/scaling/components/firstScreen.test.tsx diff --git a/app/scaling/components/CeilingCards.tsx b/app/scaling/components/CeilingCards.tsx new file mode 100644 index 0000000..8188204 --- /dev/null +++ b/app/scaling/components/CeilingCards.tsx @@ -0,0 +1,46 @@ +import Link from 'next/link'; + +import { Card } from '../../components/ui/Card'; +import { Text } from '../../components/ui/Text'; +import { deriveBinding, type Ceiling, type CeilingInput } from '../snapshot.mjs'; +import { Info } from './Info'; +import { Tag } from './Tag'; + +const AREAS: [Ceiling['area'], string][] = [['da', 'DA'], ['execution', 'Execution'], ['state', 'State'], ['networking', 'Networking']]; + +function input({ name, value, unit, status, asOf }: CeilingInput): string { + const shown = value === null ? status : `${value} ${unit}`.trim(); + return [name, shown, value === null ? null : status, asOf && new Date(asOf).toISOString().slice(0, 10)].filter(Boolean).join(' · '); +} + +export function CeilingCards({ ceilings }: { ceilings: Ceiling[] }) { + const binding = deriveBinding(ceilings); + return ( +
+ Ceilings by bottleneck · Mgas/s +
+ {AREAS.map(([area, name]) => { + const c = ceilings.find((x) => x.area === area)!; + return ( + + + {name} + {c.help} + + + {c.value === null ? '—' : c.value.toLocaleString('en-US', { maximumFractionDigits: 2 })} + + {c === binding ? Binding : null} + + {c.formula} + {c.reason ?

{c.reason}

: null} +
    + {c.inputs.map((i) =>
  • {input(i)}
  • )} +
+
+ ); + })} +
+
+ ); +} diff --git a/app/scaling/components/Guardrails.tsx b/app/scaling/components/Guardrails.tsx new file mode 100644 index 0000000..0a31143 --- /dev/null +++ b/app/scaling/components/Guardrails.tsx @@ -0,0 +1,57 @@ +import { cn } from '../../components/ui/cn'; +import { Card } from '../../components/ui/Card'; +import { Text } from '../../components/ui/Text'; +import type { Guardrail } from '../snapshot.mjs'; +import { Info } from './Info'; +import { Tag } from './Tag'; + +const TH = 'px-4 py-2 text-left text-[12px] font-[500] text-bds-gray-60'; +const TD = 'px-4 py-3 align-top'; +const DOT: Record = { ok: 'bg-bds-green-50', breached: 'bg-bds-red-50', unknown: 'bg-bds-gray-30' }; +const STATUS: Record = { ok: 'OK', breached: 'Breached', unknown: 'Unknown' }; + +const fmt = (n: number, unit: string) => `${n.toLocaleString('en-US', { maximumFractionDigits: 2 })} ${unit}`.trim(); + +export function Guardrails({ guardrails }: { guardrails: Guardrail[] }) { + return ( +
+ Guardrails + + + + + + + + + + + + {guardrails.map((g) => ( + + + + + + + ))} + +
GuardrailValueThresholdStatus
+ {g.label} {g.help} + {g.value === null ? '—' : fmt(g.value, g.unit)} + + {g.threshold === null ? '—' : `${g.comparator === '<=' ? '≤' : '≥'} ${fmt(g.threshold, g.unit)}`} + {g.thresholdTag === 'set' ? null : } + {g.owner ? {g.owner} : null} + + + + +
+
+ Breached SLOs are not attributed to saturation until triaged. +
+ ); +} diff --git a/app/scaling/components/Ladder.tsx b/app/scaling/components/Ladder.tsx index b436a87..3c0df49 100644 --- a/app/scaling/components/Ladder.tsx +++ b/app/scaling/components/Ladder.tsx @@ -6,13 +6,13 @@ import { cn } from '../../components/ui/cn'; import { Text } from '../../components/ui/Text'; import { deriveBinding, type Rung, type Snapshot } from '../snapshot.mjs'; import { Info } from './Info'; +import { Tag } from './Tag'; import { layoutRungs, type Anchor } from './ladderLayout'; const LABEL_PX = 150; const ROW = 44; const AXIS = 12; const AREA_NAME = { da: 'DA', execution: 'execution', state: 'state', networking: 'networking' }; -const TAG_LABEL: Record = { 'not-measured': 'Not measured', 'not-modeled': 'Not modeled', 'not-established': 'Not established' }; const ALIGN: Record = { start: 'items-start text-left', middle: 'items-center text-center', end: 'items-end text-right' }; const SHIFT: Record = { start: 'none', middle: 'translateX(-50%)', end: 'translateX(-100%)' }; @@ -95,7 +95,7 @@ export function Ladder(props: Props) { {all.filter((item) => !placed.has(item.id)).map((item) => (
  • {item.label} - {TAG_LABEL[item.tag] ?? item.tag} + {item.help}
  • ))} diff --git a/app/scaling/components/Tag.tsx b/app/scaling/components/Tag.tsx new file mode 100644 index 0000000..5fe623d --- /dev/null +++ b/app/scaling/components/Tag.tsx @@ -0,0 +1,11 @@ +const LABEL: Record = { + measured: 'Measured', modeled: 'Modeled', estimated: 'Estimated', + 'not-measured': 'Not measured', 'not-modeled': 'Not modeled', 'not-established': 'Not established', + provisional: 'Provisional', unset: 'Unset', +}; + +export function Tag({ tag }: { tag: string }) { + return ( + {LABEL[tag] ?? tag} + ); +} diff --git a/app/scaling/components/firstScreen.test.tsx b/app/scaling/components/firstScreen.test.tsx new file mode 100644 index 0000000..b7419e8 --- /dev/null +++ b/app/scaling/components/firstScreen.test.tsx @@ -0,0 +1,50 @@ +import { readFileSync } from 'node:fs'; + +import { renderToStaticMarkup } from 'react-dom/server'; +import { describe, expect, it } from 'vitest'; + +import type { Snapshot } from '../snapshot.mjs'; +import { CeilingCards } from './CeilingCards'; +import { Guardrails } from './Guardrails'; + +// Synthetic data only: real snapshots are internal and never committed. +function fixture(): Snapshot { + return JSON.parse(readFileSync(new URL('../fixtures/synthetic.v2.json', import.meta.url), 'utf8')); +} + +const cards = (html: string) => html.split(' { + it('renders every area in a fixed order with its tag, and badges the binding card', () => { + const html = cards(renderToStaticMarkup()); + expect(html.map((c) => c.match(/href="\/scaling\/(\w+)"/)![1])).toEqual(['da', 'execution', 'state', 'networking']); + expect(html.map((c) => c.match(/border-dashed[^>]*>([^<]+) c.includes('>Binding<'))).toEqual([true, false, false, false]); + }); + + it('moves the binding badge to a lower measured ceiling, and shows a dash, reason and pending inputs when there is no value', () => { + const { ceilings } = fixture(); + ceilings[1] = { ...ceilings[1], value: 90, tag: 'measured' }; + const html = cards(renderToStaticMarkup()); + expect(html.map((c) => c.includes('>Binding<'))).toEqual([false, true, false, false]); + expect(html[2]).toContain('>—<'); + expect(html[2]).toContain('live-state growth not measured'); + expect(html[2]).toContain('state_bytes_per_gas · pending'); + expect(html[2]).toContain('runway_years · 4 years · provisional · 2026-01-01'); + }); +}); + +describe('Guardrails', () => { + it('shows comparator and unit with the threshold, tags provisional and unset thresholds, and colors only known statuses', () => { + const rows = renderToStaticMarkup().split('Provisional<'); + expect(rows[2]).toContain('Synthetic owner'); + expect(rows[3]).toContain('>Unset<'); + expect(rows[3]).toContain('bg-bds-gray-30'); + expect(rows[3]).not.toMatch(/bg-bds-(green|red)/); + }); +}); diff --git a/app/scaling/page.tsx b/app/scaling/page.tsx index cf7600c..cb7caf3 100644 --- a/app/scaling/page.tsx +++ b/app/scaling/page.tsx @@ -6,6 +6,8 @@ import { Card } from '../components/ui/Card'; import { EmptyState } from '../components/ui/EmptyState'; import { Text } from '../components/ui/Text'; +import { CeilingCards } from './components/CeilingCards'; +import { Guardrails } from './components/Guardrails'; import { Ladder } from './components/Ladder'; import { isStale, parseSnapshot, type Metric, type Snapshot, type WorkItem } from './snapshot.mjs'; @@ -68,6 +70,8 @@ export default async function ScalingPage() { + + {snapshot.sections.map((section) => (