mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
b15121ffc8
* test(ios): add snapshot convergence evidence harness * fix(ios): satisfy benchmark CI guards * fix(ios): constrain benchmark proxy routes * fix(ios-benchmark): enforce cell admission evidence * fix(ios-benchmark): protect benchmark state ownership * fix(ios-benchmark): use proxy port flag * fix(ios-benchmark): let proxy choose an ephemeral port * test(ios-benchmark): keep CLI process seam local * fix(ios-benchmark): parse proxy startup envelope * fix(ios-benchmark): bind proxy lease to simulator * fix(ios-benchmark): keep fresh proxy CLI sessions isolated * fix(ios-benchmark): preserve async timeout evidence * docs(ios-benchmark): retain exact-head evidence * test(ios): reveal offscreen alert fixture controls * test(ios): reset alert between relaunch samples * test(ios): admit native alert snapshots * docs(ios): publish snapshot convergence corpus * chore(ios): format benchmark evidence * fix(ios-benchmark): admit proxy fixture anchors * docs(ios): republish exact-head benchmark corpus * fix(size): make publish asset evidence hermetic * style(size): format package evidence test * test(size): update publish preparation contracts * fix: retire stale utils layering zone * test: pin shared publish asset owner * test: verify preserved size reporter closure * fix: move mutation ownership to snapshot module * test(ios): add snapshot convergence evidence harness * fix(ios): satisfy benchmark CI guards * fix(ios): constrain benchmark proxy routes * fix(ios-benchmark): enforce cell admission evidence * fix(ios-benchmark): protect benchmark state ownership * fix(ios-benchmark): use proxy port flag * fix(ios-benchmark): let proxy choose an ephemeral port * test(ios-benchmark): keep CLI process seam local * fix(ios-benchmark): parse proxy startup envelope * fix(ios-benchmark): bind proxy lease to simulator * fix(ios-benchmark): keep fresh proxy CLI sessions isolated * fix(ios-benchmark): preserve async timeout evidence * docs(ios-benchmark): retain exact-head evidence * test(ios): reveal offscreen alert fixture controls * test(ios): reset alert between relaunch samples * test(ios): admit native alert snapshots * docs(ios): publish snapshot convergence corpus * chore(ios): format benchmark evidence * fix(ios-benchmark): admit proxy fixture anchors * docs(ios): republish exact-head benchmark corpus * fix(size): make publish asset evidence hermetic * test(size): update publish preparation contracts * fix: keep git-state gates out of mutation sandboxes
111 lines
4.0 KiB
TypeScript
111 lines
4.0 KiB
TypeScript
import type { BenchmarkResult, Measurement, PackageSize, Summary } from './types.ts';
|
||
|
||
export function renderBenchmarkMarkdown(result: BenchmarkResult): string {
|
||
const lines = [
|
||
'# iOS snapshot convergence benchmark',
|
||
'',
|
||
`- Status: **${result.status}**`,
|
||
`- Revision: ${result.revision.commit}`,
|
||
`- Host: ${result.host.model} (${result.host.modelIdentifier}; ${result.host.cpu}, ${result.host.cpuCores} cores)`,
|
||
`- Target: ${result.target.name} (${result.target.udid}, ${result.target.runtime})`,
|
||
`- Generated: ${result.generatedAt}`,
|
||
'',
|
||
'| State | Screen | Transport | Execution | N | Wall median | Wall p95 | Daemon median | Response median | Failures |',
|
||
'|---|---|---|---|---:|---:|---:|---:|---:|---:|',
|
||
...result.measurements.map(measurementRow),
|
||
'',
|
||
'## Package size',
|
||
'',
|
||
packageSizeLines(result),
|
||
'',
|
||
'## Deep-button control',
|
||
'',
|
||
`- Fixture artifact: ${result.deepButtonEvidence.artifact} (depth ${result.deepButtonEvidence.depth})`,
|
||
`- Red control: ${result.deepButtonEvidence.invalidShallowRule.command} (exit ${result.deepButtonEvidence.invalidShallowRule.exitCode})`,
|
||
` - ${result.deepButtonEvidence.invalidShallowRule.assertion}`,
|
||
`- Safe control: ${result.deepButtonEvidence.safeFullRule.command} (exit ${result.deepButtonEvidence.safeFullRule.exitCode})`,
|
||
` - ${result.deepButtonEvidence.safeFullRule.assertion}`,
|
||
];
|
||
if (result.stop) {
|
||
lines.push('', '## Stop condition', '', `- ${result.stop.category}: ${result.stop.message}`);
|
||
if (result.stop.reason) lines.push(`- Reason: ${result.stop.reason}`);
|
||
if (result.stop.command) lines.push(`- Command: ${result.stop.command}`);
|
||
}
|
||
return `${lines.join('\n')}\n`;
|
||
}
|
||
|
||
function measurementRow(measurement: Measurement): string {
|
||
return `| ${[
|
||
measurement.state,
|
||
measurement.screen,
|
||
measurement.transport,
|
||
measurement.execution,
|
||
measurement.wallClockMs?.n ?? 0,
|
||
formatSummaryValue(measurement.wallClockMs, 'median'),
|
||
formatSummaryValue(measurement.wallClockMs, 'p95'),
|
||
formatSummaryValue(measurement.daemonDurationMs, 'median'),
|
||
formatSummaryValue(measurement.responseBytes, 'median'),
|
||
measurement.failures,
|
||
].join(' | ')} |`;
|
||
}
|
||
|
||
function formatSummaryValue(summary: Summary | null, key: 'median' | 'p95'): string {
|
||
return summary ? `${summary[key].toFixed(1)}` : '–';
|
||
}
|
||
|
||
function packageSizeLines(result: BenchmarkResult): string {
|
||
const packageSize = result.packageSize;
|
||
if (packageSize.status !== 'measured') return 'Not measured.';
|
||
return measuredPackageSizeLines(packageSize);
|
||
}
|
||
|
||
function measuredPackageSizeLines(packageSize: PackageSize & { status: 'measured' }): string {
|
||
return [
|
||
...packedSizeLines(packageSize),
|
||
cleanInstalledSizeLine(packageSize),
|
||
bundledSizeLine(packageSize),
|
||
].join('\n');
|
||
}
|
||
|
||
function packedSizeLines(packageSize: PackageSize): string[] {
|
||
const packed = packageSize.packed;
|
||
return [
|
||
packageSizeLine('Packed tarball', packed?.tarballBytes),
|
||
packageSizeLine('Packed unpacked tree', packed?.unpackedBytes),
|
||
];
|
||
}
|
||
|
||
function cleanInstalledSizeLine(packageSize: PackageSize): string {
|
||
const cleanInstalled = packageSize.cleanInstalled;
|
||
return packageTreeLine(
|
||
'Clean-installed package tree',
|
||
cleanInstalled?.packageBytes,
|
||
cleanInstalled?.files,
|
||
);
|
||
}
|
||
|
||
function bundledSizeLine(packageSize: PackageSize): string {
|
||
const bundled = packageSize.bundled;
|
||
return packageBundleLine('Bundled JavaScript', bundled?.rawBytes, bundled?.gzipBytes);
|
||
}
|
||
|
||
function packageSizeLine(label: string, bytes: number | undefined): string {
|
||
return `- ${label}: ${bytes ?? '–'} bytes`;
|
||
}
|
||
|
||
function packageTreeLine(
|
||
label: string,
|
||
bytes: number | undefined,
|
||
files: number | undefined,
|
||
): string {
|
||
return `- ${label}: ${bytes ?? '–'} bytes (${files ?? '–'} files)`;
|
||
}
|
||
|
||
function packageBundleLine(
|
||
label: string,
|
||
raw: number | undefined,
|
||
gzip: number | undefined,
|
||
): string {
|
||
return `- ${label}: ${raw ?? '–'} raw / ${gzip ?? '–'} gzip bytes`;
|
||
}
|