diff --git a/app/scaling/components/Progress.tsx b/app/scaling/components/Progress.tsx
new file mode 100644
index 0000000..15451ae
--- /dev/null
+++ b/app/scaling/components/Progress.tsx
@@ -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 (
+
+ Progress
+ {work.length === 0 ? (
+
+ ) : (
+
+ {work.map((w) =>
)}
+
+ )}
+ Expected effects are not summed.
+
+ );
+}
+
+function Row({ item: w }: { item: WorkItem }) {
+ const l = w.linear;
+ return (
+
+
+ {w.title}
+
+ Hypothesis: {w.hypothesis}
+ Change: {w.change}
+ Owner: {w.owner ?? 'none assigned'}
+
+
+
+
+ {l ? (
+
+
+
+
+ {l.scopeDone}/{l.scopeTotal}
+
+ ) : null}
+
Expected: {w.expected ?? 'Not estimated'}
+ {w.evidence && w.realized ?
Realized: {w.realized}
: null}
+
+ {[w.evidence, l && { label: 'Linear', url: l.url }, ...w.links].map((link) => link ? (
+
{link.label}
+ ) : null)}
+
+
+ );
+}
diff --git a/app/scaling/components/Tag.tsx b/app/scaling/components/Tag.tsx
index 5fe623d..cb83d08 100644
--- a/app/scaling/components/Tag.tsx
+++ b/app/scaling/components/Tag.tsx
@@ -2,6 +2,7 @@ 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',
+ da: 'DA', execution: 'Execution', state: 'State', networking: 'Networking',
};
export function Tag({ tag }: { tag: string }) {
diff --git a/app/scaling/components/firstScreen.test.tsx b/app/scaling/components/firstScreen.test.tsx
index b7419e8..5f95aa2 100644
--- a/app/scaling/components/firstScreen.test.tsx
+++ b/app/scaling/components/firstScreen.test.tsx
@@ -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 {
@@ -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().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()).not.toContain('Realized:');
+ });
+});
diff --git a/app/scaling/page.test.tsx b/app/scaling/page.test.tsx
new file mode 100644
index 0000000..75068a7
--- /dev/null
+++ b/app/scaling/page.test.tsx
@@ -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(/]*>]*>Data availability<\/h2>]*> · 2 rows<\/span>/);
+ expect(html).not.toContain('
+
+
{snapshot.sections.map((section) => (
-
-
- {section.title}
- {section.summary}
-
-
+
+
+ {section.title}
+ · {section.metrics.length} {section.metrics.length === 1 ? 'row' : 'rows'}
+ {section.summary}
+
+
{section.metrics.map((m) => (
@@ -91,27 +95,16 @@ export default async function ScalingPage() {
))}
{section.gaps.length > 0 ? (
-
+
Missing evidence
{section.gaps.map((gap) => - {gap}
)}
) : null}
-
+
))}
-
- What we're working on
- {snapshot.work.length === 0 ? (
-
- ) : (
-
- {snapshot.work.map((w) => )}
-
- )}
-
-
Experiment results: Benchmarks ·{' '}
Load tests
@@ -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 (
-
- {item.title}
- {item.status} · {item.owner ?? 'No owner assigned'}
- {rows.map(([term, text]) => (
- {term}: {text}
- ))}
-
- {item.evidence ? : null}
- {item.links.map((l) => )}
-
-
- );
-}
-
function ExternalLink({ link }: { link: { label: string; url: string } }) {
return (