Stand up the monorepo skeleton and land the first Phase 0 artifacts: pairing threat model, plugin catalog, builder detect, 20-prompt golden harness, and synthetic 2GB mirror timing.
101 lines
3.4 KiB
TypeScript
101 lines
3.4 KiB
TypeScript
import { mkdirSync, statSync, writeFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { performance } from 'node:perf_hooks';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { mediaProxyTarget } from './media-proxy.ts';
|
|
import { exportDbSubset } from './subset.ts';
|
|
import type { SiteExport } from './types.ts';
|
|
|
|
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '../../..');
|
|
const exportDir = join(repoRoot, 'e2e/fixtures/large-exports/synthetic-2g');
|
|
const blobPath = join(exportDir, 'uploads/2024/library.bin');
|
|
const targetBytes = 2 * 1024 * 1024 * 1024;
|
|
const runs = 20;
|
|
|
|
function ensureBlob(): number {
|
|
mkdirSync(dirname(blobPath), { recursive: true });
|
|
try {
|
|
const existing = statSync(blobPath).size;
|
|
if (existing >= targetBytes) {
|
|
return existing;
|
|
}
|
|
} catch {
|
|
// create below
|
|
}
|
|
const result = spawnSync('mkfile', [`${targetBytes}`, blobPath], { stdio: 'inherit' });
|
|
if (result.status !== 0) {
|
|
throw new Error('mkfile failed');
|
|
}
|
|
return statSync(blobPath).size;
|
|
}
|
|
|
|
function dump(bytes: number): SiteExport {
|
|
const posts = Array.from({ length: 8000 }, (_, index) => ({
|
|
ID: index + 1,
|
|
post_title: index === 0 ? 'Home' : `Post ${index + 1}`,
|
|
post_content: 'x'.repeat(80),
|
|
}));
|
|
return {
|
|
origin: 'https://big.example',
|
|
tables: {
|
|
wp_posts: posts,
|
|
wp_postmeta: posts.map((post) => ({ post_id: post.ID, meta_key: '_edit_lock', meta_value: '1' })),
|
|
wp_options: [
|
|
{ option_name: 'blogname', option_value: 'Big' },
|
|
{ option_name: 'woocommerce_stripe_secret_key', option_value: 'sk' },
|
|
],
|
|
wp_wc_orders: Array.from({ length: 20000 }, (_, index) => ({ id: index, total: '10.00' })),
|
|
},
|
|
uploads: [{ path: '/wp-content/uploads/2024/library.bin', bytes }],
|
|
};
|
|
}
|
|
|
|
function percentile(values: number[], p: number): number {
|
|
const sorted = [...values].sort((a, b) => a - b);
|
|
const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil((p / 100) * sorted.length) - 1));
|
|
return sorted[index] ?? 0;
|
|
}
|
|
|
|
const bytes = ensureBlob();
|
|
const site = dump(bytes);
|
|
const samples: number[] = [];
|
|
|
|
for (let i = 0; i < runs; i += 1) {
|
|
const start = performance.now();
|
|
const subset = exportDbSubset(site, { playbook: 'content', postIds: [1] });
|
|
const proxy = mediaProxyTarget(site, '/wp-content/uploads/2024/library.bin');
|
|
if (subset.tables.includes('wp_wc_orders')) {
|
|
throw new Error('subset leaked orders');
|
|
}
|
|
if (!proxy.startsWith('https://big.example/')) {
|
|
throw new Error('proxy missed origin');
|
|
}
|
|
samples.push(performance.now() - start);
|
|
}
|
|
|
|
const copyDest = `${blobPath}.copy`;
|
|
const copyStart = performance.now();
|
|
const copy = spawnSync('dd', [`if=${blobPath}`, `of=${copyDest}`, 'bs=8m'], { stdio: 'inherit' });
|
|
const naiveCopyMs = performance.now() - copyStart;
|
|
if (copy.status !== 0) {
|
|
throw new Error('naive copy failed');
|
|
}
|
|
|
|
const report = {
|
|
blobBytes: bytes,
|
|
runs,
|
|
subsetProxyMs: samples,
|
|
p50Ms: percentile(samples, 50),
|
|
p95Ms: percentile(samples, 95),
|
|
uploadBytesCopied: 0,
|
|
naiveCopyMs,
|
|
targetPageBudgetMs: 60_000,
|
|
decision: percentile(samples, 95) <= 60_000 ? 'slice holds' : 'slice is wrong',
|
|
};
|
|
|
|
const out = join(dirname(fileURLToPath(import.meta.url)), '../runs/mirror-timing.json');
|
|
mkdirSync(dirname(out), { recursive: true });
|
|
writeFileSync(out, `${JSON.stringify(report, null, 2)}\n`);
|
|
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|