From 2e7c72603301ce02b78ed256d5de7b7bff8ec7b4 Mon Sep 17 00:00:00 2001 From: Francis Li Date: Fri, 16 Oct 2026 06:58:52 -0700 Subject: [PATCH 1/2] feat(scaling): back ceilings and progress with runs Co-authored-by: Toshi --- app/scaling/[area]/page.tsx | 8 +- app/scaling/components/CeilingCards.tsx | 7 +- app/scaling/components/Ladder.tsx | 5 ++ app/scaling/components/Progress.tsx | 2 + app/scaling/components/RelatedRuns.tsx | 34 ++++++++ .../components/RunBackedCeilingCard.tsx | 41 +++++++++ app/scaling/components/RunEvidence.tsx | 28 ++++++ app/scaling/components/runBacked.test.tsx | 87 +++++++++++++++++++ app/scaling/runs/components/RunTable.tsx | 54 ++++++++++++ app/scaling/runs/lib/runIndex.ts | 19 ++++ app/scaling/runs/page.tsx | 67 +------------- app/scaling/snapshot.mjs | 10 ++- app/scaling/snapshot.test.ts | 10 +++ 13 files changed, 303 insertions(+), 69 deletions(-) create mode 100644 app/scaling/components/RelatedRuns.tsx create mode 100644 app/scaling/components/RunBackedCeilingCard.tsx create mode 100644 app/scaling/components/RunEvidence.tsx create mode 100644 app/scaling/components/runBacked.test.tsx create mode 100644 app/scaling/runs/components/RunTable.tsx create mode 100644 app/scaling/runs/lib/runIndex.ts diff --git a/app/scaling/[area]/page.tsx b/app/scaling/[area]/page.tsx index 1e7afbc..ec9f513 100644 --- a/app/scaling/[area]/page.tsx +++ b/app/scaling/[area]/page.tsx @@ -2,7 +2,9 @@ import { notFound } from 'next/navigation'; import { EmptyState } from '../../components/ui/EmptyState'; import { Text } from '../../components/ui/Text'; -import { AREAS, CeilingCard } from '../components/CeilingCards'; +import { AREAS } from '../components/CeilingCards'; +import { RelatedRuns } from '../components/RelatedRuns'; +import { RunBackedCeilingCard } from '../components/RunBackedCeilingCard'; import { SectionTable } from '../components/SectionTable'; import { Header, loadSnapshot, Unavailable } from '../loadSnapshot'; @@ -22,14 +24,14 @@ export default async function ScalingAreaPage({ params }: { params: Promise<{ ar
Ceiling · Mgas/s - +
{section ? ( ) : ( )} - + ); } diff --git a/app/scaling/components/CeilingCards.tsx b/app/scaling/components/CeilingCards.tsx index 15c1cdc..bbfbca4 100644 --- a/app/scaling/components/CeilingCards.tsx +++ b/app/scaling/components/CeilingCards.tsx @@ -2,8 +2,10 @@ import Link from 'next/link'; import { Card } from '../../components/ui/Card'; import { Text } from '../../components/ui/Text'; +import type { UnifiedRun } from '../runs/lib/unified'; import { deriveBinding, type Ceiling, type CeilingInput } from '../snapshot.mjs'; import { Info } from './Info'; +import { RunBackedCeilingCard } from './RunBackedCeilingCard'; import { Tag } from './Tag'; export const AREAS: [Ceiling['area'], string][] = [['da', 'DA'], ['execution', 'Execution'], ['state', 'State'], ['networking', 'Networking']]; @@ -18,13 +20,13 @@ export function CeilingCards({ ceilings }: { ceilings: Ceiling[] }) {
Ceilings by bottleneck · Mgas/s
- {AREAS.map(([area]) => )} + {AREAS.map(([area]) => )}
); } -export function CeilingCard({ area, ceilings }: { area: Ceiling['area']; ceilings: Ceiling[] }) { +export function CeilingCard({ area, ceilings, run }: { area: Ceiling['area']; ceilings: Ceiling[]; run?: UnifiedRun }) { const name = AREAS.find(([a]) => a === area)![1]; const c = ceilings.find((x) => x.area === area)!; return ( @@ -40,6 +42,7 @@ export function CeilingCard({ area, ceilings }: { area: Ceiling['area']; ceiling {c.formula} {c.reason ?

{c.reason}

: null} + {run ? Bench run {new Date(run.timestamp).toISOString().slice(0, 10)} → : null}
    {c.inputs.map((i) =>
  • {input(i)}
  • )}
diff --git a/app/scaling/components/Ladder.tsx b/app/scaling/components/Ladder.tsx index 3c0df49..93af702 100644 --- a/app/scaling/components/Ladder.tsx +++ b/app/scaling/components/Ladder.tsx @@ -100,6 +100,11 @@ export function Ladder(props: Props) { ))} + {props.ladder.qualified.evidence?.length ? ( + + Qualified sustained by {props.ladder.qualified.evidence.map((l) => {l.label})} + + ) : null} {translation(props.translations)} ); diff --git a/app/scaling/components/Progress.tsx b/app/scaling/components/Progress.tsx index 15451ae..fa37381 100644 --- a/app/scaling/components/Progress.tsx +++ b/app/scaling/components/Progress.tsx @@ -3,6 +3,7 @@ import { EmptyState } from '../../components/ui/EmptyState'; import { Text } from '../../components/ui/Text'; import type { WorkItem } from '../snapshot.mjs'; import { Info } from './Info'; +import { RunEvidence } from './RunEvidence'; import { Tag } from './Tag'; export function Progress({ work }: { work: WorkItem[] }) { @@ -52,6 +53,7 @@ function Row({ item: w }: { item: WorkItem }) { ) : null}

Expected: {w.expected ?? 'Not estimated'}

{w.evidence && w.realized ?

Realized: {w.realized}

: null} + {w.evidence ? : null}
{[w.evidence, l && { label: 'Linear', url: l.url }, ...w.links].map((link) => link ? ( {link.label} diff --git a/app/scaling/components/RelatedRuns.tsx b/app/scaling/components/RelatedRuns.tsx new file mode 100644 index 0000000..34e7d7a --- /dev/null +++ b/app/scaling/components/RelatedRuns.tsx @@ -0,0 +1,34 @@ +'use client'; + +import Link from 'next/link'; +import useSWR from 'swr'; + +import { EmptyState } from '../../components/ui/EmptyState'; +import { Text } from '../../components/ui/Text'; +import { RunTable } from '../runs/components/RunTable'; +import { loadRuns } from '../runs/lib/runIndex'; +import { weekOf } from '../runs/lib/unified'; +import type { Ceiling } from '../snapshot.mjs'; + +const PER_KIND = 5; + +export function RelatedRuns({ area }: { area: Ceiling['area'] }) { + const { data, error } = useSWR('scaling-runs', loadRuns); + const related = (data?.runs ?? []).filter((r) => (r.areas as string[]).includes(area)); + // Load tests run nightly and bench runs monthly, so cap each kind or bench runs never show. + const runs = (['bench', 'load'] as const).flatMap((k) => related.filter((r) => r.kind === k).slice(0, PER_KIND)).sort((a, b) => b.timestamp - a.timestamp); + return ( +
+ Related runs → + {error ? ( + + ) : !data ? ( + Loading runs… + ) : runs.length ? ( + weekOf(r.timestamp))} /> + ) : ( + + )} +
+ ); +} diff --git a/app/scaling/components/RunBackedCeilingCard.tsx b/app/scaling/components/RunBackedCeilingCard.tsx new file mode 100644 index 0000000..0881047 --- /dev/null +++ b/app/scaling/components/RunBackedCeilingCard.tsx @@ -0,0 +1,41 @@ +'use client'; + +import useSWR from 'swr'; + +import { getDataService } from '../runs/lib/dataService'; +import { getTestRunsWithStatus, type BenchmarkRuns, type BenchmarkRunWithStatus } from '../runs/lib/types'; +import { toUnifiedRun } from '../runs/lib/unified'; +import type { Ceiling } from '../snapshot.mjs'; +import { CeilingCard } from './CeilingCards'; + +const gps = (r: BenchmarkRunWithStatus) => r.result?.sequencerMetrics?.gasPerSecond ?? 0; + +// One benchmark run can test several configurations; its ceiling is the fastest one that passed. +function newestPassing(metadata: BenchmarkRuns): BenchmarkRunWithStatus | undefined { + const passing = getTestRunsWithStatus(metadata).filter((r) => r.status === 'success' && gps(r) > 0); + const newest = passing.toSorted((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt))[0]; + return newest && passing.filter((r) => r.testConfig.BenchmarkRun === newest.testConfig.BenchmarkRun).reduce((a, b) => (gps(b) > gps(a) ? b : a)); +} + +// No producer records state size yet, so a bench run can only estimate the execution ceiling. +const fromRun = (c: Ceiling, run: BenchmarkRunWithStatus): Ceiling => ({ + ...c, + value: gps(run) / 1e6, + tag: 'estimated', + formula: 'sequencer gas/s of the newest passing bench run', + inputs: [ + { name: 'bench_run', value: `${run.testConfig.BenchmarkRun}`, unit: '', asOf: run.createdAt, status: 'observed' }, + { name: 'state_size', value: null, unit: '', asOf: null, status: 'pending' }, + ], + reason: 'state size not recorded', +}); + +export function RunBackedCeilingCard({ area, ceilings }: { area: Ceiling['area']; ceilings: Ceiling[] }) { + const { data } = useSWR('scaling-bench-metadata', () => getDataService().getMetadata()); + const run = data && newestPassing(data); + const execution = ceilings.find((c) => c.area === 'execution')!; + // A measured or modeled snapshot value outranks a run-backed estimate; the snapshot is also the fallback without the API. + if (!run || execution.tag === 'measured' || execution.tag === 'modeled') return ; + const live = ceilings.map((c) => (c === execution ? fromRun(c, run) : c)); + return ; +} diff --git a/app/scaling/components/RunEvidence.tsx b/app/scaling/components/RunEvidence.tsx new file mode 100644 index 0000000..95f7726 --- /dev/null +++ b/app/scaling/components/RunEvidence.tsx @@ -0,0 +1,28 @@ +'use client'; + +import useSWR from 'swr'; + +import { Status } from '../runs/components/parts'; +import { getDataService } from '../runs/lib/dataService'; +import { getTestRunsWithStatus } from '../runs/lib/types'; +import { toUnifiedRun } from '../runs/lib/unified'; +import { RUN_PAGE } from '../snapshot.mjs'; + +export function RunEvidence({ url }: { url: string }) { + const [, id, network, timestamp] = url.match(RUN_PAGE) ?? []; + const { data: metadata } = useSWR(id ? 'scaling-bench-metadata' : null, () => getDataService().getMetadata()); + const { data: result } = useSWR(network ? ['scaling-load-result', network, timestamp] : null, () => getDataService().getLoadTestResult(network, timestamp)); + const runs = id + ? getTestRunsWithStatus({ runs: metadata?.runs.filter((r) => `${r.testConfig.BenchmarkRun}` === id) ?? [] }).map(toUnifiedRun) + : result ? [toUnifiedRun({ network, timestamp, result })] : []; + return ( + + {runs.map((r, i) => ( + + {r.gasPerSecond === null ? '—' : (r.gasPerSecond / 1e6).toFixed(1)} Mgas/s + + + ))} + + ); +} diff --git a/app/scaling/components/runBacked.test.tsx b/app/scaling/components/runBacked.test.tsx new file mode 100644 index 0000000..445a16e --- /dev/null +++ b/app/scaling/components/runBacked.test.tsx @@ -0,0 +1,87 @@ +import { readFileSync } from 'node:fs'; + +import { renderToStaticMarkup } from 'react-dom/server'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import runFixture from '../runs/fixtures/synthetic.json'; +import { getTestRunsWithStatus, type BenchmarkRuns } from '../runs/lib/types'; +import { toUnifiedRun, type LoadRun } from '../runs/lib/unified'; +import type { Snapshot } from '../snapshot.mjs'; +import { CeilingCards } from './CeilingCards'; +import { Ladder } from './Ladder'; +import { Progress } from './Progress'; +import { RelatedRuns } from './RelatedRuns'; + +// Synthetic data only: real snapshots and runs are internal and never committed. +const swr = vi.hoisted(() => ({ byKey: {} as Record })); +vi.mock('swr', () => ({ default: (key: unknown) => (key === null ? {} : swr.byKey[Array.isArray(key) ? key[0] : String(key)] ?? {}) })); + +const snapshot = (): Snapshot => JSON.parse(readFileSync(new URL('../fixtures/synthetic.v2.json', import.meta.url), 'utf8')); +const metadata = runFixture.metadata as BenchmarkRuns; +const [bench] = metadata.runs; +const cards = (html: string) => html.split('rounded-2xl').slice(1); + +beforeEach(() => { + swr.byKey = {}; +}); + +describe('execution ceiling', () => { + it('shows the newest passing bench run as an estimate with its reason and a link, without making it binding', () => { + const older = { ...bench, id: 'old', createdAt: '2025-11-01T00:00:00Z', testConfig: { ...bench.testConfig, BenchmarkRun: 'test-old' }, result: { ...bench.result!, sequencerMetrics: { ...bench.result!.sequencerMetrics!, gasPerSecond: 99e6 } } }; + const fasterConfig = { ...bench, outputDir: 'synthetic-1b', result: { ...bench.result!, sequencerMetrics: { ...bench.result!.sequencerMetrics!, gasPerSecond: 48e6 } } }; + swr.byKey['scaling-bench-metadata'] = { data: { runs: [older, bench, fasterConfig, metadata.runs[1]] } }; + const { ceilings } = snapshot(); + ceilings[0].value = 70; // DA modeled above the run's 48 Mgas/s. + const [da, execution] = cards(renderToStaticMarkup()); + expect(execution).toMatch(/>48<\/span>.*?>EstimatedBinding<'); + expect(da).toContain('>Binding<'); + }); + + it('falls back to the snapshot when the run API is unavailable', () => { + swr.byKey['scaling-bench-metadata'] = { error: new Error('not configured') }; + const [, execution] = cards(renderToStaticMarkup()); + expect(execution).toMatch(/>150<\/span>.*?>Estimated { + swr.byKey['scaling-bench-metadata'] = { data: metadata }; + const { ceilings } = snapshot(); + Object.assign(ceilings[1], { value: 60, tag: 'measured' }); + const [, execution] = cards(renderToStaticMarkup()); + expect(execution).toMatch(/>60<\/span>.*?>Measured<.*?>Binding { + const { ladder, ceilings, translations, windows } = snapshot(); + ladder.qualified = { ...ladder.qualified, value: 30, tag: 'measured', evidence: [{ label: 'Synthetic run', url: 'https://example.com/scaling/runs/bench/synthetic-1' }] }; + const html = renderToStaticMarkup(); + expect(html).toContain('Qualified sustained by Synthetic run'); +}); + +it('lists the newest runs of each kind covering an area', () => { + const nightly = Array.from({ length: 6 }, (_, i) => ({ network: 'sepolia', timestamp: `2026-02-0${i + 1}T00-00-00` })); + const runs = [...getTestRunsWithStatus(metadata), ...(runFixture.loadTests as unknown as LoadRun[]), ...nightly].map(toUnifiedRun).sort((a, b) => b.timestamp - a.timestamp); + swr.byKey['scaling-runs'] = { data: { runs, loadTotal: 3 } }; + const links = (area: 'execution' | 'da' | 'state') => [...renderToStaticMarkup().matchAll(/href="(\/scaling\/runs\/[^"]+)"/g)].map((m) => m[1]); + const newestLoads = runs.filter((r) => r.kind === 'load').slice(0, 5).map((r) => r.href); + expect(links('execution')).toEqual([...newestLoads, '/scaling/runs/bench/test-synthetic-1', '/scaling/runs/bench/test-synthetic-2']); + expect(links('da')).toEqual(newestLoads); + expect(links('state')).toEqual([]); +}); + +it('shows gas/s and status for evidence that points at a run page', () => { + swr.byKey['scaling-bench-metadata'] = { data: metadata }; + swr.byKey['scaling-load-result'] = { data: runFixture.loadTests[0].result }; + const [item] = snapshot().work; + const at = (url: string) => renderToStaticMarkup(); + expect(at('https://example.com/scaling/runs/bench/test-synthetic-1')).toMatch(/42\.0 Mgas\/s.*?success/); + expect(at('https://example.com/scaling/runs/load/sepolia/2026-01-08T00-00-01')).toMatch(/12\.5 Mgas\/s.*?success/); + expect(at('https://example.com/synthetic/doc')).not.toContain('Mgas/s'); +}); diff --git a/app/scaling/runs/components/RunTable.tsx b/app/scaling/runs/components/RunTable.tsx new file mode 100644 index 0000000..8e0ef19 --- /dev/null +++ b/app/scaling/runs/components/RunTable.tsx @@ -0,0 +1,54 @@ +import Link from 'next/link'; + +import { Card } from '../../../components/ui/Card'; +import { cn } from '../../../components/ui/cn'; +import { Info } from '../../components/Info'; +import { Tag } from '../../components/Tag'; +import { formatValue } from '../lib/formatters'; +import type { RunStatus } from '../lib/types'; +import type { UnifiedRun } from '../lib/unified'; + +const TH = 'px-3 py-2 text-left text-[12px] font-[500] text-bds-gray-60'; +const TD = 'px-3 py-2 align-top'; +const DOT: Record = { success: 'bg-bds-green-50', warning: 'bg-bds-yellow-50', error: 'bg-bds-red-50', fatal: 'bg-bds-red-50', incomplete: 'bg-bds-gray-30' }; + +export function RunTable({ weeks }: { weeks: Map }) { + return ( + + + + + {['When', 'Kind', 'Env', 'Profile', 'Workload', 'Mgas/s', 'Latency', 'Status', 'Duration', 'Machine'].map((h) => )} + + + {[...weeks].map(([week, rows]) => ( + + + {rows.map((r) => )} + + ))} +
{h}
Week of {week}
+
+ ); +} + +function Row({ run: r }: { run: UnifiedRun }) { + return ( + + {new Date(r.timestamp).toISOString().slice(0, 16).replace('T', ' ')} + + {r.env} + {r.profile ? : '—'}{r.qualifies.reason} + {r.workload} + {r.gasPerSecond === null ? '—' : (r.gasPerSecond / 1e6).toFixed(1)} + + {r.latency.length ? r.latency.map((l) =>
{l.label} {formatValue(l.seconds, 's')}
) : '—'} + + + + + {r.duration === null ? '—' : formatValue(r.duration, 's')} + {r.machine ?? '—'} + + ); +} diff --git a/app/scaling/runs/lib/runIndex.ts b/app/scaling/runs/lib/runIndex.ts new file mode 100644 index 0000000..0aa341f --- /dev/null +++ b/app/scaling/runs/lib/runIndex.ts @@ -0,0 +1,19 @@ +import { getDataService } from './dataService'; +import { getTestRunsWithStatus } from './types'; +import { toUnifiedRun } from './unified'; + +// report-api has no endpoint listing load-test networks. +export const NETWORK = 'sepolia'; +// One request per load-test result; nightly runs grow without bound. +export const LOAD_LIMIT = 30; + +export async function loadRuns() { + const api = getDataService(); + const [metadata, entries] = await Promise.all([api.getMetadata(), api.getLoadTestList(NETWORK)]); + const recent = entries.slice(0, LOAD_LIMIT); + // A missing result leaves that row's metrics unknown instead of failing the whole index. + const results = await Promise.all(recent.map((e) => api.getLoadTestResult(e.network, e.timestamp).catch(() => undefined))); + const runs = [...getTestRunsWithStatus(metadata), ...recent.map((e, i) => ({ ...e, result: results[i] }))].map(toUnifiedRun); + runs.sort((a, b) => b.timestamp - a.timestamp); + return { runs, loadTotal: entries.length }; +} diff --git a/app/scaling/runs/page.tsx b/app/scaling/runs/page.tsx index d406a48..6abf0ef 100644 --- a/app/scaling/runs/page.tsx +++ b/app/scaling/runs/page.tsx @@ -4,36 +4,12 @@ import Link from 'next/link'; import { useState, type ReactNode } from 'react'; import useSWR from 'swr'; -import { Card } from '../../components/ui/Card'; import { cn } from '../../components/ui/cn'; import { EmptyState } from '../../components/ui/EmptyState'; import { Text } from '../../components/ui/Text'; -import { Info } from '../components/Info'; -import { Tag } from '../components/Tag'; -import { getDataService } from './lib/dataService'; -import { formatValue } from './lib/formatters'; -import { getTestRunsWithStatus, type RunStatus } from './lib/types'; -import { toUnifiedRun, weekOf, type UnifiedRun } from './lib/unified'; - -// report-api has no endpoint listing load-test networks. -const NETWORK = 'sepolia'; -// One request per load-test result; nightly runs grow without bound. -const LOAD_LIMIT = 30; - -const TH = 'px-3 py-2 text-left text-[12px] font-[500] text-bds-gray-60'; -const TD = 'px-3 py-2 align-top'; -const DOT: Record = { success: 'bg-bds-green-50', warning: 'bg-bds-yellow-50', error: 'bg-bds-red-50', fatal: 'bg-bds-red-50', incomplete: 'bg-bds-gray-30' }; - -async function loadRuns() { - const api = getDataService(); - const [metadata, entries] = await Promise.all([api.getMetadata(), api.getLoadTestList(NETWORK)]); - const recent = entries.slice(0, LOAD_LIMIT); - // A missing result leaves that row's metrics unknown instead of failing the whole index. - const results = await Promise.all(recent.map((e) => api.getLoadTestResult(e.network, e.timestamp).catch(() => undefined))); - const runs = [...getTestRunsWithStatus(metadata), ...recent.map((e, i) => ({ ...e, result: results[i] }))].map(toUnifiedRun); - runs.sort((a, b) => b.timestamp - a.timestamp); - return { runs, loadTotal: entries.length }; -} +import { RunTable } from './components/RunTable'; +import { LOAD_LIMIT, loadRuns } from './lib/runIndex'; +import { weekOf, type UnifiedRun } from './lib/unified'; export default function RunsPage() { const { data, error } = useSWR('scaling-runs', loadRuns); @@ -64,47 +40,12 @@ export default function RunsPage() { ) : runs.length === 0 ? ( ) : ( - - - - - {['When', 'Kind', 'Env', 'Profile', 'Workload', 'Mgas/s', 'Latency', 'Status', 'Duration', 'Machine'].map((h) => )} - - - {[...weeks].map(([week, rows]) => ( - - - {rows.map((r) => )} - - ))} -
{h}
Week of {week}
-
+ )}
); } -function Row({ run: r }: { run: UnifiedRun }) { - return ( - - {new Date(r.timestamp).toISOString().slice(0, 16).replace('T', ' ')} - - {r.env} - {r.profile ? : '—'}{r.qualifies.reason} - {r.workload} - {r.gasPerSecond === null ? '—' : (r.gasPerSecond / 1e6).toFixed(1)} - - {r.latency.length ? r.latency.map((l) =>
{l.label} {formatValue(l.seconds, 's')}
) : '—'} - - - - - {r.duration === null ? '—' : formatValue(r.duration, 's')} - {r.machine ?? '—'} - - ); -} - function Chip({ on, onClick, children }: { on: boolean; onClick: () => void; children: ReactNode }) { const tone = on ? 'border-base-blue text-base-blue' : 'border-bds-gray-20 text-bds-gray-60'; return ; diff --git a/app/scaling/snapshot.mjs b/app/scaling/snapshot.mjs index 24c515f..4ab7fa9 100644 --- a/app/scaling/snapshot.mjs +++ b/app/scaling/snapshot.mjs @@ -16,7 +16,7 @@ * window: string | null, note: string, query?: string, source?: Link * }} Metric * @typedef {{ id: Area | 'outcomes', title: string, summary: string, metrics: Metric[], gaps: string[] }} Section - * @typedef {{ value: number | null, unit: 'Mgas/s', tag: Tag, window: string | null, source?: Link, help: string }} Rung + * @typedef {{ value: number | null, unit: 'Mgas/s', tag: Tag, window: string | null, source?: Link, evidence?: Link[], help: string }} Rung * @typedef {{ observed: { p50: Rung, p99: Rung }, operatingPoint: Rung, configuredLimit: Rung, qualified: Rung }} Ladder * @typedef {{ * name: string, value: number | string | null, unit: string, asOf: string | null, source?: Link, @@ -57,6 +57,8 @@ const AREAS = ['da', 'execution', 'state', 'networking']; const SECTION_IDS = [...AREAS, 'outcomes']; const INPUT_STATUSES = ['observed', 'configured', 'provisional', 'pending']; const DAY_MS = 86_400_000; +// Captures a bench run id, or a load test's network and timestamp. +export const RUN_PAGE = /^https:\/\/[^/]+\/scaling\/runs\/(?:bench\/([^/?#]+)|load\/([^/?#]+)\/([^/?#]+))/; const V1_MESSAGE = 'schemaVersion: 1 is no longer read; migrate to 2: replace headline with ladder, add ceilings, guardrails and ' + 'translations, and give each work entry area, expected, realized, evidence and linear'; @@ -138,6 +140,12 @@ export function parseSnapshot(data) { rung(observed.p50, 'ladder.observed.p50'); rung(observed.p99, 'ladder.observed.p99'); for (const key of ['operatingPoint', 'configuredLimit', 'qualified']) rung(ladder[key], `ladder.${key}`); + const qualified = ladder.qualified; + if (isObj(qualified) && (VALUED_TAGS.includes(qualified.tag) || qualified.evidence !== undefined)) { + const evidence = Array.isArray(qualified.evidence) ? qualified.evidence : []; + evidence.forEach((l, i) => link(l, `ladder.qualified.evidence[${i}]`)); + if (!evidence.length || !evidence.every((l) => RUN_PAGE.test(l?.url))) fail('ladder.qualified.evidence', 'a qualified value needs links to the run pages behind it'); + } const areas = new Set(); list(data, 'ceilings', 'snapshot').forEach((c, i) => { diff --git a/app/scaling/snapshot.test.ts b/app/scaling/snapshot.test.ts index 24cdd43..4fb54f5 100644 --- a/app/scaling/snapshot.test.ts +++ b/app/scaling/snapshot.test.ts @@ -102,6 +102,16 @@ describe('parseSnapshot', () => { data.windows.day.end = '2025-12-31T00:00:00Z'; expect(errorsOf(data)).toEqual(['windows.day: start must precede end']); }); + + it('accepts a qualified rung only with links to the run pages behind it', () => { + const data = fixture(); + Object.assign(data.ladder.qualified, { value: 30, tag: 'measured' }); + expect(errorsOf(data)).toEqual(['ladder.qualified.evidence: a qualified value needs links to the run pages behind it']); + data.ladder.qualified.evidence = [{ label: 'Synthetic doc', url: 'https://example.com/synthetic/doc' }]; + expect(errorsOf(data)).toEqual(['ladder.qualified.evidence: a qualified value needs links to the run pages behind it']); + data.ladder.qualified.evidence = [{ label: 'Synthetic run', url: 'https://example.com/scaling/runs/bench/synthetic-1' }]; + expect(errorsOf(data)).toEqual([]); + }); }); describe('deriveBinding', () => { From d7975383bcef259abbcddc8ff7d46743e02e28d2 Mon Sep 17 00:00:00 2001 From: Francis Li Date: Fri, 16 Oct 2026 07:03:04 -0700 Subject: [PATCH 2/2] Match run-page evidence links to the whole route Co-authored-by: Toshi --- app/scaling/snapshot.mjs | 2 +- app/scaling/snapshot.test.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/scaling/snapshot.mjs b/app/scaling/snapshot.mjs index 4ab7fa9..160c6cf 100644 --- a/app/scaling/snapshot.mjs +++ b/app/scaling/snapshot.mjs @@ -58,7 +58,7 @@ const SECTION_IDS = [...AREAS, 'outcomes']; const INPUT_STATUSES = ['observed', 'configured', 'provisional', 'pending']; const DAY_MS = 86_400_000; // Captures a bench run id, or a load test's network and timestamp. -export const RUN_PAGE = /^https:\/\/[^/]+\/scaling\/runs\/(?:bench\/([^/?#]+)|load\/([^/?#]+)\/([^/?#]+))/; +export const RUN_PAGE = /^https:\/\/[^/]+\/scaling\/runs\/(?:bench\/([^/?#]+)|load\/([^/?#]+)\/([^/?#]+))\/?(?:[?#].*)?$/; const V1_MESSAGE = 'schemaVersion: 1 is no longer read; migrate to 2: replace headline with ladder, add ceilings, guardrails and ' + 'translations, and give each work entry area, expected, realized, evidence and linear'; diff --git a/app/scaling/snapshot.test.ts b/app/scaling/snapshot.test.ts index 4fb54f5..cc0f824 100644 --- a/app/scaling/snapshot.test.ts +++ b/app/scaling/snapshot.test.ts @@ -109,6 +109,8 @@ describe('parseSnapshot', () => { expect(errorsOf(data)).toEqual(['ladder.qualified.evidence: a qualified value needs links to the run pages behind it']); data.ladder.qualified.evidence = [{ label: 'Synthetic doc', url: 'https://example.com/synthetic/doc' }]; expect(errorsOf(data)).toEqual(['ladder.qualified.evidence: a qualified value needs links to the run pages behind it']); + data.ladder.qualified.evidence = [{ label: 'Synthetic run', url: 'https://example.com/scaling/runs/bench/synthetic-1/not-a-page' }]; + expect(errorsOf(data)).toEqual(['ladder.qualified.evidence: a qualified value needs links to the run pages behind it']); data.ladder.qualified.evidence = [{ label: 'Synthetic run', url: 'https://example.com/scaling/runs/bench/synthetic-1' }]; expect(errorsOf(data)).toEqual([]); });