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
62 changes: 62 additions & 0 deletions app/scaling/components/Progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Card } from '../../components/ui/Card';
import { EmptyState } from '../../components/ui/EmptyState';
import { Text } from '../../components/ui/Text';
import type { WorkItem } from '../snapshot.mjs';
import { Info } from './Info';
import { Tag } from './Tag';

export function Progress({ work }: { work: WorkItem[] }) {
return (
<section className="flex flex-col gap-3">
<Text as="h2" variant="headline">Progress</Text>
{work.length === 0 ? (
<EmptyState description="No current work supplied for this snapshot." />
) : (
<Card className="divide-y divide-bds-gray-10 bg-background text-[13px] dark:divide-white/10 dark:bg-white/5">
{work.map((w) => <Row key={w.title} item={w} />)}
</Card>
)}
<Text variant="footnote" tone="muted">Expected effects are not summed.</Text>
</section>
);
}

function Row({ item: w }: { item: WorkItem }) {
const l = w.linear;
return (
<div className="flex flex-col gap-2 px-4 py-3">
<span className="flex flex-wrap items-center gap-2">
<Text as="span" variant="label">{w.title}</Text>
<Info label={`About ${w.title}`}>
<p>Hypothesis: {w.hypothesis}</p>
<p>Change: {w.change}</p>
<p>Owner: {w.owner ?? 'none assigned'}</p>
</Info>
<Tag tag={w.area} />
<Tag tag={l ? l.state : 'proposed'} />
</span>
{l ? (
<span className="flex items-center gap-2">
<span
role="progressbar"
aria-label={`${l.scopeDone} of ${l.scopeTotal} issues done`}
aria-valuemin={0}
aria-valuemax={l.scopeTotal}
aria-valuenow={l.scopeDone}
className="h-1.5 w-40 overflow-hidden rounded-full bg-bds-gray-10 dark:bg-white/10"
>
<span className="block h-full bg-base-blue" style={{ width: `${l.scopeTotal ? (100 * l.scopeDone) / l.scopeTotal : 0}%` }} />
</span>
<span className="font-mono text-[12px] text-bds-gray-60">{l.scopeDone}/{l.scopeTotal}</span>
</span>
) : null}
<p><span className="text-bds-gray-60">Expected:</span> {w.expected ?? 'Not estimated'}</p>
{w.evidence && w.realized ? <p><span className="text-bds-gray-60">Realized:</span> {w.realized}</p> : null}
<div className="flex flex-wrap gap-3">
{[w.evidence, l && { label: 'Linear', url: l.url }, ...w.links].map((link) => link ? (
<a key={link.url} className="w-fit underline" href={link.url} target="_blank" rel="noreferrer">{link.label}</a>
) : null)}
</div>
</div>
);
}
1 change: 1 addition & 0 deletions app/scaling/components/Tag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const LABEL: Record<string, string> = {
measured: 'Measured', modeled: 'Modeled', estimated: 'Estimated',
'not-measured': 'Not measured', 'not-modeled': 'Not modeled', 'not-established': 'Not established',
provisional: 'Provisional', unset: 'Unset',
da: 'DA', execution: 'Execution', state: 'State', networking: 'Networking',
};

export function Tag({ tag }: { tag: string }) {
Expand Down
20 changes: 20 additions & 0 deletions app/scaling/components/firstScreen.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { describe, expect, it } from 'vitest';
import type { Snapshot } from '../snapshot.mjs';
import { CeilingCards } from './CeilingCards';
import { Guardrails } from './Guardrails';
import { Progress } from './Progress';

// Synthetic data only: real snapshots are internal and never committed.
function fixture(): Snapshot {
Expand Down Expand Up @@ -48,3 +49,22 @@ describe('Guardrails', () => {
expect(rows[3]).not.toMatch(/bg-bds-(green|red)/);
});
});

describe('Progress', () => {
it('shows Linear state and a labelled bar when linked, and proposed with no bar otherwise', () => {
const [linked, proposed] = renderToStaticMarkup(<Progress work={fixture().work} />).split('px-4 py-3').slice(1);
expect(linked).toContain('>started<');
expect(linked).toContain('aria-label="4 of 10 issues done"');
expect(linked).toContain('width:40%');
expect(linked).toContain('Realized:');
expect(linked).toContain('href="https://example.com/synthetic/linear/project"');
expect(proposed).toContain('>proposed<');
expect(proposed).not.toContain('progressbar');
expect(proposed).not.toContain('Realized:');
});

it('hides realized without evidence', () => {
const [item] = fixture().work;
expect(renderToStaticMarkup(<Progress work={[{ ...item, evidence: null }]} />)).not.toContain('Realized:');
});
});
14 changes: 14 additions & 0 deletions app/scaling/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { fileURLToPath } from 'node:url';

import { renderToStaticMarkup } from 'react-dom/server';
import { expect, it, vi } from 'vitest';

import ScalingPage from './page';

it('collapses each detail section by default with its title and row count', async () => {
vi.stubEnv('SCALING_SNAPSHOT_PATH', fileURLToPath(new URL('./fixtures/synthetic.v2.json', import.meta.url)));
const html = renderToStaticMarkup(await ScalingPage());
expect(html).toMatch(/<details><summary[^>]*><h2[^>]*>Data availability<\/h2><span[^>]*> · 2 rows<\/span>/);
expect(html).not.toContain('<details open');
vi.unstubAllEnvs();
});
55 changes: 13 additions & 42 deletions app/scaling/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ 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';
import { Progress } from './components/Progress';
import { isStale, parseSnapshot, type Metric, type Snapshot } from './snapshot.mjs';

// The snapshot is a runtime file, so render per request rather than at build.
export const dynamic = 'force-dynamic';
Expand Down Expand Up @@ -73,13 +74,16 @@ export default async function ScalingPage() {
<CeilingCards ceilings={snapshot.ceilings} />
<Guardrails guardrails={snapshot.guardrails} />

<Progress work={snapshot.work} />

{snapshot.sections.map((section) => (
<section key={section.id} className="flex flex-col gap-3">
<div>
<Text as="h2" variant="headline">{section.title}</Text>
<Text variant="label.regular" tone="muted">{section.summary}</Text>
</div>
<Card className="divide-y divide-bds-gray-10 bg-background dark:divide-white/10 dark:bg-white/5">
<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">
Expand All @@ -91,27 +95,16 @@ export default async function ScalingPage() {
))}
</Card>
{section.gaps.length > 0 ? (
<div className="rounded-lg border border-dashed border-bds-gray-10 px-4 py-3 dark:border-white/10">
<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}
</section>
</details>
))}

<section className="flex flex-col gap-3">
<Text as="h2" variant="headline">What we&apos;re working on</Text>
{snapshot.work.length === 0 ? (
<EmptyState description="No current work supplied for this snapshot." />
) : (
<div className="grid grid-cols-1 gap-3 md:grid-cols-2">
{snapshot.work.map((w) => <WorkCard key={w.title} item={w} />)}
</div>
)}
</section>

<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>
Expand Down Expand Up @@ -160,28 +153,6 @@ function MetricDetails({ metric, snapshot }: { metric: Metric; snapshot: Snapsho
);
}

function WorkCard({ item }: { item: WorkItem }) {
const rows = [
['Hypothesis', item.hypothesis],
['Change', item.change],
['Expected impact', item.expected ?? 'Not estimated'],
['Realized impact', item.realized ?? 'Not measured'],
];
return (
<Card className="flex flex-col gap-2 bg-background p-4 text-[13px] dark:bg-white/5">
<Text variant="label">{item.title}</Text>
<Text variant="footnote" tone="muted">{item.status} · {item.owner ?? 'No owner assigned'}</Text>
{rows.map(([term, text]) => (
<p key={term}><span className="text-bds-gray-60">{term}:</span> {text}</p>
))}
<div className="flex flex-wrap gap-3">
{item.evidence ? <ExternalLink link={item.evidence} /> : null}
{item.links.map((l) => <ExternalLink key={l.url} link={l} />)}
</div>
</Card>
);
}

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