@fairfox/polly 0.81.0 → 0.82.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,11 +28,45 @@ var BOOL_FLAGS = {
28
28
  "--full": "full",
29
29
  "--list": "list",
30
30
  "--bail": "bail",
31
+ "--fail-fast": "failFast",
31
32
  "--strict-needs": "strictNeeds"
32
33
  };
34
+ function parseOrder(value) {
35
+ if (value === "default" || value === "fast" || value === "cost")
36
+ return value;
37
+ return null;
38
+ }
33
39
  function listValue(arg, name) {
34
40
  return arg.startsWith(name) ? arg.slice(name.length).split(",") : [];
35
41
  }
42
+ function applyValueFlag(args, arg) {
43
+ if (arg === "--json") {
44
+ args.json = DEFAULT_JSON;
45
+ return true;
46
+ }
47
+ if (arg.startsWith("--json=")) {
48
+ args.json = arg.slice("--json=".length);
49
+ return true;
50
+ }
51
+ if (arg.startsWith("--tier=")) {
52
+ args.tiers.push(...listValue(arg, "--tier="));
53
+ return true;
54
+ }
55
+ if (arg.startsWith("--only=")) {
56
+ args.only.push(...listValue(arg, "--only="));
57
+ return true;
58
+ }
59
+ if (arg.startsWith("--order=")) {
60
+ const order = parseOrder(arg.slice("--order=".length));
61
+ if (order === null) {
62
+ console.log("Unknown --order value (expected default, fast, or cost)");
63
+ process.exit(2);
64
+ }
65
+ args.order = order;
66
+ return true;
67
+ }
68
+ return false;
69
+ }
36
70
  function parseTierArgs(argv) {
37
71
  const args = {
38
72
  tiers: [],
@@ -41,6 +75,8 @@ function parseTierArgs(argv) {
41
75
  full: false,
42
76
  list: false,
43
77
  bail: false,
78
+ failFast: false,
79
+ order: null,
44
80
  strictNeeds: false,
45
81
  json: null
46
82
  };
@@ -50,20 +86,7 @@ function parseTierArgs(argv) {
50
86
  args[boolKey] = true;
51
87
  continue;
52
88
  }
53
- if (arg === "--json") {
54
- args.json = DEFAULT_JSON;
55
- continue;
56
- }
57
- if (arg.startsWith("--json=")) {
58
- args.json = arg.slice("--json=".length);
59
- continue;
60
- }
61
- if (arg.startsWith("--tier=")) {
62
- args.tiers.push(...listValue(arg, "--tier="));
63
- continue;
64
- }
65
- if (arg.startsWith("--only=")) {
66
- args.only.push(...listValue(arg, "--only="));
89
+ if (applyValueFlag(args, arg)) {
67
90
  continue;
68
91
  }
69
92
  if (arg.startsWith("-")) {
@@ -211,6 +234,22 @@ async function firstUnmetNeed(needs) {
211
234
  return null;
212
235
  }
213
236
 
237
+ // tools/test/src/tiers/order.ts
238
+ var COST_WEIGHT = {
239
+ light: 0,
240
+ medium: 1,
241
+ heavy: 2
242
+ };
243
+ function weightOf(spec) {
244
+ return COST_WEIGHT[spec.cost ?? "medium"];
245
+ }
246
+ function orderCases(cases, order) {
247
+ if (order === "default")
248
+ return cases;
249
+ const direction = order === "cost" ? -1 : 1;
250
+ return cases.map((spec, index) => ({ spec, index })).sort((a, b) => (weightOf(a.spec) - weightOf(b.spec)) * direction || a.index - b.index).map((entry) => entry.spec);
251
+ }
252
+
214
253
  // tools/test/src/tiers/protocol.ts
215
254
  var SENTINEL = "__TIER_RESULT__";
216
255
 
@@ -349,40 +388,52 @@ async function runOneCase(spec, tier, options, worker) {
349
388
  }
350
389
  async function runTier(tier, options, worker) {
351
390
  const log = options.log ?? ((m) => console.log(m));
352
- const selected = tier.cases.filter((c) => caseMatches(c, options.only));
353
- if (selected.length === 0)
391
+ const matched = tier.cases.filter((c) => caseMatches(c, options.only));
392
+ if (matched.length === 0)
354
393
  return [];
394
+ const selected = orderCases(matched, options.order ?? "default");
355
395
  log(`
356
396
  ▶ ${tier.name}${tier.description ? ` — ${tier.description}` : ""} (${selected.length} case${selected.length === 1 ? "" : "s"})`);
357
397
  const concurrency = Math.max(1, tier.concurrency ?? 1);
398
+ const failFast = options.failFast ?? false;
358
399
  const reports = new Array(selected.length);
359
400
  let next = 0;
401
+ let aborted = false;
360
402
  async function worker_loop() {
361
- while (true) {
403
+ while (!aborted) {
362
404
  const i = next++;
363
405
  const spec = selected[i];
364
406
  if (!spec)
365
407
  return;
366
- reports[i] = await runOneCase(spec, tier, options, worker);
408
+ const report = await runOneCase(spec, tier, options, worker);
409
+ reports[i] = report;
410
+ if (failFast && (report.outcome === "fail" || report.outcome === "timeout")) {
411
+ aborted = true;
412
+ }
367
413
  }
368
414
  }
369
415
  await Promise.all(Array.from({ length: Math.min(concurrency, selected.length) }, worker_loop));
370
- return reports;
416
+ const done = reports.filter((r) => r !== undefined);
417
+ if (aborted && done.length < selected.length) {
418
+ log(` ⏹ fail-fast: stopped after a failure — ${selected.length - done.length} case(s) not run`);
419
+ }
420
+ return done;
371
421
  }
372
422
  async function runPlan(plan, options = {}) {
373
423
  const log = options.log ?? ((m) => console.log(m));
374
424
  const worker = await workerPath();
375
425
  const wanted = options.tiers && options.tiers.length > 0 ? new Set(options.tiers) : null;
376
426
  const started = performance.now();
427
+ const stopOnFail = Boolean(options.bail || options.failFast);
377
428
  const all = [];
378
429
  for (const tier of plan.tiers) {
379
430
  if (wanted && !wanted.has(tier.name))
380
431
  continue;
381
432
  const reports = await runTier(tier, options, worker);
382
433
  all.push(...reports);
383
- if (options.bail && reports.some((r) => r.outcome === "fail" || r.outcome === "timeout")) {
434
+ if (stopOnFail && reports.some((r) => r.outcome === "fail" || r.outcome === "timeout")) {
384
435
  log(`
385
- bailing after failing tier "${tier.name}"`);
436
+ ${options.failFast ? "fail-fast" : "bail"}: stopping after failing tier "${tier.name}"`);
386
437
  break;
387
438
  }
388
439
  }
@@ -427,7 +478,8 @@ function formatPlan(plan) {
427
478
  lines.push(`${tier.name}${conc}${tier.description ? ` — ${tier.description}` : ""}`);
428
479
  for (const c of tier.cases) {
429
480
  const needs = c.needs && c.needs.length > 0 ? ` (needs ${c.needs.join(", ")})` : "";
430
- lines.push(` ${c.id}${needs}`);
481
+ const cost = c.cost ? ` [${c.cost}]` : "";
482
+ lines.push(` ${c.id}${cost}${needs}`);
431
483
  }
432
484
  lines.push("");
433
485
  }
@@ -471,7 +523,9 @@ async function main() {
471
523
  const report = await runPlan(plan, {
472
524
  tiers,
473
525
  only: args.only,
526
+ order: args.order ?? (args.failFast ? "fast" : "default"),
474
527
  bail: args.bail,
528
+ failFast: args.failFast,
475
529
  strictNeeds: args.strictNeeds,
476
530
  cwd: root,
477
531
  log: (m) => console.log(m)
@@ -487,4 +541,4 @@ wrote ${args.json}`);
487
541
  }
488
542
  await main();
489
543
 
490
- //# debugId=170074AB01C8CBEF64756E2164756E21
544
+ //# debugId=CD4A2E88C15B8A6864756E2164756E21
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../tools/test/src/tiers/cli.ts", "../tools/test/src/tiers/args.ts", "../tools/test/src/tiers/discover.ts", "../tools/test/src/tiers/detect.ts", "../tools/test/src/tiers/protocol.ts", "../tools/test/src/tiers/engine.ts", "../tools/test/src/tiers/reporter.ts"],
3
+ "sources": ["../tools/test/src/tiers/cli.ts", "../tools/test/src/tiers/args.ts", "../tools/test/src/tiers/discover.ts", "../tools/test/src/tiers/detect.ts", "../tools/test/src/tiers/order.ts", "../tools/test/src/tiers/protocol.ts", "../tools/test/src/tiers/engine.ts", "../tools/test/src/tiers/reporter.ts"],
4
4
  "sourcesContent": [
5
- "#!/usr/bin/env bun\n/**\n * Consumer-facing tiered test runner — what `polly test --tier …` runs from a\n * consumer's own Polly project. It auto-discovers the project's tiers (see\n * discover.ts) and runs them through the shared engine, exactly as Polly's own\n * internal suite does.\n *\n * Usage (from a Polly project root):\n * polly test --tier # discovered unit + integration (fast loop)\n * polly test --tier --all # every discovered tier\n * polly test --tier=browser # one tier\n * polly test --tier --list # show what was discovered, run nothing\n * polly test --tier --json # write test-results/tiers.json\n *\n * (Bare `polly test` still delegates to `bun test`; the --tier-family flags\n * switch into this runner.)\n */\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { parseTierArgs } from \"./args\";\nimport { discoverPlan } from \"./discover\";\nimport { runPlan } from \"./engine\";\nimport { formatPlan, formatSummary, toJSON } from \"./reporter\";\n\n/** Tiers run when no tier is named (fast inner loop), if they were discovered. */\nconst DEFAULT_TIERS = [\"unit\", \"integration\"];\n\nasync function main(): Promise<void> {\n const args = parseTierArgs(process.argv.slice(2));\n const root = process.cwd();\n const plan = await discoverPlan(root);\n\n if (plan.tiers.length === 0) {\n console.log(\n \"polly test: no tiers discovered.\\n\" +\n \" Looked for *.test.{ts,tsx}, *.browser.{ts,tsx}, and scripts/e2e-*.{ts,tsx}.\"\n );\n process.exit(0);\n }\n\n if (args.list) {\n console.log(formatPlan(plan));\n return;\n }\n\n const discovered = plan.tiers.map((t) => t.name);\n const known = new Set(discovered);\n let tiers: string[];\n if (args.tiers.length > 0) {\n const unknown = args.tiers.filter((t) => !known.has(t));\n if (unknown.length > 0) {\n console.log(`Unknown tier(s): ${unknown.join(\", \")}`);\n console.log(`Discovered tiers: ${discovered.join(\", \")}`);\n process.exit(2);\n }\n tiers = args.tiers;\n } else if (args.all || args.full) {\n tiers = discovered;\n } else {\n const fast = discovered.filter((t) => DEFAULT_TIERS.includes(t));\n tiers = fast.length > 0 ? fast : discovered;\n }\n\n console.log(\n `polly test — tiers: ${tiers.join(\" → \")}${args.only.length ? ` only: ${args.only.join(\", \")}` : \"\"}`\n );\n\n const report = await runPlan(plan, {\n tiers,\n only: args.only,\n bail: args.bail,\n strictNeeds: args.strictNeeds,\n cwd: root,\n log: (m) => console.log(m),\n });\n\n console.log(formatSummary(report));\n\n if (args.json) {\n mkdirSync(dirname(args.json), { recursive: true });\n await Bun.write(args.json, toJSON(report));\n console.log(`\\nwrote ${args.json}`);\n }\n\n process.exit(report.ok ? 0 : 1);\n}\n\nawait main();\n",
6
- "/**\n * Shared flag parsing for the tiered runner CLIs.\n *\n * Both front-ends (Polly's internal scripts/test/cli.ts and the consumer-facing\n * tools/test/src/tiers/cli.ts) accept the same flags; only their tier *sets*\n * differ. This keeps the surface identical.\n */\n\nexport interface TierArgs {\n /** Explicit tier names (positional or via --tier=a,b). */\n tiers: string[];\n /** --only=substr filters across tiers. */\n only: string[];\n all: boolean;\n full: boolean;\n list: boolean;\n bail: boolean;\n strictNeeds: boolean;\n /** Path to write JSON results, or null. */\n json: string | null;\n}\n\nexport const DEFAULT_JSON = \"test-results/tiers.json\";\n\nconst BOOL_FLAGS: Record<string, \"all\" | \"full\" | \"list\" | \"bail\" | \"strictNeeds\"> = {\n \"--all\": \"all\",\n \"--full\": \"full\",\n \"--list\": \"list\",\n \"--bail\": \"bail\",\n \"--strict-needs\": \"strictNeeds\",\n};\n\nfunction listValue(arg: string, name: string): string[] {\n return arg.startsWith(name) ? arg.slice(name.length).split(\",\") : [];\n}\n\n/** Parse argv into {@link TierArgs}. Exits(2) on an unknown `--flag`. */\nexport function parseTierArgs(argv: string[]): TierArgs {\n const args: TierArgs = {\n tiers: [],\n only: [],\n all: false,\n full: false,\n list: false,\n bail: false,\n strictNeeds: false,\n json: null,\n };\n for (const arg of argv) {\n const boolKey = BOOL_FLAGS[arg];\n if (boolKey) {\n args[boolKey] = true;\n continue;\n }\n if (arg === \"--json\") {\n args.json = DEFAULT_JSON;\n continue;\n }\n if (arg.startsWith(\"--json=\")) {\n args.json = arg.slice(\"--json=\".length);\n continue;\n }\n if (arg.startsWith(\"--tier=\")) {\n args.tiers.push(...listValue(arg, \"--tier=\"));\n continue;\n }\n if (arg.startsWith(\"--only=\")) {\n args.only.push(...listValue(arg, \"--only=\"));\n continue;\n }\n if (arg.startsWith(\"-\")) {\n console.log(`Unknown flag: ${arg}`);\n process.exit(2);\n }\n args.tiers.push(arg);\n }\n return args;\n}\n",
5
+ "#!/usr/bin/env bun\n/**\n * Consumer-facing tiered test runner — what `polly test --tier …` runs from a\n * consumer's own Polly project. It auto-discovers the project's tiers (see\n * discover.ts) and runs them through the shared engine, exactly as Polly's own\n * internal suite does.\n *\n * Usage (from a Polly project root):\n * polly test --tier # discovered unit + integration (fast loop)\n * polly test --tier --all # every discovered tier\n * polly test --tier=browser # one tier\n * polly test --tier --all --order=cost # heaviest cases first (min wall-clock)\n * polly test --tier --all --fail-fast # soft early-stop on first failure\n * polly test --tier --list # show what was discovered, run nothing\n * polly test --tier --json # write test-results/tiers.json\n *\n * (Bare `polly test` still delegates to `bun test`; the --tier-family flags\n * switch into this runner.)\n */\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { parseTierArgs } from \"./args\";\nimport { discoverPlan } from \"./discover\";\nimport { runPlan } from \"./engine\";\nimport { formatPlan, formatSummary, toJSON } from \"./reporter\";\n\n/** Tiers run when no tier is named (fast inner loop), if they were discovered. */\nconst DEFAULT_TIERS = [\"unit\", \"integration\"];\n\nasync function main(): Promise<void> {\n const args = parseTierArgs(process.argv.slice(2));\n const root = process.cwd();\n const plan = await discoverPlan(root);\n\n if (plan.tiers.length === 0) {\n console.log(\n \"polly test: no tiers discovered.\\n\" +\n \" Looked for *.test.{ts,tsx}, *.browser.{ts,tsx}, and scripts/e2e-*.{ts,tsx}.\"\n );\n process.exit(0);\n }\n\n if (args.list) {\n console.log(formatPlan(plan));\n return;\n }\n\n const discovered = plan.tiers.map((t) => t.name);\n const known = new Set(discovered);\n let tiers: string[];\n if (args.tiers.length > 0) {\n const unknown = args.tiers.filter((t) => !known.has(t));\n if (unknown.length > 0) {\n console.log(`Unknown tier(s): ${unknown.join(\", \")}`);\n console.log(`Discovered tiers: ${discovered.join(\", \")}`);\n process.exit(2);\n }\n tiers = args.tiers;\n } else if (args.all || args.full) {\n tiers = discovered;\n } else {\n const fast = discovered.filter((t) => DEFAULT_TIERS.includes(t));\n tiers = fast.length > 0 ? fast : discovered;\n }\n\n console.log(\n `polly test — tiers: ${tiers.join(\" → \")}${args.only.length ? ` only: ${args.only.join(\", \")}` : \"\"}`\n );\n\n const report = await runPlan(plan, {\n tiers,\n only: args.only,\n // --fail-fast wants cheap, high-signal cases first so the abort trips\n // soonest; an explicit --order always wins.\n order: args.order ?? (args.failFast ? \"fast\" : \"default\"),\n bail: args.bail,\n failFast: args.failFast,\n strictNeeds: args.strictNeeds,\n cwd: root,\n log: (m) => console.log(m),\n });\n\n console.log(formatSummary(report));\n\n if (args.json) {\n mkdirSync(dirname(args.json), { recursive: true });\n await Bun.write(args.json, toJSON(report));\n console.log(`\\nwrote ${args.json}`);\n }\n\n process.exit(report.ok ? 0 : 1);\n}\n\nawait main();\n",
6
+ "/**\n * Shared flag parsing for the tiered runner CLIs.\n *\n * Both front-ends (Polly's internal scripts/test/cli.ts and the consumer-facing\n * tools/test/src/tiers/cli.ts) accept the same flags; only their tier *sets*\n * differ. This keeps the surface identical.\n */\n\nimport type { CaseOrder } from \"./types\";\n\nexport interface TierArgs {\n /** Explicit tier names (positional or via --tier=a,b). */\n tiers: string[];\n /** --only=substr filters across tiers. */\n only: string[];\n all: boolean;\n full: boolean;\n list: boolean;\n bail: boolean;\n /** --fail-fast: soft early-stop on the first failing case. */\n failFast: boolean;\n /** --order=fast|cost|default within-tier ordering, or null to leave unset. */\n order: CaseOrder | null;\n strictNeeds: boolean;\n /** Path to write JSON results, or null. */\n json: string | null;\n}\n\nexport const DEFAULT_JSON = \"test-results/tiers.json\";\n\nconst BOOL_FLAGS: Record<string, \"all\" | \"full\" | \"list\" | \"bail\" | \"failFast\" | \"strictNeeds\"> = {\n \"--all\": \"all\",\n \"--full\": \"full\",\n \"--list\": \"list\",\n \"--bail\": \"bail\",\n \"--fail-fast\": \"failFast\",\n \"--strict-needs\": \"strictNeeds\",\n};\n\n/** Narrow a raw `--order=` value to a {@link CaseOrder}, or null if unknown. */\nfunction parseOrder(value: string): CaseOrder | null {\n if (value === \"default\" || value === \"fast\" || value === \"cost\") return value;\n return null;\n}\n\nfunction listValue(arg: string, name: string): string[] {\n return arg.startsWith(name) ? arg.slice(name.length).split(\",\") : [];\n}\n\n/** Apply a value-bearing flag (`--name=value`, or bare `--json`). Returns false\n * if `arg` isn't one, so the caller can fall through to tier names. Exits(2) on\n * a malformed `--order=`. */\nfunction applyValueFlag(args: TierArgs, arg: string): boolean {\n if (arg === \"--json\") {\n args.json = DEFAULT_JSON;\n return true;\n }\n if (arg.startsWith(\"--json=\")) {\n args.json = arg.slice(\"--json=\".length);\n return true;\n }\n if (arg.startsWith(\"--tier=\")) {\n args.tiers.push(...listValue(arg, \"--tier=\"));\n return true;\n }\n if (arg.startsWith(\"--only=\")) {\n args.only.push(...listValue(arg, \"--only=\"));\n return true;\n }\n if (arg.startsWith(\"--order=\")) {\n const order = parseOrder(arg.slice(\"--order=\".length));\n if (order === null) {\n console.log(\"Unknown --order value (expected default, fast, or cost)\");\n process.exit(2);\n }\n args.order = order;\n return true;\n }\n return false;\n}\n\n/** Parse argv into {@link TierArgs}. Exits(2) on an unknown `--flag`. */\nexport function parseTierArgs(argv: string[]): TierArgs {\n const args: TierArgs = {\n tiers: [],\n only: [],\n all: false,\n full: false,\n list: false,\n bail: false,\n failFast: false,\n order: null,\n strictNeeds: false,\n json: null,\n };\n for (const arg of argv) {\n const boolKey = BOOL_FLAGS[arg];\n if (boolKey) {\n args[boolKey] = true;\n continue;\n }\n if (applyValueFlag(args, arg)) {\n continue;\n }\n if (arg.startsWith(\"-\")) {\n console.log(`Unknown flag: ${arg}`);\n process.exit(2);\n }\n args.tiers.push(arg);\n }\n return args;\n}\n",
7
7
  "/**\n * Zero-config tier discovery for a consumer's Polly project.\n *\n * `polly test --tier` from a consumer's project builds its {@link TierPlan} by\n * convention — no config required:\n * - unit `bun test` (or `bun test tests/unit` if that dir exists)\n * - integration `bun test tests/integration` (when the dir exists)\n * - browser the Polly browser runner over `*.browser.{ts,tsx}`\n * - e2e `scripts/e2e-*.{ts,tsx}` exporting `run(ctx)` — the same\n * contract Polly dogfoods, so consumer e2e scripts written with\n * `@fairfox/polly/test` helpers slot straight in.\n *\n * A tier only appears when its inputs exist, so a project with just unit tests\n * gets just a unit tier.\n */\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { CaseSpec, Tier, TierPlan } from \"./types\";\n\n/** Files matching `pattern` under `root`, excluding node_modules, sorted. */\nasync function globFiles(root: string, pattern: string): Promise<string[]> {\n const glob = new Bun.Glob(pattern);\n const out: string[] = [];\n for await (const file of glob.scan({ cwd: root, onlyFiles: true })) {\n if (file.includes(\"node_modules\") || file.startsWith(\"dist/\")) continue;\n out.push(file);\n }\n return out.sort();\n}\n\n/** Resolve the browser runner, preferring the bundled build. */\nfunction browserRunner(): string {\n const bundled = `${import.meta.dir}/../browser/run.js`;\n const source = `${import.meta.dir}/../browser/run.ts`;\n return existsSync(bundled) ? bundled : source;\n}\n\n/** A safe directory to hand the browser runner (never the project root, which\n * would make it scan node_modules). */\nfunction browserDir(root: string, files: string[]): string {\n if (existsSync(join(root, \"tests/browser\"))) return \"tests/browser\";\n if (existsSync(join(root, \"tests\"))) return \"tests\";\n return dirname(files[0] ?? \".\") || \".\";\n}\n\n/** `scripts/e2e-foo-bar.ts` → `foo-bar`. */\nfunction e2eId(file: string): string {\n const base = file.replace(/^.*\\//, \"\").replace(/\\.(ts|tsx)$/, \"\");\n return base.replace(/^e2e-/, \"\") || base;\n}\n\nexport async function discoverPlan(root: string): Promise<TierPlan> {\n const tiers: Tier[] = [];\n\n const hasUnitDir = existsSync(join(root, \"tests/unit\"));\n const hasIntegrationDir = existsSync(join(root, \"tests/integration\"));\n const testFiles = await globFiles(root, \"**/*.test.{ts,tsx}\");\n\n if (hasUnitDir) {\n tiers.push({\n name: \"unit\",\n description: \"bun test tests/unit\",\n cases: [\n { id: \"unit\", exec: { kind: \"command\", argv: [\"bun\", \"test\", \"tests/unit\"], cwd: root } },\n ],\n });\n } else if (testFiles.length > 0) {\n tiers.push({\n name: \"unit\",\n description: `bun test (${testFiles.length} files)`,\n cases: [{ id: \"unit\", exec: { kind: \"command\", argv: [\"bun\", \"test\"], cwd: root } }],\n });\n }\n\n if (hasIntegrationDir) {\n tiers.push({\n name: \"integration\",\n description: \"bun test tests/integration\",\n cases: [\n {\n id: \"integration\",\n exec: { kind: \"command\", argv: [\"bun\", \"test\", \"tests/integration\"], cwd: root },\n },\n ],\n });\n }\n\n const browserFiles = await globFiles(root, \"**/*.browser.{ts,tsx}\");\n if (browserFiles.length > 0) {\n tiers.push({\n name: \"browser\",\n description: `Puppeteer over ${browserFiles.length} *.browser file(s)`,\n timeoutMs: 180_000,\n cases: [\n {\n id: \"browser\",\n needs: [\"browser\"],\n exec: {\n kind: \"command\",\n argv: [\"bun\", browserRunner(), browserDir(root, browserFiles)],\n cwd: root,\n },\n },\n ],\n });\n }\n\n const e2eFiles = await globFiles(root, \"scripts/e2e-*.{ts,tsx}\");\n if (e2eFiles.length > 0) {\n const cases: CaseSpec[] = e2eFiles.map((file) => ({\n id: e2eId(file),\n tags: [\"e2e\"],\n exec: { kind: \"module\", modulePath: join(root, file) },\n }));\n tiers.push({\n name: \"e2e\",\n description: `run()-export scripts (${e2eFiles.length})`,\n concurrency: 2,\n timeoutMs: 240_000,\n cases,\n });\n }\n\n return { tiers };\n}\n",
8
8
  "/**\n * Host capability detection for need-gating.\n *\n * A case declaring `needs: [\"docker\"]` is skipped (not failed) when the host\n * can't satisfy it, unless `--strict-needs` is set. Detection is cached for the\n * lifetime of the process so a 30-case run probes `docker info` once.\n */\nimport type { Need } from \"./types\";\n\nconst cache = new Map<Need, boolean>();\n\nasync function commandSucceeds(argv: string[]): Promise<boolean> {\n try {\n const proc = Bun.spawn(argv, { stdout: \"ignore\", stderr: \"ignore\", stdin: \"ignore\" });\n return (await proc.exited) === 0;\n } catch {\n return false;\n }\n}\n\nasync function probe(need: Need): Promise<boolean> {\n switch (need) {\n case \"docker\":\n // `docker info` fails fast when the daemon is down, unlike `docker --version`.\n return commandSucceeds([\"docker\", \"info\"]);\n case \"browser\":\n // Puppeteer ships Chromium as a devDependency; assume present in-repo.\n // A real probe would resolve the executable path, but that pulls puppeteer\n // into the engine. Front-ends that need a stricter check can override.\n return true;\n case \"network\":\n return true;\n default:\n return false;\n }\n}\n\n/** Resolve whether a need is satisfied, memoised. */\nexport async function hasNeed(need: Need): Promise<boolean> {\n const cached = cache.get(need);\n if (cached !== undefined) return cached;\n const result = await probe(need);\n cache.set(need, result);\n return result;\n}\n\n/** First unmet need among `needs`, or null if all are satisfied. */\nexport async function firstUnmetNeed(needs: Need[] | undefined): Promise<Need | null> {\n for (const need of needs ?? []) {\n if (!(await hasNeed(need))) return need;\n }\n return null;\n}\n",
9
+ "/**\n * Within-tier case ordering.\n *\n * The engine drains a tier's cases through a bounded pool in array order, so\n * where a case sits decides when it launches. Reordering by a coarse cost hint\n * buys two different things depending on intent:\n *\n * - \"cost\" (heaviest first): the long poles launch in the first `concurrency`\n * slots and everything cheaper packs in behind them, so wall-clock collapses\n * toward the single slowest case instead of the sum. Use for a full run.\n * - \"fast\" (lightest first): cheap, high-signal cases run first, so under\n * soft-fail-fast they trip the abort soonest — you can't un-spawn a 4-minute\n * case, so you want it to *not* have started when a 2-second case fails.\n * - \"default\": registry definition order, unchanged.\n *\n * Pure and dependency-free on purpose: this is the one piece of the engine that\n * is worth unit-testing in isolation, and keeping it out of engine.ts keeps the\n * subprocess-heavy engine off the unit-coverage table.\n */\nimport type { CaseOrder, CaseSpec } from \"./types\";\n\nconst COST_WEIGHT: Record<NonNullable<CaseSpec[\"cost\"]>, number> = {\n light: 0,\n medium: 1,\n heavy: 2,\n};\n\n/** Weight of a case; unset cost is treated as \"medium\". */\nfunction weightOf(spec: CaseSpec): number {\n return COST_WEIGHT[spec.cost ?? \"medium\"];\n}\n\n/**\n * Return a copy of `cases` reordered per `order`. Stable: cases of equal weight\n * keep their original relative order, and \"default\" returns the input as-is.\n */\nexport function orderCases(cases: CaseSpec[], order: CaseOrder): CaseSpec[] {\n if (order === \"default\") return cases;\n const direction = order === \"cost\" ? -1 : 1; // cost → heaviest first; fast → lightest first\n return cases\n .map((spec, index) => ({ spec, index }))\n .sort((a, b) => (weightOf(a.spec) - weightOf(b.spec)) * direction || a.index - b.index)\n .map((entry) => entry.spec);\n}\n",
9
10
  "/**\n * The one shared constant between the engine and its subprocess worker.\n *\n * It lives in its own leaf module so the engine never has to *import* the\n * worker (only spawn it by path). If the engine imported the worker, a\n * `splitting: false` bundle would inline the worker's `import.meta.main`\n * self-exec block into the CLI bundle and run it on startup. Keeping the\n * sentinel here avoids that.\n */\nexport const SENTINEL = \"__TIER_RESULT__\";\n",
10
- "/**\n * The tiered test engine.\n *\n * Runs a {@link TierPlan} tier-by-tier in order. Within a tier, cases run with\n * bounded concurrency. Each case is its own subprocess (see worker.ts) so the\n * isolation the e2e scripts assume is preserved. Cases whose host needs are\n * unmet are skipped (logged), not failed, unless `strictNeeds` is set.\n */\nimport { firstUnmetNeed } from \"./detect\";\nimport { SENTINEL } from \"./protocol\";\nimport type {\n CaseOutcome,\n CaseReport,\n CaseSpec,\n EngineOptions,\n RunReport,\n Tier,\n TierPlan,\n} from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\n\nasync function workerPath(): Promise<string> {\n const bundled = `${import.meta.dir}/worker.js`;\n const source = `${import.meta.dir}/worker.ts`;\n return (await Bun.file(bundled).exists()) ? bundled : source;\n}\n\nfunction caseLabel(spec: CaseSpec): string {\n return spec.label ?? spec.id;\n}\n\nfunction caseMatches(spec: CaseSpec, only: string[] | undefined): boolean {\n if (!only || only.length === 0) return true;\n const haystacks = [spec.id, caseLabel(spec), ...(spec.tags ?? [])].map((s) => s.toLowerCase());\n return only.some((needle) => {\n const n = needle.toLowerCase();\n return haystacks.some((h) => h.includes(n));\n });\n}\n\ninterface SubprocOutcome {\n exitCode: number;\n stdout: string;\n timedOut: boolean;\n}\n\nasync function runSubprocess(\n argv: string[],\n opts: { cwd?: string; env: Record<string, string | undefined>; timeoutMs: number },\n onLine: (line: string) => void\n): Promise<SubprocOutcome> {\n const proc = Bun.spawn(argv, {\n cwd: opts.cwd,\n env: opts.env,\n stdout: \"pipe\",\n stderr: \"pipe\",\n stdin: \"ignore\",\n });\n\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n proc.kill();\n }, opts.timeoutMs);\n\n const chunks: string[] = [];\n const pump = async (stream: ReadableStream<Uint8Array>): Promise<void> => {\n const decoder = new TextDecoder();\n let buffered = \"\";\n for await (const chunk of stream) {\n buffered += decoder.decode(chunk, { stream: true });\n let nl = buffered.indexOf(\"\\n\");\n while (nl !== -1) {\n const line = buffered.slice(0, nl);\n chunks.push(line);\n onLine(line);\n buffered = buffered.slice(nl + 1);\n nl = buffered.indexOf(\"\\n\");\n }\n }\n if (buffered) {\n chunks.push(buffered);\n onLine(buffered);\n }\n };\n\n await Promise.all([pump(proc.stdout), pump(proc.stderr)]);\n const exitCode = await proc.exited;\n clearTimeout(timer);\n\n return { exitCode, stdout: chunks.join(\"\\n\"), timedOut };\n}\n\nfunction parseSentinel(stdout: string): { pass: boolean; message?: string } | null {\n const idx = stdout.lastIndexOf(SENTINEL);\n if (idx === -1) return null;\n const after = stdout.slice(idx + SENTINEL.length);\n const newline = after.indexOf(\"\\n\");\n const json = newline === -1 ? after : after.slice(0, newline);\n try {\n const parsed = JSON.parse(json.trim());\n return { pass: Boolean(parsed.pass), message: parsed.message };\n } catch {\n return null;\n }\n}\n\ninterface Verdict {\n outcome: CaseOutcome;\n message?: string;\n}\n\nconst VERDICT_ICON: Record<CaseOutcome, string> = {\n pass: \"✓\",\n fail: \"✗\",\n skip: \"⊘\",\n timeout: \"⏱\",\n};\n\n/** Resolve argv + cwd for a case, falling back to the run-wide cwd. */\nfunction buildInvocation(\n spec: CaseSpec,\n worker: string,\n options: EngineOptions\n): { argv: string[]; cwd?: string } {\n if (spec.exec.kind === \"module\") {\n return { argv: [\"bun\", worker, spec.exec.modulePath, spec.id], cwd: options.cwd };\n }\n return { argv: spec.exec.argv, cwd: spec.exec.cwd ?? options.cwd };\n}\n\n/** Decide pass/fail/timeout, preferring the sentinel over the exit code. */\nfunction decideVerdict(spec: CaseSpec, result: SubprocOutcome, timeoutMs: number): Verdict {\n if (result.timedOut) return { outcome: \"timeout\", message: `timed out after ${timeoutMs}ms` };\n const sentinel = spec.exec.kind === \"module\" ? parseSentinel(result.stdout) : null;\n const pass = sentinel ? sentinel.pass : result.exitCode === 0;\n if (pass) return { outcome: \"pass\" };\n return { outcome: \"fail\", message: sentinel?.message ?? `exit code ${result.exitCode}` };\n}\n\nasync function runOneCase(\n spec: CaseSpec,\n tier: Tier,\n options: EngineOptions,\n worker: string\n): Promise<CaseReport> {\n const label = caseLabel(spec);\n const log = options.log ?? ((m: string) => console.log(m));\n\n const unmet = await firstUnmetNeed(spec.needs);\n if (unmet && !options.strictNeeds) {\n log(` ⊘ ${label} — skipped (needs ${unmet})`);\n return {\n tier: tier.name,\n id: spec.id,\n label,\n outcome: \"skip\",\n durationMs: 0,\n skipReason: `needs ${unmet}`,\n };\n }\n\n const timeoutMs = spec.timeoutMs ?? tier.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const env: Record<string, string | undefined> = { ...process.env, ...options.env };\n const { argv, cwd } = buildInvocation(spec, worker, options);\n\n const started = performance.now();\n const prefix = ` [${spec.id}] `;\n const result = await runSubprocess(argv, { cwd, env, timeoutMs }, (line) => {\n if (!line.includes(SENTINEL) && line.trim()) log(prefix + line);\n });\n const durationMs = Math.round(performance.now() - started);\n\n const verdict = decideVerdict(spec, result, timeoutMs);\n const tail = verdict.message ? ` — ${verdict.message}` : \"\";\n log(` ${VERDICT_ICON[verdict.outcome]} ${label} (${durationMs}ms)${tail}`);\n return {\n tier: tier.name,\n id: spec.id,\n label,\n outcome: verdict.outcome,\n durationMs,\n message: verdict.message,\n };\n}\n\nasync function runTier(tier: Tier, options: EngineOptions, worker: string): Promise<CaseReport[]> {\n const log = options.log ?? ((m: string) => console.log(m));\n const selected = tier.cases.filter((c) => caseMatches(c, options.only));\n if (selected.length === 0) return [];\n\n log(\n `\\n▶ ${tier.name}${tier.description ? ` — ${tier.description}` : \"\"} (${selected.length} case${selected.length === 1 ? \"\" : \"s\"})`\n );\n\n const concurrency = Math.max(1, tier.concurrency ?? 1);\n const reports: CaseReport[] = new Array(selected.length);\n let next = 0;\n async function worker_loop(): Promise<void> {\n while (true) {\n const i = next++;\n const spec = selected[i];\n if (!spec) return;\n reports[i] = await runOneCase(spec, tier, options, worker);\n }\n }\n await Promise.all(Array.from({ length: Math.min(concurrency, selected.length) }, worker_loop));\n return reports;\n}\n\n/** Run a plan and return a structured report. Does not exit the process. */\nexport async function runPlan(plan: TierPlan, options: EngineOptions = {}): Promise<RunReport> {\n const log = options.log ?? ((m: string) => console.log(m));\n const worker = await workerPath();\n const wanted = options.tiers && options.tiers.length > 0 ? new Set(options.tiers) : null;\n\n const started = performance.now();\n const all: CaseReport[] = [];\n for (const tier of plan.tiers) {\n if (wanted && !wanted.has(tier.name)) continue;\n const reports = await runTier(tier, options, worker);\n all.push(...reports);\n if (options.bail && reports.some((r) => r.outcome === \"fail\" || r.outcome === \"timeout\")) {\n log(`\\n⏹ bailing after failing tier \"${tier.name}\"`);\n break;\n }\n }\n\n const durationMs = Math.round(performance.now() - started);\n const passed = all.filter((r) => r.outcome === \"pass\").length;\n const failed = all.filter((r) => r.outcome === \"fail\" || r.outcome === \"timeout\").length;\n const skipped = all.filter((r) => r.outcome === \"skip\").length;\n return { cases: all, passed, failed, skipped, durationMs, ok: failed === 0 };\n}\n",
11
- "/**\n * Reporting for engine runs: a human summary table (with per-case timing and a\n * slowest-N list, the data the old `&&` chains never captured) and a JSON\n * artefact for tooling. No cloud reporters — everything lands on disk locally.\n */\nimport type { RunReport, TierPlan } from \"./types\";\n\nconst ICON = { pass: \"✓\", fail: \"✗\", skip: \"⊘\", timeout: \"⏱\" } as const;\n\n/** One-line-per-case summary plus totals and slowest cases. */\nexport function formatSummary(report: RunReport): string {\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(\"── results ─────────────────────────────────\");\n for (const c of report.cases) {\n const time = c.outcome === \"skip\" ? \"\" : `${c.durationMs}ms`;\n const tail = c.outcome === \"skip\" ? ` (${c.skipReason})` : c.message ? ` — ${c.message}` : \"\";\n lines.push(`${ICON[c.outcome]} ${c.tier} › ${c.label} ${time}${tail}`);\n }\n\n const ran = report.cases.filter((c) => c.outcome !== \"skip\");\n const slowest = [...ran].sort((a, b) => b.durationMs - a.durationMs).slice(0, 5);\n if (slowest.length > 0) {\n lines.push(\"\");\n lines.push(\"slowest:\");\n for (const c of slowest) lines.push(` ${c.durationMs}ms ${c.tier} › ${c.label}`);\n }\n\n lines.push(\"\");\n lines.push(\n `${report.ok ? \"PASS\" : \"FAIL\"} ${report.passed} passed, ${report.failed} failed, ` +\n `${report.skipped} skipped in ${(report.durationMs / 1000).toFixed(1)}s`\n );\n return lines.join(\"\\n\");\n}\n\n/** Stable JSON artefact written to test-results/. */\nexport function toJSON(report: RunReport): string {\n return JSON.stringify(report, null, 2);\n}\n\n/** `--list` output: tiers and their cases without running anything. */\nexport function formatPlan(plan: TierPlan): string {\n const lines: string[] = [\"Tiers (run order):\", \"\"];\n for (const tier of plan.tiers) {\n const conc = tier.concurrency && tier.concurrency > 1 ? ` ×${tier.concurrency}` : \"\";\n lines.push(`${tier.name}${conc}${tier.description ? ` — ${tier.description}` : \"\"}`);\n for (const c of tier.cases) {\n const needs = c.needs && c.needs.length > 0 ? ` (needs ${c.needs.join(\", \")})` : \"\";\n lines.push(` ${c.id}${needs}`);\n }\n lines.push(\"\");\n }\n return lines.join(\"\\n\");\n}\n"
11
+ "/**\n * The tiered test engine.\n *\n * Runs a {@link TierPlan} tier-by-tier in order. Within a tier, cases run with\n * bounded concurrency. Each case is its own subprocess (see worker.ts) so the\n * isolation the e2e scripts assume is preserved. Cases whose host needs are\n * unmet are skipped (logged), not failed, unless `strictNeeds` is set.\n */\nimport { firstUnmetNeed } from \"./detect\";\nimport { orderCases } from \"./order\";\nimport { SENTINEL } from \"./protocol\";\nimport type {\n CaseOutcome,\n CaseReport,\n CaseSpec,\n EngineOptions,\n RunReport,\n Tier,\n TierPlan,\n} from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\n\nasync function workerPath(): Promise<string> {\n const bundled = `${import.meta.dir}/worker.js`;\n const source = `${import.meta.dir}/worker.ts`;\n return (await Bun.file(bundled).exists()) ? bundled : source;\n}\n\nfunction caseLabel(spec: CaseSpec): string {\n return spec.label ?? spec.id;\n}\n\nfunction caseMatches(spec: CaseSpec, only: string[] | undefined): boolean {\n if (!only || only.length === 0) return true;\n const haystacks = [spec.id, caseLabel(spec), ...(spec.tags ?? [])].map((s) => s.toLowerCase());\n return only.some((needle) => {\n const n = needle.toLowerCase();\n return haystacks.some((h) => h.includes(n));\n });\n}\n\ninterface SubprocOutcome {\n exitCode: number;\n stdout: string;\n timedOut: boolean;\n}\n\nasync function runSubprocess(\n argv: string[],\n opts: { cwd?: string; env: Record<string, string | undefined>; timeoutMs: number },\n onLine: (line: string) => void\n): Promise<SubprocOutcome> {\n const proc = Bun.spawn(argv, {\n cwd: opts.cwd,\n env: opts.env,\n stdout: \"pipe\",\n stderr: \"pipe\",\n stdin: \"ignore\",\n });\n\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n proc.kill();\n }, opts.timeoutMs);\n\n const chunks: string[] = [];\n const pump = async (stream: ReadableStream<Uint8Array>): Promise<void> => {\n const decoder = new TextDecoder();\n let buffered = \"\";\n for await (const chunk of stream) {\n buffered += decoder.decode(chunk, { stream: true });\n let nl = buffered.indexOf(\"\\n\");\n while (nl !== -1) {\n const line = buffered.slice(0, nl);\n chunks.push(line);\n onLine(line);\n buffered = buffered.slice(nl + 1);\n nl = buffered.indexOf(\"\\n\");\n }\n }\n if (buffered) {\n chunks.push(buffered);\n onLine(buffered);\n }\n };\n\n await Promise.all([pump(proc.stdout), pump(proc.stderr)]);\n const exitCode = await proc.exited;\n clearTimeout(timer);\n\n return { exitCode, stdout: chunks.join(\"\\n\"), timedOut };\n}\n\nfunction parseSentinel(stdout: string): { pass: boolean; message?: string } | null {\n const idx = stdout.lastIndexOf(SENTINEL);\n if (idx === -1) return null;\n const after = stdout.slice(idx + SENTINEL.length);\n const newline = after.indexOf(\"\\n\");\n const json = newline === -1 ? after : after.slice(0, newline);\n try {\n const parsed = JSON.parse(json.trim());\n return { pass: Boolean(parsed.pass), message: parsed.message };\n } catch {\n return null;\n }\n}\n\ninterface Verdict {\n outcome: CaseOutcome;\n message?: string;\n}\n\nconst VERDICT_ICON: Record<CaseOutcome, string> = {\n pass: \"✓\",\n fail: \"✗\",\n skip: \"⊘\",\n timeout: \"⏱\",\n};\n\n/** Resolve argv + cwd for a case, falling back to the run-wide cwd. */\nfunction buildInvocation(\n spec: CaseSpec,\n worker: string,\n options: EngineOptions\n): { argv: string[]; cwd?: string } {\n if (spec.exec.kind === \"module\") {\n return { argv: [\"bun\", worker, spec.exec.modulePath, spec.id], cwd: options.cwd };\n }\n return { argv: spec.exec.argv, cwd: spec.exec.cwd ?? options.cwd };\n}\n\n/** Decide pass/fail/timeout, preferring the sentinel over the exit code. */\nfunction decideVerdict(spec: CaseSpec, result: SubprocOutcome, timeoutMs: number): Verdict {\n if (result.timedOut) return { outcome: \"timeout\", message: `timed out after ${timeoutMs}ms` };\n const sentinel = spec.exec.kind === \"module\" ? parseSentinel(result.stdout) : null;\n const pass = sentinel ? sentinel.pass : result.exitCode === 0;\n if (pass) return { outcome: \"pass\" };\n return { outcome: \"fail\", message: sentinel?.message ?? `exit code ${result.exitCode}` };\n}\n\nasync function runOneCase(\n spec: CaseSpec,\n tier: Tier,\n options: EngineOptions,\n worker: string\n): Promise<CaseReport> {\n const label = caseLabel(spec);\n const log = options.log ?? ((m: string) => console.log(m));\n\n const unmet = await firstUnmetNeed(spec.needs);\n if (unmet && !options.strictNeeds) {\n log(` ⊘ ${label} — skipped (needs ${unmet})`);\n return {\n tier: tier.name,\n id: spec.id,\n label,\n outcome: \"skip\",\n durationMs: 0,\n skipReason: `needs ${unmet}`,\n };\n }\n\n const timeoutMs = spec.timeoutMs ?? tier.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const env: Record<string, string | undefined> = { ...process.env, ...options.env };\n const { argv, cwd } = buildInvocation(spec, worker, options);\n\n const started = performance.now();\n const prefix = ` [${spec.id}] `;\n const result = await runSubprocess(argv, { cwd, env, timeoutMs }, (line) => {\n if (!line.includes(SENTINEL) && line.trim()) log(prefix + line);\n });\n const durationMs = Math.round(performance.now() - started);\n\n const verdict = decideVerdict(spec, result, timeoutMs);\n const tail = verdict.message ? ` — ${verdict.message}` : \"\";\n log(` ${VERDICT_ICON[verdict.outcome]} ${label} (${durationMs}ms)${tail}`);\n return {\n tier: tier.name,\n id: spec.id,\n label,\n outcome: verdict.outcome,\n durationMs,\n message: verdict.message,\n };\n}\n\nasync function runTier(tier: Tier, options: EngineOptions, worker: string): Promise<CaseReport[]> {\n const log = options.log ?? ((m: string) => console.log(m));\n const matched = tier.cases.filter((c) => caseMatches(c, options.only));\n if (matched.length === 0) return [];\n const selected = orderCases(matched, options.order ?? \"default\");\n\n log(\n `\\n▶ ${tier.name}${tier.description ? ` — ${tier.description}` : \"\"} (${selected.length} case${selected.length === 1 ? \"\" : \"s\"})`\n );\n\n const concurrency = Math.max(1, tier.concurrency ?? 1);\n const failFast = options.failFast ?? false;\n // Slots left empty when soft-fail-fast aborts before claiming them; filtered out below.\n const reports: (CaseReport | undefined)[] = new Array(selected.length);\n let next = 0;\n let aborted = false;\n async function worker_loop(): Promise<void> {\n while (!aborted) {\n const i = next++;\n const spec = selected[i];\n if (!spec) return;\n const report = await runOneCase(spec, tier, options, worker);\n reports[i] = report;\n if (failFast && (report.outcome === \"fail\" || report.outcome === \"timeout\")) {\n aborted = true; // soft: in-flight siblings finish, but no new case is claimed\n }\n }\n }\n await Promise.all(Array.from({ length: Math.min(concurrency, selected.length) }, worker_loop));\n const done = reports.filter((r): r is CaseReport => r !== undefined);\n if (aborted && done.length < selected.length) {\n log(\n ` ⏹ fail-fast: stopped after a failure — ${selected.length - done.length} case(s) not run`\n );\n }\n return done;\n}\n\n/** Run a plan and return a structured report. Does not exit the process. */\nexport async function runPlan(plan: TierPlan, options: EngineOptions = {}): Promise<RunReport> {\n const log = options.log ?? ((m: string) => console.log(m));\n const worker = await workerPath();\n const wanted = options.tiers && options.tiers.length > 0 ? new Set(options.tiers) : null;\n\n const started = performance.now();\n const stopOnFail = Boolean(options.bail || options.failFast);\n const all: CaseReport[] = [];\n for (const tier of plan.tiers) {\n if (wanted && !wanted.has(tier.name)) continue;\n const reports = await runTier(tier, options, worker);\n all.push(...reports);\n if (stopOnFail && reports.some((r) => r.outcome === \"fail\" || r.outcome === \"timeout\")) {\n log(\n `\\n⏹ ${options.failFast ? \"fail-fast\" : \"bail\"}: stopping after failing tier \"${tier.name}\"`\n );\n break;\n }\n }\n\n const durationMs = Math.round(performance.now() - started);\n const passed = all.filter((r) => r.outcome === \"pass\").length;\n const failed = all.filter((r) => r.outcome === \"fail\" || r.outcome === \"timeout\").length;\n const skipped = all.filter((r) => r.outcome === \"skip\").length;\n return { cases: all, passed, failed, skipped, durationMs, ok: failed === 0 };\n}\n",
12
+ "/**\n * Reporting for engine runs: a human summary table (with per-case timing and a\n * slowest-N list, the data the old `&&` chains never captured) and a JSON\n * artefact for tooling. No cloud reporters — everything lands on disk locally.\n */\nimport type { RunReport, TierPlan } from \"./types\";\n\nconst ICON = { pass: \"✓\", fail: \"✗\", skip: \"⊘\", timeout: \"⏱\" } as const;\n\n/** One-line-per-case summary plus totals and slowest cases. */\nexport function formatSummary(report: RunReport): string {\n const lines: string[] = [];\n lines.push(\"\");\n lines.push(\"── results ─────────────────────────────────\");\n for (const c of report.cases) {\n const time = c.outcome === \"skip\" ? \"\" : `${c.durationMs}ms`;\n const tail = c.outcome === \"skip\" ? ` (${c.skipReason})` : c.message ? ` — ${c.message}` : \"\";\n lines.push(`${ICON[c.outcome]} ${c.tier} › ${c.label} ${time}${tail}`);\n }\n\n const ran = report.cases.filter((c) => c.outcome !== \"skip\");\n const slowest = [...ran].sort((a, b) => b.durationMs - a.durationMs).slice(0, 5);\n if (slowest.length > 0) {\n lines.push(\"\");\n lines.push(\"slowest:\");\n for (const c of slowest) lines.push(` ${c.durationMs}ms ${c.tier} › ${c.label}`);\n }\n\n lines.push(\"\");\n lines.push(\n `${report.ok ? \"PASS\" : \"FAIL\"} ${report.passed} passed, ${report.failed} failed, ` +\n `${report.skipped} skipped in ${(report.durationMs / 1000).toFixed(1)}s`\n );\n return lines.join(\"\\n\");\n}\n\n/** Stable JSON artefact written to test-results/. */\nexport function toJSON(report: RunReport): string {\n return JSON.stringify(report, null, 2);\n}\n\n/** `--list` output: tiers and their cases without running anything. */\nexport function formatPlan(plan: TierPlan): string {\n const lines: string[] = [\"Tiers (run order):\", \"\"];\n for (const tier of plan.tiers) {\n const conc = tier.concurrency && tier.concurrency > 1 ? ` ×${tier.concurrency}` : \"\";\n lines.push(`${tier.name}${conc}${tier.description ? ` — ${tier.description}` : \"\"}`);\n for (const c of tier.cases) {\n const needs = c.needs && c.needs.length > 0 ? ` (needs ${c.needs.join(\", \")})` : \"\";\n const cost = c.cost ? ` [${c.cost}]` : \"\";\n lines.push(` ${c.id}${cost}${needs}`);\n }\n lines.push(\"\");\n }\n return lines.join(\"\\n\");\n}\n"
12
13
  ],
13
- "mappings": "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",
14
- "debugId": "170074AB01C8CBEF64756E2164756E21",
14
+ "mappings": "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",
15
+ "debugId": "CD4A2E88C15B8A6864756E2164756E21",
15
16
  "names": []
16
17
  }
@@ -10,5 +10,6 @@ export { DEFAULT_JSON, parseTierArgs, type TierArgs } from "./args";
10
10
  export { firstUnmetNeed, hasNeed } from "./detect";
11
11
  export { discoverPlan } from "./discover";
12
12
  export { runPlan } from "./engine";
13
+ export { orderCases } from "./order";
13
14
  export { formatPlan, formatSummary, toJSON } from "./reporter";
14
- export type { CaseExec, CaseReport, CaseSpec, EngineOptions, Need, RunReport, Tier, TierPlan, } from "./types";
15
+ export type { CaseExec, CaseOrder, CaseReport, CaseSpec, EngineOptions, Need, RunReport, Tier, TierPlan, } from "./types";
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Within-tier case ordering.
3
+ *
4
+ * The engine drains a tier's cases through a bounded pool in array order, so
5
+ * where a case sits decides when it launches. Reordering by a coarse cost hint
6
+ * buys two different things depending on intent:
7
+ *
8
+ * - "cost" (heaviest first): the long poles launch in the first `concurrency`
9
+ * slots and everything cheaper packs in behind them, so wall-clock collapses
10
+ * toward the single slowest case instead of the sum. Use for a full run.
11
+ * - "fast" (lightest first): cheap, high-signal cases run first, so under
12
+ * soft-fail-fast they trip the abort soonest — you can't un-spawn a 4-minute
13
+ * case, so you want it to *not* have started when a 2-second case fails.
14
+ * - "default": registry definition order, unchanged.
15
+ *
16
+ * Pure and dependency-free on purpose: this is the one piece of the engine that
17
+ * is worth unit-testing in isolation, and keeping it out of engine.ts keeps the
18
+ * subprocess-heavy engine off the unit-coverage table.
19
+ */
20
+ import type { CaseOrder, CaseSpec } from "./types";
21
+ /**
22
+ * Return a copy of `cases` reordered per `order`. Stable: cases of equal weight
23
+ * keep their original relative order, and "default" returns the input as-is.
24
+ */
25
+ export declare function orderCases(cases: CaseSpec[], order: CaseOrder): CaseSpec[];
@@ -39,6 +39,11 @@ export interface CaseSpec {
39
39
  needs?: Need[];
40
40
  /** Per-case timeout. Defaults to the engine's tier default. */
41
41
  timeoutMs?: number;
42
+ /**
43
+ * Coarse cost hint consumed by `--order` (see order.ts). Unset = "medium".
44
+ * A scheduling hint, not a measurement — tune from `--json` durations.
45
+ */
46
+ cost?: "light" | "medium" | "heavy";
42
47
  exec: CaseExec;
43
48
  }
44
49
  /** An ordered group of cases sharing a realism level. */
@@ -57,6 +62,8 @@ export interface TierPlan {
57
62
  tiers: Tier[];
58
63
  }
59
64
  export type CaseOutcome = "pass" | "fail" | "skip" | "timeout";
65
+ /** How cases are ordered within a tier before the pool drains them. */
66
+ export type CaseOrder = "default" | "fast" | "cost";
60
67
  export interface CaseReport {
61
68
  tier: string;
62
69
  id: string;
@@ -81,8 +88,16 @@ export interface EngineOptions {
81
88
  tiers?: string[];
82
89
  /** Only run cases whose id/label/tags match one of these substrings. */
83
90
  only?: string[];
91
+ /** Order cases within each tier. Default "default" (definition order). */
92
+ order?: CaseOrder;
84
93
  /** Stop after the first tier that has a failure. */
85
94
  bail?: boolean;
95
+ /**
96
+ * Soft fail-fast: on the first failing case, the tier's pool stops *claiming*
97
+ * new cases (in-flight ones finish) and the run stops after that tier. Unlike
98
+ * `bail`, which lets every case in the failing tier finish first.
99
+ */
100
+ failFast?: boolean;
86
101
  /** Treat unmet-need skips as failures (CI-strict). Default false. */
87
102
  strictNeeds?: boolean;
88
103
  /** Forwarded into each case's environment. */
@@ -7923,7 +7923,7 @@ function displaySetupSuccess(configPath) {
7923
7923
  console.log();
7924
7924
  console.log(" 1. Review the generated configuration file");
7925
7925
  console.log(" 2. Fill in values marked with /* CONFIGURE */");
7926
- console.log(" 3. Run 'bun verify' to check your configuration");
7926
+ console.log(" 3. Run 'polly verify' to check your configuration");
7927
7927
  console.log();
7928
7928
  console.log(color("\uD83D\uDCA1 Tip:", COLORS.gray));
7929
7929
  console.log(color(" Look for comments explaining what each field needs.", COLORS.gray));
@@ -7938,7 +7938,7 @@ async function validateCommand() {
7938
7938
  if (result.valid) {
7939
7939
  console.log(color(`✅ Configuration is complete and valid!
7940
7940
  `, COLORS.green));
7941
- console.log(" You can now run 'bun verify' to start verification.");
7941
+ console.log(" You can now run 'polly verify' to start verification.");
7942
7942
  console.log();
7943
7943
  return;
7944
7944
  }
@@ -8162,8 +8162,8 @@ async function verifyCommand() {
8162
8162
  console.log(color(` ... and ${errors.length - 3} more error(s)`, COLORS.gray));
8163
8163
  console.log();
8164
8164
  }
8165
- console.log(" Run 'bun verify --validate' to see all issues");
8166
- console.log(" Run 'bun verify --setup' to regenerate configuration");
8165
+ console.log(" Run 'polly verify --validate' to see all issues");
8166
+ console.log(" Run 'polly verify --setup' to regenerate configuration");
8167
8167
  console.log();
8168
8168
  process.exit(1);
8169
8169
  }
@@ -8613,36 +8613,41 @@ function displayVerificationResults(result, specDir) {
8613
8613
  }
8614
8614
  function showHelp() {
8615
8615
  console.log(`
8616
- ${color("bun verify", COLORS.blue)} - Formal verification for web extensions
8616
+ ${color("polly verify", COLORS.blue)} - Formal verification for web extensions
8617
+
8618
+ Tests sample a few executions; a model checker explores every reachable state.
8619
+ This compiles your handlers and state into TLA+ and runs TLC to prove safety
8620
+ invariants hold under all interleavings — the ordering and concurrency bugs
8621
+ tests rarely reach.
8617
8622
 
8618
8623
  ${color("Commands:", COLORS.blue)}
8619
8624
 
8620
- ${color("bun verify", COLORS.green)}
8625
+ ${color("polly verify", COLORS.green)}
8621
8626
  Run verification (validates config, generates specs, runs TLC)
8622
8627
 
8623
- ${color("bun verify --strict", COLORS.green)}
8628
+ ${color("polly verify --strict", COLORS.green)}
8624
8629
  Fail closed (non-zero exit) on model-coverage gaps: a declared state
8625
8630
  field no handler writes, or an unverified $meshState/$peerState predicate.
8626
8631
  Also via ${color("POLLY_VERIFY_STRICT=1", COLORS.yellow)}.
8627
8632
 
8628
- ${color("bun verify --setup", COLORS.green)}
8633
+ ${color("polly verify --setup", COLORS.green)}
8629
8634
  Analyze codebase and generate configuration file
8630
8635
 
8631
- ${color("bun verify --validate", COLORS.green)}
8636
+ ${color("polly verify --validate", COLORS.green)}
8632
8637
  Validate existing configuration without running verification
8633
8638
 
8634
- ${color("bun verify --estimate", COLORS.green)}
8639
+ ${color("polly verify --estimate", COLORS.green)}
8635
8640
  Estimate state space without running TLC
8636
8641
 
8637
- ${color("bun verify --help", COLORS.green)}
8642
+ ${color("polly verify --help", COLORS.green)}
8638
8643
  Show this help message
8639
8644
 
8640
8645
  ${color("Getting Started:", COLORS.blue)}
8641
8646
 
8642
- 1. Run ${color("bun verify --setup", COLORS.green)} to generate configuration
8647
+ 1. Run ${color("polly verify --setup", COLORS.green)} to generate configuration
8643
8648
  2. Review ${color("specs/verification.config.ts", COLORS.blue)} and fill in marked fields
8644
- 3. Run ${color("bun verify --validate", COLORS.green)} to check your configuration
8645
- 4. Run ${color("bun verify", COLORS.green)} to start verification
8649
+ 3. Run ${color("polly verify --validate", COLORS.green)} to check your configuration
8650
+ 4. Run ${color("polly verify", COLORS.green)} to start verification
8646
8651
 
8647
8652
  ${color("Configuration Help:", COLORS.blue)}
8648
8653
 
@@ -8688,4 +8693,4 @@ main().catch((error) => {
8688
8693
  process.exit(1);
8689
8694
  });
8690
8695
 
8691
- //# debugId=9530CFE43867B27164756E2164756E21
8696
+ //# debugId=EBD97C743E15B6D964756E2164756E21