Live grid in controlled headless Chromium. Ten counterbalanced rounds; all fourteen scenarios run warm per mount, and the fixture is rebuilt after any failure so crashes cannot leak state. Every scenario must prove its effect (scroll really moved, editor really opened, rows really changed) or it fails.
-
Bright = median round, faded = p95 round. Did not complete = recorded crash, timeout, or failed checkpoint - never a timing.
+
Each measured sample repeats one logical action until it covers at least 100 ms of measured time, so timer resolution and scheduler jitter cannot decide a sample. Every raw sample is retained in the artifact.
+
Bright = median round, faded = p95 round. Did not complete = recorded crash, timeout, or failed checkpoint - never a timing. The failure table names the stage and the recorded error behind every missing cell.
scroll-down.top-left- From the origin, jump-scroll 50 px down: a fresh row band enters the viewport and must paint.
scroll-down.middle- The same 50 px jump starting from the vertical middle of the scroll range.
@@ -1065,35 +1087,15 @@ bun run --filter @sheetwrite/bench bench:formula
### Default and full formula engines
-Validated evidence. Eight shared workloads have 51 paired rounds per engine. The full engine also has eight checked analysis workloads.
+Validated evidence. Both engines ran the shared workload matrix. The paired-ratio capture is not published on this page yet, so no engine-to-engine ratio is claimed here.
-- Matched capture
- 2026-10-04 11:18 UTC
-- Matched commit
a50a897e9f93 clean worktree
- Analysis capture
- 2026-10-04 11:20 UTC
- Analysis commit
a50a897e9f93 clean worktree
-- Machine
- 12th Gen Intel(R) Core(TM) i9-12900H · Linux 7.2.8-1-cachyos · x64 · Bun 1.4.2
The default engine is `@sheetwrite/wasm`. The full engine is `@sheetwrite/formulas`. Select it with `initSheetwrite(undefined, formulas)`. Each app uses one engine.
-The first capture ran all 53 shared workloads on each engine in sequence. Eight rows were more than 5% slower with the full engine. We checked those eight rows with matched rounds. Each pair runs default, then full. Each timed sample uses a fresh Bun process and one untimed warmup fixture. The runner used CPU 4 and one concurrent capture.
-
-No shared workload tested in the matched rounds had a median paired ratio more than 5% slower with the full engine. This check covers the eight flagged rows, not a new matched run of all 53 rows.
-
-The ratio is full time divided by default time within each pair. The table shows the median of 51 paired ratios. The spread is the interpolated 10th to 90th percentile of those ratios. It is not a confidence interval. The time columns are the median times for each engine. A ratio below 1 means the full engine took less time. Wide spreads and very short operations limit what this sample can show.
-
-| Shared workload | Size | Default median ms | Full median ms | Paired median ratio | Ratio p10–p90 |
-| --- | ---: | ---: | ---: | ---: | ---: |
-| independent-parse-load | 1,000 | 2.0895 | 2.6377 | 1.0149 | 0.3786–3.5129 |
-| independent-first-recompute | 1,000 | 0.7200 | 0.7008 | 0.9939 | 0.2959–2.3024 |
-| independent-parse-load | 10,000 | 13.4585 | 13.8707 | 1.0095 | 0.8935–1.1378 |
-| independent-first-recompute | 10,000 | 26.5895 | 26.3255 | 0.9859 | 0.9088–1.0561 |
-| linear-chain | 8 | 0.1210 | 0.1215 | 1.0113 | 0.9194–1.1899 |
-| wide-fan-out-edit | 1,000 | 0.4538 | 0.4473 | 0.9849 | 0.8534–1.1019 |
-| scalar-edit-affects-0 | 1,000 | 0.0107 | 0.0107 | 0.9957 | 0.8127–1.2054 |
-| vlookup-many | 1,000 | 5.7530 | 5.5446 | 0.9398 | 0.7541–1.4022 |
-
#### Analysis workloads
Each workload has 1,000 formulas. It has one untimed warmup and five measured samples. Each sample uses a fresh store. The timer measures first recompute. Setup and output reads are outside the timer. Every result is read and summed as a checked checksum. The default engine does not run these analysis functions.
@@ -1358,3 +1360,13 @@ The landing-page data comes from a separate browser benchmark. The Delivery size
+
+## Pending local evidence
+
+These protocols have no validated artifact in this environment yet, so no numbers are published for them.
+
+| Artifact | Status | Reproduce with |
+| --- | --- | --- |
+| `bench/results/core-paths-results.json` | artifact is missing | `bun run --filter @sheetwrite/bench bench:core-paths` |
+| `bench/results/full-engine-matched-results.json` | Matched engine evidence is invalid: Matched engine protocol mismatch | `bun run --filter @sheetwrite/bench bench:formula:matched` |
+| `bench/results/xlsx-results.json` | artifact has no clean-tree protocol stamp (commit, timestamp, dirty=false), so freshness cannot be established | `bun run --filter @sheetwrite/bench bench:xlsx -- --baseline-root ` |
diff --git a/docs/src/styles/site.css b/docs/src/styles/site.css
index 5940c420..558f0a67 100644
--- a/docs/src/styles/site.css
+++ b/docs/src/styles/site.css
@@ -1561,7 +1561,8 @@ body .sw-code-popover__accessible-signature {
/* Evidence page callouts. */
.evidence-available,
-.evidence-unavailable {
+.evidence-unavailable,
+.evidence-mixed {
margin: 0 0 1.2rem;
border: 1px solid color-mix(in srgb, var(--sw-accent) 30%, var(--sw-border));
border-radius: 0.55rem;
@@ -1576,6 +1577,12 @@ body .sw-code-popover__accessible-signature {
color: var(--sw-fg-muted);
}
+/* Capture vintages differ: a caution tone, not the "validated" accent. */
+.evidence-mixed {
+ border-color: color-mix(in srgb, var(--sw-state-pending) 45%, var(--sw-border));
+ background: color-mix(in srgb, var(--sw-state-pending) 6%, var(--sw-surface-1));
+}
+
.error-catalog {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
diff --git a/scripts/docs.ts b/scripts/docs.ts
index 1d2b28a3..cc633f20 100644
--- a/scripts/docs.ts
+++ b/scripts/docs.ts
@@ -1310,6 +1310,10 @@ interface RenderEvidenceResult {
madMs: number;
memory: { beforeBytes: number; afterBytes: number; deltaBytes: number };
validation: Array<{ passed: boolean }>;
+ /** Recorded only on failures: where the scenario stopped and what it reported. */
+ stage?: string;
+ errorClass?: string;
+ message?: string;
}
interface ValidatedRenderEvidence {
@@ -1530,6 +1534,120 @@ function validateRenderArtifact(value: Record): ValidatedRender
return artifact as ValidatedRenderEvidence;
}
+interface CorePathsEvidence {
+ schemaVersion: number;
+ protocol: string;
+ mode: string;
+ metadata: CaptureMeta;
+ toolchain: { bun: string; nodeCompat: string; cpu: string };
+ methodology: { timing: string; scope: string };
+ scale: Record;
+ scenarios: Array<{
+ id: string;
+ unit: string;
+ samplesMs: number[];
+ timing: { median: number; p95: number; iters: number };
+ counters: Record;
+ observations?: Record;
+ variants?: Array<{
+ id: string;
+ samplesMs: number[];
+ timing: { median: number; p95: number; iters: number };
+ }>;
+ validation: string;
+ }>;
+}
+
+/**
+ * Full-mode core-path capture. The artifact is written by `bench:core-paths`;
+ * only a complete scenario matrix with finite timings and a written validation
+ * checkpoint per scenario is publishable.
+ */
+function validateCorePathsArtifact(value: Record): CorePathsEvidence | string {
+ const artifact = value as unknown as Partial;
+ if (
+ artifact.schemaVersion !== 1 ||
+ artifact.protocol !== "sheetwrite-core-paths-v1" ||
+ artifact.mode !== "full"
+ ) {
+ return "artifact is not a full-mode core-path capture";
+ }
+ if (!Array.isArray(artifact.scenarios) || artifact.scenarios.length === 0) {
+ return "artifact carries no core-path scenarios";
+ }
+ for (const scenario of artifact.scenarios) {
+ const timings = [scenario.timing, ...(scenario.variants ?? []).map((entry) => entry.timing)];
+ if (
+ typeof scenario.unit !== "string" ||
+ scenario.unit.length === 0 ||
+ typeof scenario.validation !== "string" ||
+ scenario.validation.length === 0 ||
+ timings.some(
+ (timing) =>
+ !Number.isFinite(timing?.median) ||
+ !Number.isFinite(timing?.p95) ||
+ !Number.isInteger(timing?.iters) ||
+ timing.iters < 1,
+ )
+ ) {
+ return "core-path scenarios carry an unvalidated or non-finite timing";
+ }
+ }
+ return artifact as CorePathsEvidence;
+}
+
+interface XlsxEvidence {
+ protocol: string;
+ mode: string;
+ metadata: CaptureMeta;
+ rounds: number;
+ maxBaselineRatio: number;
+ fixture: { path: string; bytes: number; sha256: string; producer: string };
+ toolchain: { bun: string; node: string; cpu: string; baselineCommit?: string };
+ summaries: Array<{
+ engine: string;
+ operation: string;
+ scenario: string;
+ durationMs: { median: number; p95: number; iters: number };
+ maxRssBytes: { median: number; p95: number; max: number };
+ }>;
+ comparisons: Array<{
+ operation: string;
+ scenario: string;
+ medianWallRatio: number;
+ peakRssRatio: number;
+ }>;
+}
+
+function validateXlsxArtifact(value: Record): XlsxEvidence | string {
+ const artifact = value as unknown as Partial;
+ if (artifact.protocol !== "sheetwrite-xlsx-codec-v1" || artifact.mode !== "full") {
+ return "artifact is not a full-mode XLSX codec capture";
+ }
+ const rounds = artifact.rounds;
+ if (
+ typeof rounds !== "number" ||
+ !Number.isInteger(rounds) ||
+ rounds < 1 ||
+ !Array.isArray(artifact.summaries) ||
+ artifact.summaries.length === 0 ||
+ !Array.isArray(artifact.comparisons)
+ ) {
+ return "XLSX capture is missing its rounds, summaries, or comparisons";
+ }
+ if (
+ artifact.summaries.some(
+ (summary) =>
+ !Number.isFinite(summary?.durationMs?.median) ||
+ !Number.isFinite(summary?.durationMs?.p95) ||
+ !Number.isFinite(summary?.maxRssBytes?.max),
+ )
+ ) {
+ return "XLSX summaries carry non-finite samples";
+ }
+ return artifact as XlsxEvidence;
+}
+
interface DataEvidence {
protocolVersion: number;
mode: string;
@@ -1775,7 +1893,8 @@ const RENDER_METHOD = benchMethod(
"Methodology - what each scenario does",
[
"Live grid in controlled headless Chromium. Ten counterbalanced rounds; all fourteen scenarios run warm per mount, and the fixture is rebuilt after any failure so crashes cannot leak state. Every scenario must prove its effect (scroll really moved, editor really opened, rows really changed) or it fails.",
- "Bright = median round, faded = p95 round. Did not complete = recorded crash, timeout, or failed checkpoint - never a timing.",
+ "Each measured sample repeats one logical action until it covers at least 100 ms of measured time, so timer resolution and scheduler jitter cannot decide a sample. Every raw sample is retained in the artifact.",
+ "Bright = median round, faded = p95 round. Did not complete = recorded crash, timeout, or failed checkpoint - never a timing. The failure table names the stage and the recorded error behind every missing cell.",
],
[
[
@@ -2020,6 +2139,265 @@ export function runCompletionSummary(results: ReadonlyArray<{ status: string }>)
return { successes, total: results.length, failures: results.length - successes };
}
+/** One validated artifact that the page publishes numbers from. */
+interface EvidenceCapture {
+ readonly label: string;
+ readonly source: string;
+ readonly meta: CaptureMeta;
+}
+
+/** Every loaded artifact states its capture stamp as either `meta` or `metadata`. */
+type CapturedEvidence =
+ | { evidence: { meta?: CaptureMeta; metadata?: CaptureMeta }; source: string }
+ | EvidenceState;
+
+function formatCaptureTime(timestamp: string): string {
+ return timestamp.slice(0, 16).replace("T", " ");
+}
+
+/**
+ * One capture header for the whole page. A page assembled from artifacts of one
+ * commit states that single point-in-time capture; a page assembled from
+ * different commits lists every vintage instead of letting each section's own
+ * commit line hide the mismatch.
+ */
+function renderCaptureHeader(captures: readonly EvidenceCapture[]): string[] {
+ const first = captures[0];
+ if (first === undefined) return [];
+ const commits = new Set(captures.map((capture) => capture.meta.commit));
+ const timestamps = captures.map((capture) => capture.meta.timestamp).sort();
+ const earliest = timestamps[0];
+ const latest = timestamps.at(-1);
+ if (earliest === undefined || latest === undefined) return [];
+ const window =
+ formatCaptureTime(earliest) === formatCaptureTime(latest)
+ ? formatCaptureTime(earliest)
+ : `${formatCaptureTime(earliest)} → ${formatCaptureTime(latest)}`;
+ if (commits.size === 1) {
+ return [
+ "## Capture",
+ "",
+ '',
+ `- Captured
- ${window} UTC
`,
+ `- Commit
${first.meta.commit.slice(0, 12)} clean worktree `,
+ `- Artifacts
- ${captures.length} validated captures from that one commit; each section states its own environment (browser or runtime) and protocol
`,
+ "
",
+ "",
+ ];
+ }
+ const vintages = [...captures].sort(
+ (left, right) =>
+ left.meta.timestamp.localeCompare(right.meta.timestamp) ||
+ left.label.localeCompare(right.label),
+ );
+ return [
+ "## Capture",
+ "",
+ 'Mixed capture vintages. The sections below were captured at different commits. Each section is internally consistent and each one names its own commit; the page as a whole is not a single point-in-time measurement.
',
+ "",
+ "| Section | Artifact | Commit | Captured |",
+ "| --- | --- | --- | --- |",
+ ...vintages.map(
+ (capture) =>
+ `| ${capture.label} | \`${capture.source}\` | ${capture.meta.commit.slice(0, 12)} | ${formatCaptureTime(capture.meta.timestamp)} UTC |`,
+ ),
+ "",
+ ];
+}
+
+/**
+ * Failures grouped by the cell that produced them. A run that did not finish is
+ * never converted into a timing, so the failure list is part of the evidence:
+ * it names the stage and the recorded error behind every missing cell.
+ */
+function renderFailureTable(evidence: ValidatedRenderEvidence): string[] {
+ const failures = evidence.results.filter((result) => result.status !== "success");
+ if (failures.length === 0) return [];
+ const groups = new Map<
+ string,
+ { engine: string; rows: number; scenario: string; stage: string; error: string; cells: number }
+ >();
+ for (const failure of failures) {
+ const stage = failure.stage ?? "unrecorded";
+ const error = [failure.errorClass, failure.message]
+ .filter((part): part is string => typeof part === "string" && part.length > 0)
+ .join(": ")
+ .replaceAll("|", "\\|");
+ const key = [failure.engine, failure.rows, failure.scenarioId, stage, error].join("\u0000");
+ const group = groups.get(key);
+ if (group === undefined) {
+ groups.set(key, {
+ engine: failure.engine,
+ rows: failure.rows,
+ scenario: failure.scenarioId,
+ stage,
+ error: error.length > 0 ? error : "not recorded",
+ cells: 1,
+ });
+ } else {
+ group.cells += 1;
+ }
+ }
+ const ordered = [...groups.values()].sort(
+ (left, right) =>
+ left.engine.localeCompare(right.engine) ||
+ left.rows - right.rows ||
+ left.scenario.localeCompare(right.scenario) ||
+ left.stage.localeCompare(right.stage),
+ );
+ return [
+ "",
+ "Every expected cell carries either a timing or its recorded failure. These cells did not finish and have no timing:",
+ "",
+ "| Engine | Size | Scenario | Stage | Recorded error | Cells |",
+ "| --- | ---: | --- | --- | --- | ---: |",
+ ...ordered.map(
+ (group) =>
+ `| ${group.engine} | ${fmtRows(group.rows)} | ${group.scenario} | ${group.stage} | ${group.error} | ${group.cells} |`,
+ ),
+ "",
+ ];
+}
+
+/** Markdown table cells cannot carry a raw pipe. */
+const markdownCell = (text: string): string => text.replaceAll("|", "\\|");
+
+/**
+ * Core write-path evidence: the packed block writes, CSV import, large restore,
+ * and paged residency work that the core hot paths changed. Every scenario
+ * carries the checkpoint it proved, so a timing is never published alone.
+ */
+function renderCorePathsSection(evidence: CorePathsEvidence, source: string): string[] {
+ const counters = evidence.scenarios.filter(
+ (scenario) => Object.keys(scenario.counters).length > 0,
+ );
+ return [
+ "## Core write path",
+ "",
+ `Validated evidence. ${evidence.scenarios.length} store and document scenarios at production sizes; every scenario passed its own correctness checkpoint before its timing was accepted.
`,
+ "",
+ '',
+ `- Captured
- ${formatCaptureTime(evidence.metadata.timestamp)} UTC
`,
+ `- Commit
${evidence.metadata.commit.slice(0, 12)} clean worktree `,
+ `- Environment
- Bun ${evidence.toolchain.bun} · Node compatibility ${evidence.toolchain.nodeCompat} · ${html(evidence.toolchain.cpu)}
`,
+ `- Raw artifact
${source} `,
+ "
",
+ "",
+ `Scale: ${Object.entries(evidence.scale)
+ .map(([name, value]) => `${name}=${value.toLocaleString("en-US")}`)
+ .join(", ")}.`,
+ "",
+ "| Scenario | One timed iteration | Median | p95 | Samples |",
+ "| --- | --- | ---: | ---: | ---: |",
+ ...evidence.scenarios.flatMap((scenario) => [
+ `| \`${scenario.id}\` | ${markdownCell(scenario.unit)} | ${fmtMs(scenario.timing.median)} | ${fmtMs(scenario.timing.p95)} | ${scenario.timing.iters} |`,
+ ...(scenario.variants ?? []).map(
+ (variant) =>
+ `| \`${scenario.id}:${variant.id}\` | variant measured in the same run | ${fmtMs(variant.timing.median)} | ${fmtMs(variant.timing.p95)} | ${variant.timing.iters} |`,
+ ),
+ ]),
+ "",
+ ...(counters.length === 0
+ ? []
+ : [
+ "Counters recorded by the same runs (non-time evidence):",
+ "",
+ ...counters.map(
+ (scenario) =>
+ `- \`${scenario.id}\` — ${Object.entries(scenario.counters)
+ .map(([name, value]) => `${name}=${value.toLocaleString("en-US")}`)
+ .join(", ")}`,
+ ),
+ "",
+ ]),
+ "Per-scenario correctness checkpoint
",
+ "",
+ ...evidence.scenarios.map(
+ (scenario) => `- \`${scenario.id}\` — ${markdownCell(scenario.validation)}`,
+ ),
+ "",
+ " ",
+ "",
+ "Reproduce with:",
+ "",
+ '```sh verify title="Core write-path evidence"',
+ "bun run --filter @sheetwrite/bench bench:core-paths",
+ "```",
+ "",
+ ];
+}
+
+/**
+ * XLSX codec evidence: the current tree against the codec at the recorded
+ * baseline commit, both reading the same checked fixture. A ratio below 1 means
+ * the current codec is faster; peak RSS is the largest raw process peak.
+ */
+function renderXlsxSection(evidence: XlsxEvidence, source: string): string[] {
+ const summaryFor = (
+ engine: string,
+ operation: string,
+ scenario: string,
+ ): XlsxEvidence["summaries"][number] | undefined =>
+ evidence.summaries.find(
+ (summary) =>
+ summary.engine === engine &&
+ summary.operation === operation &&
+ summary.scenario === scenario,
+ );
+ const baselineCommit = evidence.toolchain.baselineCommit;
+ return [
+ "## XLSX codec benchmark",
+ "",
+ `Validated evidence. ${evidence.comparisons.length > 0 ? `${evidence.comparisons.length} compared operations` : `${evidence.summaries.length} measured operations`} over ${evidence.rounds} process-isolated rounds each, from one checked corpus fixture.
`,
+ "",
+ '',
+ `- Captured
- ${formatCaptureTime(evidence.metadata.timestamp)} UTC
`,
+ `- Commit
${evidence.metadata.commit.slice(0, 12)} clean worktree `,
+ `- Fixture
${evidence.fixture.path} · ${evidence.fixture.bytes.toLocaleString("en-US")} bytes · ${evidence.fixture.sha256.slice(0, 12)} · ${html(evidence.fixture.producer)} `,
+ `- Environment
- Bun ${evidence.toolchain.bun} · Node ${evidence.toolchain.node} · ${html(evidence.toolchain.cpu)}
`,
+ `- Raw artifact
${source} `,
+ "
",
+ "",
+ ...(baselineCommit === undefined
+ ? [
+ "This capture ran the current tree only, so no codec comparison is published.",
+ "",
+ "| Operation | Scenario | Median | p95 | Peak RSS |",
+ "| --- | --- | ---: | ---: | ---: |",
+ ...evidence.summaries
+ .filter((summary) => summary.engine === "current")
+ .map(
+ (summary) =>
+ `| ${summary.operation} | ${summary.scenario} | ${fmtMs(summary.durationMs.median)} | ${fmtMs(summary.durationMs.p95)} | ${fmtMb(summary.maxRssBytes.max)} |`,
+ ),
+ "",
+ ]
+ : [
+ `The baseline codec is the same operation at commit ${baselineCommit.slice(0, 12)}, built from that commit and measured in the same session. Ratio = current ÷ baseline; below 1 is faster.`,
+ "",
+ "| Operation | Scenario | Current median | Baseline median | Ratio | Current peak RSS | Baseline peak RSS | RSS ratio |",
+ "| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: |",
+ ...evidence.comparisons.flatMap((comparison) => {
+ const current = summaryFor("current", comparison.operation, comparison.scenario);
+ const baseline = summaryFor("baseline", comparison.operation, comparison.scenario);
+ if (current === undefined || baseline === undefined) return [];
+ return [
+ `| ${comparison.operation} | ${comparison.scenario} | ${fmtMs(current.durationMs.median)} | ${fmtMs(baseline.durationMs.median)} | ${comparison.medianWallRatio.toFixed(2)}× | ${fmtMb(current.maxRssBytes.max)} | ${fmtMb(baseline.maxRssBytes.max)} | ${comparison.peakRssRatio.toFixed(2)}× |`,
+ ];
+ }),
+ "",
+ ]),
+ "Reproduce with a checkout of the baseline commit, built and passed as the comparison root:",
+ "",
+ '```sh verify title="XLSX codec evidence"',
+ `git worktree add ../sheetwrite-xlsx-baseline ${baselineCommit ?? ""}`,
+ "cd ../sheetwrite-xlsx-baseline && bun install --frozen-lockfile && bun run build:packages",
+ "cd - && bun run --filter @sheetwrite/bench bench:xlsx -- --baseline-root ../sheetwrite-xlsx-baseline",
+ "```",
+ "",
+ ];
+}
+
export async function renderEvidencePage(sizeHistoryOverride?: SizeHistory): Promise {
const scale = await loadEvidence(
"bench/results/render-scale.json",
@@ -2046,6 +2424,32 @@ export async function renderEvidencePage(sizeHistoryOverride?: SizeHistory): Pro
"bun run --filter @sheetwrite/bench bench:formula:matched",
validateMatchedEngineArtifact,
);
+ const corePaths = await loadEvidence(
+ "bench/results/core-paths-results.json",
+ "bun run --filter @sheetwrite/bench bench:core-paths",
+ validateCorePathsArtifact,
+ );
+ const xlsx = await loadEvidence(
+ "bench/results/xlsx-results.json",
+ "bun run --filter @sheetwrite/bench bench:xlsx -- --baseline-root ",
+ validateXlsxArtifact,
+ );
+ const captures = (
+ [
+ { label: "Render benchmark", loaded: scale },
+ { label: "Data engine benchmark", loaded: data },
+ { label: "Core write path", loaded: corePaths },
+ { label: "Formula engine benchmark", loaded: formula },
+ { label: "Formula engines (analysis capture)", loaded: fullEngine },
+ { label: "Formula engines (matched capture)", loaded: matchedEngine },
+ { label: "XLSX codec benchmark", loaded: xlsx },
+ ] satisfies Array<{ label: string; loaded: CapturedEvidence }>
+ ).flatMap(({ label, loaded }) => {
+ if (!("evidence" in loaded)) return [];
+ const evidence = loaded.evidence;
+ const captured = "meta" in evidence ? evidence.meta : evidence.metadata;
+ return [{ label, source: loaded.source, meta: captured }];
+ });
const sizeHistory =
sizeHistoryOverride ??
validateSizeHistory(
@@ -2059,6 +2463,7 @@ export async function renderEvidencePage(sizeHistoryOverride?: SizeHistory): Pro
).trimEnd(),
"Every number on this page comes from a validated local protocol artifact captured on a clean tree; nothing is published from an unvalidated or protocol-mismatched artifact. Every expected cell carries either a validated timing or its recorded failure - a run that did not complete is shown as a failure, never converted into a timing.",
"",
+ ...renderCaptureHeader(captures),
"## Matched local regression check",
"",
"Timing comparisons run deliberately on a controlled local machine, not as a required CI job. Capture ten fresh matched rounds, retain every raw sample, and compare the fresh artifact with the committed baseline. Any unapproved slowdown fails the local command.",
@@ -2072,6 +2477,8 @@ export async function renderEvidencePage(sizeHistoryOverride?: SizeHistory): Pro
"",
"A result is a regression decision only when that final baseline check passes on the declared power mode and concurrency. `bench:verify` remains a smoke and safety-ceiling check.",
"",
+ "The committed baseline at `bench/results/render-baseline.json` pins the harness source hashes, the declared sampling, and the runner (OS, CPU, Bun, Node, Chromium, power mode, concurrency). It is therefore machine- and harness-pinned: it must be re-recorded whenever a harness file, the sampling flags, the protocol version, or the runner changes, and the release capture does that as its last step by re-recording ten controlled rounds into `bench/results/render-baseline-raw.json` and promoting that artifact over the committed baseline. Until the re-recorded baseline is committed, `bench:check` fails closed on the fingerprint mismatch instead of comparing unrelated measurements.",
+ "",
"## Render benchmark",
"",
];
@@ -2092,6 +2499,7 @@ export async function renderEvidencePage(sizeHistoryOverride?: SizeHistory): Pro
"
",
"",
renderBenchWidget(evidence),
+ ...renderFailureTable(evidence),
"",
RENDER_METHOD,
"",
@@ -2216,6 +2624,11 @@ export async function renderEvidencePage(sizeHistoryOverride?: SizeHistory): Pro
} else {
pending.push(data);
}
+ if ("evidence" in corePaths) {
+ lines.push(...renderCorePathsSection(corePaths.evidence, corePaths.source));
+ } else {
+ pending.push(corePaths);
+ }
lines.push("## Formula engine benchmark", "");
if ("evidence" in formula) {
const { evidence, source } = formula;
@@ -2290,12 +2703,23 @@ export async function renderEvidencePage(sizeHistoryOverride?: SizeHistory): Pro
} else {
pending.push(formula);
}
- if ("evidence" in fullEngine && "evidence" in matchedEngine) {
- lines.push(renderFullEngineEvidence(fullEngine.evidence, matchedEngine.evidence));
+ if ("evidence" in fullEngine) {
+ lines.push(
+ renderFullEngineEvidence(
+ fullEngine.evidence,
+ "evidence" in matchedEngine ? matchedEngine.evidence : undefined,
+ ),
+ );
+ if (!("evidence" in matchedEngine)) pending.push(matchedEngine);
} else {
- if (!("evidence" in fullEngine)) pending.push(fullEngine);
+ pending.push(fullEngine);
if (!("evidence" in matchedEngine)) pending.push(matchedEngine);
}
+ if ("evidence" in xlsx) {
+ lines.push(...renderXlsxSection(xlsx.evidence, xlsx.source));
+ } else {
+ pending.push(xlsx);
+ }
lines.push("## Delivery size", "");
const latestRelease = sizeHistory.releases.at(-1);
if (latestRelease !== undefined) {
diff --git a/scripts/full-engine-docs.ts b/scripts/full-engine-docs.ts
index 6a2f830f..a91f8736 100644
--- a/scripts/full-engine-docs.ts
+++ b/scripts/full-engine-docs.ts
@@ -1,9 +1,17 @@
import { type FullEngineResult, validateFullEngineResult } from "../bench/src/full-engine-bench.js";
import {
type MatchedEngineResult,
+ type MatchedEngineRow,
validateMatchedEngineResult,
} from "../bench/src/matched-engine-bench.js";
+/**
+ * Largest paired-ratio p10–p90 span (p90/p10) that still supports a ratio
+ * claim. Identical shared work is the control: when the protocol is quiet, the
+ * paired ratio stays near 1 and its spread stays narrow.
+ */
+const MATCHED_SPREAD_CEILING = 1.5;
+
export function validateFullEngineArtifact(
value: Record
,
): FullEngineResult | string {
@@ -26,48 +34,9 @@ export function validateMatchedEngineArtifact(
return `Matched engine evidence is invalid: ${error instanceof Error ? error.message : String(error)}`;
}
}
-export function renderFullEngineEvidence(
- full: FullEngineResult,
- matched: MatchedEngineResult,
-): string {
- validateFullEngineResult(full);
- validateMatchedEngineResult(matched);
- for (const engine of full.engines) {
- const path = `packages/${engine.engine === "full" ? "formulas" : "wasm"}/pkg/sheetwrite_wasm_bg.wasm`;
- if (engine.wasm.sha256 !== matched.sourceFiles[path])
- throw new Error("Matched and analysis captures use different engine binaries");
- }
- const slowerCount = matched.rows.filter((row) => row.ratioStat.median > 1.05).length;
- const lines = [
- "### Default and full formula engines",
- "",
- `Validated evidence. Eight shared workloads have ${matched.rounds} paired rounds per engine. The full engine also has eight checked analysis workloads.
`,
- "",
- '',
- `- Matched capture
- ${matched.meta.timestamp.slice(0, 16).replace("T", " ")} UTC
`,
- `- Matched commit
${matched.meta.commit.slice(0, 12)} clean worktree `,
- `- Analysis capture
- ${full.meta.timestamp.slice(0, 16).replace("T", " ")} UTC
`,
- `- Analysis commit
${full.meta.commit.slice(0, 12)} clean worktree `,
- `- Machine
- ${matched.runner.cpu} · Linux ${matched.runner.kernel} · ${matched.runner.arch} · Bun ${matched.runner.bun}
`,
- "
",
- "",
- "The default engine is `@sheetwrite/wasm`. The full engine is `@sheetwrite/formulas`. Select it with `initSheetwrite(undefined, formulas)`. Each app uses one engine.",
- "",
- "The first capture ran all 53 shared workloads on each engine in sequence. Eight rows were more than 5% slower with the full engine. We checked those eight rows with matched rounds. Each pair runs default, then full. Each timed sample uses a fresh Bun process and one untimed warmup fixture. The runner used CPU 4 and one concurrent capture.",
- "",
- slowerCount === 0
- ? "No shared workload tested in the matched rounds had a median paired ratio more than 5% slower with the full engine. This check covers the eight flagged rows, not a new matched run of all 53 rows."
- : `${slowerCount} shared workloads tested in the matched rounds had a median paired ratio more than 5% slower with the full engine.`,
- "",
- `The ratio is full time divided by default time within each pair. The table shows the median of ${matched.rounds} paired ratios. The spread is the interpolated 10th to 90th percentile of those ratios. It is not a confidence interval. The time columns are the median times for each engine. A ratio below 1 means the full engine took less time. Wide spreads and very short operations limit what this sample can show.`,
- "",
- "| Shared workload | Size | Default median ms | Full median ms | Paired median ratio | Ratio p10–p90 |",
- "| --- | ---: | ---: | ---: | ---: | ---: |",
- ...matched.rows.map(
- (row) =>
- `| ${row.id} | ${row.size.toLocaleString("en-US")} | ${row.defaultStat.median.toFixed(4)} | ${row.fullStat.median.toFixed(4)} | ${row.ratioStat.median.toFixed(4)} | ${row.ratioP10.toFixed(4)}–${row.ratioP90.toFixed(4)} |`,
- ),
- "",
+
+function analysisSection(full: FullEngineResult): string[] {
+ return [
"#### Analysis workloads",
"",
"Each workload has 1,000 formulas. It has one untimed warmup and five measured samples. Each sample uses a fresh store. The timer measures first recompute. Setup and output reads are outside the timer. Every result is read and summed as a checked checksum. The default engine does not run these analysis functions.",
@@ -101,8 +70,96 @@ export function renderFullEngineEvidence(
"bun run bench:formula:matched",
"```",
"",
+ ];
+}
+
+/**
+ * The analysis capture (the shared matrix on both engines, WASM sizes, Node
+ * cold init) stands on its own. The matched paired-ratio table is added when
+ * that second capture is present and valid; without it the page still
+ * publishes the measured analysis evidence and names the capture that is
+ * missing.
+ */
+export function renderFullEngineEvidence(
+ full: FullEngineResult,
+ matched?: MatchedEngineResult,
+): string {
+ validateFullEngineResult(full);
+ const lines = ["### Default and full formula engines", ""];
+ if (matched === undefined) {
+ lines.push(
+ `Validated evidence. Both engines ran the shared workload matrix. The paired-ratio capture is not published on this page yet, so no engine-to-engine ratio is claimed here.
`,
+ "",
+ '',
+ `- Analysis capture
- ${full.meta.timestamp.slice(0, 16).replace("T", " ")} UTC
`,
+ `- Analysis commit
${full.meta.commit.slice(0, 12)} clean worktree `,
+ "
",
+ "",
+ "The default engine is `@sheetwrite/wasm`. The full engine is `@sheetwrite/formulas`. Select it with `initSheetwrite(undefined, formulas)`. Each app uses one engine.",
+ "",
+ ...analysisSection(full),
+ "The landing-page data comes from a separate browser benchmark. The Delivery size section below records published package sizes. Neither data set has an engine comparison field. They are unchanged by this local engine capture.",
+ "",
+ );
+ return lines.join("\n");
+ }
+
+ validateMatchedEngineResult(matched);
+ for (const engine of full.engines) {
+ const path = `packages/${engine.engine === "full" ? "formulas" : "wasm"}/pkg/sheetwrite_wasm_bg.wasm`;
+ if (engine.wasm.sha256 !== matched.sourceFiles[path])
+ throw new Error("Matched and analysis captures use different engine binaries");
+ }
+ const slowerCount = matched.rows.filter((row) => row.ratioStat.median > 1.05).length;
+ const sampleIterations = (row: MatchedEngineRow): { min: number; max: number } =>
+ row.samples.reduce(
+ (range, sample) => ({
+ min: Math.min(range.min, sample.iterations),
+ max: Math.max(range.max, sample.iterations),
+ }),
+ { min: Number.POSITIVE_INFINITY, max: 0 },
+ );
+ const widestSpread = matched.rows.reduce(
+ (worst, row) => Math.max(worst, row.ratioP90 / row.ratioP10),
+ 0,
+ );
+ lines.push(
+ `Validated evidence. Eight shared workloads have ${matched.rounds} paired rounds per engine. The full engine also has eight checked analysis workloads.
`,
+ "",
+ '',
+ `- Matched capture
- ${matched.meta.timestamp.slice(0, 16).replace("T", " ")} UTC
`,
+ `- Matched commit
${matched.meta.commit.slice(0, 12)} clean worktree `,
+ `- Analysis capture
- ${full.meta.timestamp.slice(0, 16).replace("T", " ")} UTC
`,
+ `- Analysis commit
${full.meta.commit.slice(0, 12)} clean worktree `,
+ `- Machine
- ${matched.runner.cpu} · Linux ${matched.runner.kernel} · ${matched.runner.arch} · Bun ${matched.runner.bun}
`,
+ "
",
+ "",
+ "The default engine is `@sheetwrite/wasm`. The full engine is `@sheetwrite/formulas`. Select it with `initSheetwrite(undefined, formulas)`. Each app uses one engine.",
+ "",
+ `The first capture ran all 53 shared workloads on each engine in sequence. Eight rows were more than 5% slower with the full engine. Those eight rows were checked with matched rounds. Each pair runs default, then full, in separate Bun processes. A timed sample starts with ${matched.warmupFixtures} untimed warm-up fixtures and then repeats the workload until at least ${matched.minimumSampleDurationMs} ms of measured time; the sample is the per-iteration mean, so a short operation is measured over many repetitions instead of one cold run. The runner used CPU 4 and one concurrent capture.`,
+ "",
+ slowerCount === 0
+ ? "No shared workload tested in the matched rounds had a median paired ratio more than 5% slower with the full engine. This check covers the eight flagged rows, not a new matched run of all 53 rows."
+ : `${slowerCount} shared workloads tested in the matched rounds had a median paired ratio more than 5% slower with the full engine.`,
+ "",
+ `The ratio is full time divided by default time within each pair. The table shows the median of ${matched.rounds} paired ratios. The spread is the interpolated 10th to 90th percentile of those ratios. It is not a confidence interval. The time columns are the median times for each engine. A ratio below 1 means the full engine took less time.`,
+ "",
+ widestSpread <= MATCHED_SPREAD_CEILING
+ ? `Identical shared work is the control for this protocol: the widest paired-ratio p10–p90 span across the eight rows is ${widestSpread.toFixed(2)}× (ceiling ${MATCHED_SPREAD_CEILING.toFixed(2)}×), so each median ratio is supported by its paired samples.`
+ : `At least one row's paired-ratio p10–p90 span is ${widestSpread.toFixed(2)}× (ceiling ${MATCHED_SPREAD_CEILING.toFixed(2)}×). Rows above the ceiling are marked and their median ratio should not be read as a measured difference.`,
+ "",
+ "| Shared workload | Size | Default median ms | Full median ms | Paired median ratio | Ratio p10–p90 | Iterations per sample |",
+ "| --- | ---: | ---: | ---: | ---: | ---: | ---: |",
+ ...matched.rows.map((row) => {
+ const iterations = sampleIterations(row);
+ const spread = row.ratioP90 / row.ratioP10;
+ const marker = spread > MATCHED_SPREAD_CEILING ? " ⚠︎" : "";
+ return `| ${row.id}${marker} | ${row.size.toLocaleString("en-US")} | ${row.defaultStat.median.toFixed(4)} | ${row.fullStat.median.toFixed(4)} | ${row.ratioStat.median.toFixed(4)} | ${row.ratioP10.toFixed(4)}–${row.ratioP90.toFixed(4)} | ${iterations.min}–${iterations.max} |`;
+ }),
+ "",
+ ...analysisSection(full),
"The landing-page data comes from a separate browser benchmark. The Delivery size section below records published package sizes. Neither data set has an engine comparison field. They are unchanged by this local engine capture.",
"",
- ];
+ );
return lines.join("\n");
}