Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ jobs:
/internal-explorer/bundles/0x1 /api/internal-explorer/blocks \
/tips /tips/block/0x1 /tips/bundles/0x1 /api/tips/blocks \
/benchmark /benchmark/run/latest /benchmark/run-comparison/1 \
/benchmark/load-tests/sepolia /scaling /scaling/guardrails; do
/benchmark/load-tests/sepolia /scaling /scaling/da /scaling/guardrails; do
code=$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:3000${route}")
if [ "${code}" != "404" ]; then
echo "FAIL: ${route} returned ${code}, expected 404"
Expand Down
35 changes: 35 additions & 0 deletions app/scaling/[area]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { notFound } from 'next/navigation';

import { EmptyState } from '../../components/ui/EmptyState';
import { Text } from '../../components/ui/Text';
import { AREAS, CeilingCard } from '../components/CeilingCards';
import { SectionTable } from '../components/SectionTable';
import { Header, loadSnapshot, Unavailable } from '../loadSnapshot';

export const dynamic = 'force-dynamic';

export default async function ScalingAreaPage({ params }: { params: Promise<{ area: string }> }) {
const { area } = await params;
const entry = AREAS.find(([a]) => a === area);
if (!entry) notFound();
const loaded = await loadSnapshot();
if (loaded.kind !== 'ok') return <Unavailable loaded={loaded} />;

const { snapshot } = loaded;
const section = snapshot.sections.find((s) => s.id === area);
return (
<div className="flex flex-col gap-10 pb-8">
<Header loaded={loaded} title={`${entry[1]} · ${snapshot.network}`} crumb={entry[1]} />
<section className="flex flex-col gap-3">
<Text as="h2" variant="headline">Ceiling <span className="text-bds-gray-60">· Mgas/s</span></Text>
<CeilingCard area={entry[0]} ceilings={snapshot.ceilings} />
</section>
{section ? (
<SectionTable section={section} windows={snapshot.windows} />
) : (
<EmptyState title="No detailed metrics yet" description="This snapshot has no metrics for this area." />
)}
<EmptyState title="Related runs" description="Benchmark and load-test runs for this area land here later." />
</div>
);
}
48 changes: 25 additions & 23 deletions app/scaling/components/CeilingCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,43 @@ 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']];
export 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 (
<section className="flex flex-col gap-3">
<Text as="h2" variant="headline">Ceilings by bottleneck <span className="text-bds-gray-60">· Mgas/s</span></Text>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
{AREAS.map(([area, name]) => {
const c = ceilings.find((x) => x.area === area)!;
return (
<Card key={area} className="flex flex-col gap-2 bg-background p-4 text-[13px] dark:bg-white/5">
<span className="flex items-center gap-1">
<Link className="underline" href={`/scaling/${area}`}><Text as="span" variant="label">{name}</Text></Link>
<Info label={`About the ${name} ceiling`}>{c.help}</Info>
</span>
<span className="flex flex-wrap items-center gap-2">
<span className="font-mono text-[20px]">{c.value === null ? '—' : c.value.toLocaleString('en-US', { maximumFractionDigits: 2 })}</span>
<Tag tag={c.tag} />
{c === binding ? <span className="rounded-md bg-base-blue px-2 py-0.5 text-[12px] text-white">Binding</span> : null}
</span>
<code className="break-words font-mono text-[12px] text-bds-gray-60">{c.formula}</code>
{c.reason ? <p className="text-bds-gray-60">{c.reason}</p> : null}
<ul className="flex flex-col gap-0.5 text-[12px] text-bds-gray-60 empty:hidden">
{c.inputs.map((i) => <li key={i.name}>{input(i)}</li>)}
</ul>
</Card>
);
})}
{AREAS.map(([area]) => <CeilingCard key={area} area={area} ceilings={ceilings} />)}
</div>
</section>
);
}

export function CeilingCard({ area, ceilings }: { area: Ceiling['area']; ceilings: Ceiling[] }) {
const name = AREAS.find(([a]) => a === area)![1];
const c = ceilings.find((x) => x.area === area)!;
return (
<Card className="flex flex-col gap-2 bg-background p-4 text-[13px] dark:bg-white/5">
<span className="flex items-center gap-1">
<Link className="underline" href={`/scaling/${area}`}><Text as="span" variant="label">{name}</Text></Link>
<Info label={`About the ${name} ceiling`}>{c.help}</Info>
</span>
<span className="flex flex-wrap items-center gap-2">
<span className="font-mono text-[20px]">{c.value === null ? '—' : c.value.toLocaleString('en-US', { maximumFractionDigits: 2 })}</span>
<Tag tag={c.tag} />
{c === deriveBinding(ceilings) ? <span className="rounded-md bg-base-blue px-2 py-0.5 text-[12px] text-white">Binding</span> : null}
</span>
<code className="break-words font-mono text-[12px] text-bds-gray-60">{c.formula}</code>
{c.reason ? <p className="text-bds-gray-60">{c.reason}</p> : null}
<ul className="flex flex-col gap-0.5 text-[12px] text-bds-gray-60 empty:hidden">
{c.inputs.map((i) => <li key={i.name}>{input(i)}</li>)}
</ul>
</Card>
);
}
26 changes: 26 additions & 0 deletions app/scaling/fixtures/synthetic.v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,32 @@
],
"gaps": ["Confirmed drain"]
},
{
"id": "execution",
"title": "Execution",
"summary": "Synthetic block-building observations.",
"metrics": [
{
"label": "Block build time p90",
"status": "partial",
"value": 310,
"unit": "ms",
"window": "week",
"note": "Invented; sampled from one synthetic sequencer.",
"source": { "label": "Synthetic dashboard", "url": "https://example.com/synthetic/build-time" }
}
],
"gaps": []
},
{
"id": "state",
"title": "State",
"summary": "Synthetic state-size observations.",
"metrics": [
{ "label": "Live state growth", "status": "unavailable", "value": null, "unit": "GB/day", "window": "week", "note": "Synthetic query timed out." }
],
"gaps": ["Live state growth"]
},
{
"id": "outcomes",
"title": "User outcomes",
Expand Down
37 changes: 34 additions & 3 deletions app/scaling/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,48 @@ import { fileURLToPath } from 'node:url';
import { renderToStaticMarkup } from 'react-dom/server';
import { afterEach, beforeEach, expect, it, vi } from 'vitest';

import ScalingAreaPage from './[area]/page';
import fixture from './fixtures/synthetic.v2.json';
import ScalingGuardrailsPage from './guardrails/page';
import ScalingPage from './page';

beforeEach(() => vi.stubEnv('SCALING_SNAPSHOT_PATH', fileURLToPath(new URL('./fixtures/synthetic.v2.json', import.meta.url))));
afterEach(() => vi.unstubAllEnvs());

it('collapses each detail section by default with its title and row count', async () => {
const area = async (id: string) => renderToStaticMarkup(await ScalingAreaPage({ params: Promise.resolve({ area: id }) }));

it('links the first screen to five detail pages instead of listing metric rows', async () => {
const html = renderToStaticMarkup(await ScalingPage());
expect(html).toMatch(/<details><summary[^>]*><h2[^>]*>Data availability<\/h2><span[^>]*> · 2 rows<\/span>/);
expect(html).not.toContain('<details open');
for (const page of ['da', 'execution', 'state', 'networking', 'guardrails']) expect(html).toContain(`href="/scaling/${page}"`);
expect(html).not.toContain('Blob utilization');
});

it('shows every metric row on its detail page', async () => {
for (const section of fixture.sections) {
const html = section.id === 'outcomes' ? renderToStaticMarkup(await ScalingGuardrailsPage()) : await area(section.id);
for (const m of section.metrics) expect(html).toContain(m.label);
}
});

it('renders an area with breadcrumb, as-of header, ceiling, metric details, gaps and a runs slot', async () => {
const html = await area('da');
expect(html).toContain('href="/scaling">Scaling</a> / DA');
expect(html).toContain('As of 2026-01-02 00:00 UTC');
expect(html).toMatch(/>Ceiling <span[^>]*>· Mgas\/s<\/span>/);
expect(html).toContain('da_bytes_per_gas · 0.0055 bytes/gas · observed · 2026-01-02');
expect(html).toContain('synthetic.blob_utilization');
expect(html).toContain('<li>Confirmed drain</li>');
expect(html).toContain('Related runs');
});

it('shows the ceiling and an empty state for an area without metrics', async () => {
const html = await area('networking');
expect(html).toContain('gossip and peer limits unknown');
expect(html).toContain('No detailed metrics yet');
});

it('404s an unknown area', async () => {
await expect(area('bogus')).rejects.toMatchObject({ digest: 'NEXT_HTTP_ERROR_FALLBACK;404' });
});

it('links the first-screen guardrail strip to the guardrails page', async () => {
Expand Down
81 changes: 1 addition & 80 deletions app/scaling/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import Link from 'next/link';

import { Card } from '../components/ui/Card';
import { Text } from '../components/ui/Text';

import { CeilingCards } from './components/CeilingCards';
import { Guardrails } from './components/Guardrails';
import { Ladder } from './components/Ladder';
import { Progress } from './components/Progress';
import { formatTime, Header, loadSnapshot, Unavailable } from './loadSnapshot';
import type { Metric, Snapshot } from './snapshot.mjs';
import { Header, loadSnapshot, Unavailable } from './loadSnapshot';

// The snapshot is a runtime file, so render per request rather than at build.
export const dynamic = 'force-dynamic';
Expand All @@ -28,87 +26,10 @@ export default async function ScalingPage() {

<Progress work={snapshot.work} />

{snapshot.sections.map((section) => (
<details key={section.id}>
<summary className="cursor-pointer select-none">
<Text as="h2" variant="headline" className="inline">{section.title}</Text>
<Text as="span" variant="label.regular" tone="muted"> · {section.metrics.length} {section.metrics.length === 1 ? 'row' : 'rows'}</Text>
<Text as="span" variant="label.regular" tone="muted" className="block">{section.summary}</Text>
</summary>
<Card className="mt-3 divide-y divide-bds-gray-10 bg-background dark:divide-white/10 dark:bg-white/5">
{section.metrics.map((m) => (
<div key={m.label} className="flex flex-col gap-1 px-4 py-3">
<div className="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1">
<Text variant="label">{m.label}</Text>
<Value metric={m} />
</div>
<MetricDetails metric={m} snapshot={snapshot} />
</div>
))}
</Card>
{section.gaps.length > 0 ? (
<div className="mt-3 rounded-lg border border-dashed border-bds-gray-10 px-4 py-3 dark:border-white/10">
<Text variant="label" tone="muted">Missing evidence</Text>
<ul className="mt-1 list-disc pl-5 text-[13px] text-bds-gray-60">
{section.gaps.map((gap) => <li key={gap}>{gap}</li>)}
</ul>
</div>
) : null}
</details>
))}

<Text variant="label.regular" tone="muted">
Experiment results: <Link className="underline" href="/benchmark/run">Benchmarks</Link> ·{' '}
<Link className="underline" href="/benchmark/load-tests">Load tests</Link>
</Text>
</div>
);
}

const STATUS_LABEL: Record<string, string> = {
observed: '', partial: 'Partial', unavailable: 'Unavailable', 'not-measured': 'Not measured',
};

function Value({ metric }: { metric: Metric }) {
if (metric.value === null) {
return (
<span className="w-fit rounded-md border border-dashed border-bds-gray-40 px-2 py-0.5 text-[13px] text-bds-gray-60">
{STATUS_LABEL[metric.status]}
</span>
);
}
return (
<span className="flex items-baseline gap-2">
<Text as="span" variant="label.mono">
{metric.value.toLocaleString('en-US', { maximumFractionDigits: 2 })}
{metric.unit ? <span className="ml-1 text-bds-gray-60">{metric.unit}</span> : null}
</Text>
{metric.status === 'partial' ? <span className="text-[12px] text-bds-yellow-70">Partial</span> : null}
</span>
);
}

function MetricDetails({ metric, snapshot }: { metric: Metric; snapshot: Snapshot }) {
const window = metric.window ? snapshot.windows[metric.window] : null;
return (
<details className="text-[13px] text-bds-gray-60">
<summary className="cursor-pointer select-none">
{window ? `${window.label} · details` : metric.value === null ? 'No measurement yet · details' : 'Details'}
</summary>
<div className="mt-1 flex flex-col gap-1">
{window ? <p>{formatTime(window.start)} → {formatTime(window.end)}</p> : null}
<p>{metric.note}</p>
{metric.query ? <code className="break-all font-mono text-[12px]">{metric.query}</code> : null}
{metric.source ? <ExternalLink link={metric.source} /> : null}
</div>
</details>
);
}

function ExternalLink({ link }: { link: { label: string; url: string } }) {
return (
<a className="w-fit underline" href={link.url} target="_blank" rel="noreferrer">
{link.label}
</a>
);
}
Loading