@fairfox/polly 0.85.1 → 0.86.0

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.
Files changed (120) hide show
  1. package/dist/cli/polly.js.map +1 -1
  2. package/dist/gallery/gallery.css +1 -1
  3. package/dist/gallery/gallery.js +2 -27
  4. package/dist/scripts/build-extension.js.map +1 -1
  5. package/dist/src/actions/index.js +34 -32
  6. package/dist/src/actions/index.js.map +2 -2
  7. package/dist/src/background/index.js +24 -22
  8. package/dist/src/background/index.js.map +2 -2
  9. package/dist/src/background/message-router.js +21 -19
  10. package/dist/src/background/message-router.js.map +2 -2
  11. package/dist/src/client/index.js +9 -7
  12. package/dist/src/client/index.js.map +3 -3
  13. package/dist/src/client/wrapper.d.ts +3 -3
  14. package/dist/src/elysia/index.d.ts +1 -1
  15. package/dist/src/elysia/index.js +25 -23
  16. package/dist/src/elysia/index.js.map +2 -2
  17. package/dist/src/elysia/types.d.ts +11 -2
  18. package/dist/src/index.js +68 -64
  19. package/dist/src/index.js.map +3 -3
  20. package/dist/src/mesh-node.js +6 -6
  21. package/dist/src/mesh-node.js.map +1 -1
  22. package/dist/src/mesh.js +92 -90
  23. package/dist/src/mesh.js.map +2 -2
  24. package/dist/src/peer.js +83 -52
  25. package/dist/src/peer.js.map +3 -3
  26. package/dist/src/polly-ui/index.css +1 -1
  27. package/dist/src/polly-ui/index.js +37 -35
  28. package/dist/src/polly-ui/index.js.map +2 -2
  29. package/dist/src/polly-ui/markdown.js +233 -96
  30. package/dist/src/polly-ui/markdown.js.map +4 -4
  31. package/dist/src/polly-ui/styles.css +1 -1
  32. package/dist/src/shared/adapters/index.js +30 -28
  33. package/dist/src/shared/adapters/index.js.map +2 -2
  34. package/dist/src/shared/lib/context-helpers.js +23 -21
  35. package/dist/src/shared/lib/context-helpers.js.map +2 -2
  36. package/dist/src/shared/lib/errors.js +16 -14
  37. package/dist/src/shared/lib/errors.js.map +2 -2
  38. package/dist/src/shared/lib/guards.js +11 -9
  39. package/dist/src/shared/lib/guards.js.map +2 -2
  40. package/dist/src/shared/lib/message-bus.js +24 -22
  41. package/dist/src/shared/lib/message-bus.js.map +2 -2
  42. package/dist/src/shared/lib/peer-relay-adapter.d.ts +6 -0
  43. package/dist/src/shared/lib/resource.js +19 -15
  44. package/dist/src/shared/lib/resource.js.map +3 -3
  45. package/dist/src/shared/lib/state.js +26 -22
  46. package/dist/src/shared/lib/state.js.map +3 -3
  47. package/dist/src/shared/lib/test-helpers.js +11 -9
  48. package/dist/src/shared/lib/test-helpers.js.map +2 -2
  49. package/dist/src/shared/state/app-state.js +22 -18
  50. package/dist/src/shared/state/app-state.js.map +3 -3
  51. package/dist/src/shared/types/messages.js +11 -9
  52. package/dist/src/shared/types/messages.js.map +2 -2
  53. package/dist/tools/bdd/src/cli.js +44 -1
  54. package/dist/tools/bdd/src/cli.js.map +4 -4
  55. package/dist/tools/bdd/src/index.js +54 -11
  56. package/dist/tools/bdd/src/index.js.map +4 -4
  57. package/dist/tools/gallery/src/cli.js +1 -1
  58. package/dist/tools/gallery/src/cli.js.map +2 -2
  59. package/dist/tools/init/src/cli.js +1 -1
  60. package/dist/tools/init/src/cli.js.map +2 -2
  61. package/dist/tools/mutate/src/cli.js +1 -1
  62. package/dist/tools/mutate/src/cli.js.map +2 -2
  63. package/dist/tools/mutate/src/index.js +8 -8
  64. package/dist/tools/mutate/src/index.js.map +2 -2
  65. package/dist/tools/quality/src/cli.js +3 -2
  66. package/dist/tools/quality/src/cli.js.map +3 -3
  67. package/dist/tools/quality/src/index.js +37 -36
  68. package/dist/tools/quality/src/index.js.map +3 -3
  69. package/dist/tools/test/src/adapters/index.js +19 -17
  70. package/dist/tools/test/src/adapters/index.js.map +2 -2
  71. package/dist/tools/test/src/browser/index.js +15 -13
  72. package/dist/tools/test/src/browser/index.js.map +2 -2
  73. package/dist/tools/test/src/browser/run.js +12 -3
  74. package/dist/tools/test/src/browser/run.js.map +5 -4
  75. package/dist/tools/test/src/contrast/index.js +14 -12
  76. package/dist/tools/test/src/contrast/index.js.map +2 -2
  77. package/dist/tools/test/src/coverage-policy/cli.js +5 -5
  78. package/dist/tools/test/src/coverage-policy/cli.js.map +2 -2
  79. package/dist/tools/test/src/coverage-policy/index.js +12 -12
  80. package/dist/tools/test/src/coverage-policy/index.js.map +1 -1
  81. package/dist/tools/test/src/e2e-mesh/index.js +88 -50
  82. package/dist/tools/test/src/e2e-mesh/index.js.map +6 -5
  83. package/dist/tools/test/src/e2e-mesh/with-relay.d.ts +1 -1
  84. package/dist/tools/test/src/e2e-relay/index.js +3 -3
  85. package/dist/tools/test/src/e2e-relay/index.js.map +2 -2
  86. package/dist/tools/test/src/e2e-shared/ephemeral-port.d.ts +73 -0
  87. package/dist/tools/test/src/e2e-shared/index.d.ts +1 -0
  88. package/dist/tools/test/src/index.d.ts +1 -0
  89. package/dist/tools/test/src/index.js +68 -24
  90. package/dist/tools/test/src/index.js.map +4 -3
  91. package/dist/tools/test/src/test-utils.js +14 -12
  92. package/dist/tools/test/src/test-utils.js.map +2 -2
  93. package/dist/tools/test/src/tiers/budget.d.ts +32 -0
  94. package/dist/tools/test/src/tiers/cli.js +35 -5
  95. package/dist/tools/test/src/tiers/cli.js.map +6 -5
  96. package/dist/tools/test/src/tiers/index.d.ts +1 -0
  97. package/dist/tools/test/src/tiers/reporter.d.ts +0 -5
  98. package/dist/tools/test/src/tiers/types.d.ts +9 -0
  99. package/dist/tools/test/src/tiers/worker.js +1 -1
  100. package/dist/tools/test/src/tiers/worker.js.map +1 -1
  101. package/dist/tools/test/src/visual/index.js +121 -119
  102. package/dist/tools/test/src/visual/index.js.map +2 -2
  103. package/dist/tools/verify/specs/README.md +18 -0
  104. package/dist/tools/verify/specs/tla/MeshState.cfg +1 -1
  105. package/dist/tools/verify/specs/tla/MeshState.tla +7 -0
  106. package/dist/tools/verify/specs/tla/MessageRouter.cfg +4 -2
  107. package/dist/tools/verify/specs/tla/MessageRouter.tla +45 -10
  108. package/dist/tools/verify/specs/tla/PeerState.cfg +1 -1
  109. package/dist/tools/verify/specs/tla/PeerState.tla +7 -0
  110. package/dist/tools/verify/specs/tla/README.md +1 -1
  111. package/dist/tools/verify/src/cli.js +258 -202
  112. package/dist/tools/verify/src/cli.js.map +12 -11
  113. package/dist/tools/verify/src/config.d.ts +25 -0
  114. package/dist/tools/verify/src/config.js +18 -16
  115. package/dist/tools/verify/src/config.js.map +3 -3
  116. package/dist/tools/verify/src/stryker/index.js +6 -6
  117. package/dist/tools/verify/src/stryker/index.js.map +1 -1
  118. package/dist/tools/visualize/src/cli.js +439 -47
  119. package/dist/tools/visualize/src/cli.js.map +7 -5
  120. package/package.json +2 -2
@@ -19,12 +19,14 @@ var __toESM = (mod, isNodeMode, target) => {
19
19
  }
20
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
21
21
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
- for (let key of __getOwnPropNames(mod))
23
- if (!__hasOwnProp.call(to, key))
24
- __defProp(to, key, {
25
- get: __accessProp.bind(mod, key),
26
- enumerable: true
27
- });
22
+ if (mod && typeof mod === "object" || typeof mod === "function") {
23
+ for (let key of __getOwnPropNames(mod))
24
+ if (!__hasOwnProp.call(to, key))
25
+ __defProp(to, key, {
26
+ get: __accessProp.bind(mod, key),
27
+ enumerable: true
28
+ });
29
+ }
28
30
  if (canCache)
29
31
  cache.set(mod, to);
30
32
  return to;
@@ -96,12 +98,12 @@ function expectType(_value) {}
96
98
  function noOp() {}
97
99
  async function noOpAsync() {}
98
100
  export {
99
- waitForCondition,
100
- waitFor,
101
- noOpAsync,
102
- noOp,
101
+ createMockRoutedMessage,
103
102
  expectType,
104
- createMockRoutedMessage
103
+ noOp,
104
+ noOpAsync,
105
+ waitFor,
106
+ waitForCondition
105
107
  };
106
108
 
107
- //# debugId=1D7B3D33F0FB579464756E2164756E21
109
+ //# debugId=C9AAA85477DD07DB64756E2164756E21
@@ -4,7 +4,7 @@
4
4
  "sourcesContent": [
5
5
  "import type { ExtensionMessage, RoutedMessage } from \"@fairfox/polly/types\";\n\n/**\n * Test utilities for extension testing\n */\n\nexport function createMockRoutedMessage<T extends ExtensionMessage>(\n payload: T,\n overrides?: Partial<Omit<RoutedMessage<T>, \"payload\">>\n): RoutedMessage<T> {\n return {\n id: overrides?.id || `msg-${Date.now()}-${Math.random()}`,\n source: overrides?.source || \"background\",\n targets: overrides?.targets || [\"content\"],\n tabId: overrides?.tabId,\n timestamp: overrides?.timestamp || Date.now(),\n payload,\n };\n}\n\nexport function waitFor(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForCondition(\n condition: () => boolean,\n timeout = 1000,\n interval = 10\n): Promise<void> {\n const startTime = Date.now();\n while (!condition()) {\n if (Date.now() - startTime > timeout) {\n throw new Error(\"Condition not met within timeout\");\n }\n await waitFor(interval);\n }\n}\n\nexport function expectType<T>(_value: T): void {\n // Type assertion helper for compile-time checks\n}\n\n/**\n * No-op function for mocks that don't need to do anything\n * Use this instead of empty arrow functions to satisfy linter\n */\n// biome-ignore lint/suspicious/noEmptyBlockStatements: intentional no-op for mocks\nexport function noOp(): void {}\n\n/**\n * Async no-op function for async mocks that don't need to do anything\n * Use this instead of empty async arrow functions to satisfy linter\n */\n// biome-ignore lint/suspicious/noEmptyBlockStatements: intentional no-op for mocks\nexport async function noOpAsync(): Promise<void> {}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMO,SAAS,uBAAmD,CACjE,SACA,WACkB;AAAA,EAClB,OAAO;AAAA,IACL,IAAI,WAAW,MAAM,OAAO,KAAK,IAAI,KAAK,KAAK,OAAO;AAAA,IACtD,QAAQ,WAAW,UAAU;AAAA,IAC7B,SAAS,WAAW,WAAW,CAAC,SAAS;AAAA,IACzC,OAAO,WAAW;AAAA,IAClB,WAAW,WAAW,aAAa,KAAK,IAAI;AAAA,IAC5C;AAAA,EACF;AAAA;AAGK,SAAS,OAAO,CAAC,IAA2B;AAAA,EACjD,OAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA;AAGzD,eAAsB,gBAAgB,CACpC,WACA,UAAU,MACV,WAAW,IACI;AAAA,EACf,MAAM,YAAY,KAAK,IAAI;AAAA,EAC3B,OAAO,CAAC,UAAU,GAAG;AAAA,IACnB,IAAI,KAAK,IAAI,IAAI,YAAY,SAAS;AAAA,MACpC,MAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAAA,IACA,MAAM,QAAQ,QAAQ;AAAA,EACxB;AAAA;AAGK,SAAS,UAAa,CAAC,QAAiB;AASxC,SAAS,IAAI,GAAS;AAO7B,eAAsB,SAAS,GAAkB;",
8
- "debugId": "1D7B3D33F0FB579464756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMO,SAAS,uBAAmD,CACjE,SACA,WACkB;AAAA,EAClB,OAAO;AAAA,IACL,IAAI,WAAW,MAAM,OAAO,KAAK,IAAI,KAAK,KAAK,OAAO;AAAA,IACtD,QAAQ,WAAW,UAAU;AAAA,IAC7B,SAAS,WAAW,WAAW,CAAC,SAAS;AAAA,IACzC,OAAO,WAAW;AAAA,IAClB,WAAW,WAAW,aAAa,KAAK,IAAI;AAAA,IAC5C;AAAA,EACF;AAAA;AAGK,SAAS,OAAO,CAAC,IAA2B;AAAA,EACjD,OAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA;AAGzD,eAAsB,gBAAgB,CACpC,WACA,UAAU,MACV,WAAW,IACI;AAAA,EACf,MAAM,YAAY,KAAK,IAAI;AAAA,EAC3B,OAAO,CAAC,UAAU,GAAG;AAAA,IACnB,IAAI,KAAK,IAAI,IAAI,YAAY,SAAS;AAAA,MACpC,MAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAAA,IACA,MAAM,QAAQ,QAAQ;AAAA,EACxB;AAAA;AAGK,SAAS,UAAa,CAAC,QAAiB;AASxC,SAAS,IAAI,GAAS;AAO7B,eAAsB,SAAS,GAAkB;",
8
+ "debugId": "C9AAA85477DD07DB64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Timeout budgets and the margin left against them.
3
+ *
4
+ * A fixed per-case timeout silently tightens every time the work it wraps
5
+ * grows. `coverage.enforce` re-runs the whole unit suite under `--coverage`,
6
+ * so its cost tracks that suite's size: it drifted to 83–86% of a 180s cap,
7
+ * then crossed the line under load and failed an `--all` run that had no
8
+ * coverage regression in it (polly#175).
9
+ *
10
+ * A duration is only legible next to its budget. The engine records
11
+ * `timeoutMs` on every case report, and reports the ratio out loud once a
12
+ * case passes {@link BUDGET_WARN_FRACTION} of it — so the margin erodes
13
+ * visibly, one run at a time, instead of arriving as a red run.
14
+ */
15
+ /** Report the margin once a case has consumed this much of its budget. */
16
+ export declare const BUDGET_WARN_FRACTION = 0.7;
17
+ /**
18
+ * Fraction of its timeout a case consumed, or `undefined` when there is no
19
+ * budget to measure against.
20
+ */
21
+ export declare function budgetUse(durationMs: number, timeoutMs: number | undefined): number | undefined;
22
+ /**
23
+ * A short "how close was that" note, or `undefined` when the case sat below
24
+ * {@link BUDGET_WARN_FRACTION} and the margin needs no comment.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * formatBudgetUse(154_235, 180_000); // "86% of its 180000ms timeout budget"
29
+ * formatBudgetUse(4_633, 180_000); // undefined
30
+ * ```
31
+ */
32
+ export declare function formatBudgetUse(durationMs: number, timeoutMs: number | undefined): string | undefined;
@@ -216,6 +216,20 @@ async function discoverPlan(root) {
216
216
  return { tiers };
217
217
  }
218
218
 
219
+ // tools/test/src/tiers/budget.ts
220
+ var BUDGET_WARN_FRACTION = 0.7;
221
+ function budgetUse(durationMs, timeoutMs) {
222
+ if (typeof timeoutMs !== "number" || timeoutMs <= 0)
223
+ return;
224
+ return durationMs / timeoutMs;
225
+ }
226
+ function formatBudgetUse(durationMs, timeoutMs) {
227
+ const used = budgetUse(durationMs, timeoutMs);
228
+ if (used === undefined || used < BUDGET_WARN_FRACTION)
229
+ return;
230
+ return `${Math.round(used * 100)}% of its ${timeoutMs}ms timeout budget`;
231
+ }
232
+
219
233
  // tools/test/src/tiers/detect.ts
220
234
  var cache = new Map;
221
235
  async function commandSucceeds(argv) {
@@ -385,7 +399,12 @@ async function runOneCase(spec, tier, options, worker) {
385
399
  };
386
400
  }
387
401
  const timeoutMs = spec.timeoutMs ?? tier.timeoutMs ?? DEFAULT_TIMEOUT_MS;
388
- const env = { ...process.env, ...options.env };
402
+ const caseEnv = spec.exec.kind === "command" ? spec.exec.env : undefined;
403
+ const env = {
404
+ ...process.env,
405
+ ...options.env,
406
+ ...caseEnv
407
+ };
389
408
  const { argv, cwd } = buildInvocation(spec, worker, options);
390
409
  const started = performance.now();
391
410
  const prefix = ` [${spec.id}] `;
@@ -395,7 +414,8 @@ async function runOneCase(spec, tier, options, worker) {
395
414
  });
396
415
  const durationMs = Math.round(performance.now() - started);
397
416
  const verdict = decideVerdict(spec, result, timeoutMs);
398
- const tail = verdict.message ? ` — ${verdict.message}` : "";
417
+ const budgetNote = verdict.outcome === "timeout" ? undefined : formatBudgetUse(durationMs, timeoutMs);
418
+ const tail = verdict.message ? ` — ${verdict.message}` : budgetNote ? ` — ${budgetNote}` : "";
399
419
  log(` ${VERDICT_ICON[verdict.outcome]} ${label} (${durationMs}ms)${tail}`);
400
420
  return {
401
421
  tier: tier.name,
@@ -403,6 +423,7 @@ async function runOneCase(spec, tier, options, worker) {
403
423
  label,
404
424
  outcome: verdict.outcome,
405
425
  durationMs,
426
+ timeoutMs,
406
427
  message: verdict.message
407
428
  };
408
429
  }
@@ -466,14 +487,23 @@ async function runPlan(plan, options = {}) {
466
487
 
467
488
  // tools/test/src/tiers/reporter.ts
468
489
  var ICON = { pass: "✓", fail: "✗", skip: "⊘", timeout: "⏱" };
490
+ function caseTail(c) {
491
+ if (c.outcome === "skip")
492
+ return ` (${c.skipReason})`;
493
+ if (c.message)
494
+ return ` — ${c.message}`;
495
+ if (c.outcome === "timeout")
496
+ return "";
497
+ const budgetNote = formatBudgetUse(c.durationMs, c.timeoutMs);
498
+ return budgetNote ? ` — ${budgetNote}` : "";
499
+ }
469
500
  function formatSummary(report) {
470
501
  const lines = [];
471
502
  lines.push("");
472
503
  lines.push("── results ─────────────────────────────────");
473
504
  for (const c of report.cases) {
474
505
  const time = c.outcome === "skip" ? "" : `${c.durationMs}ms`;
475
- const tail = c.outcome === "skip" ? ` (${c.skipReason})` : c.message ? ` — ${c.message}` : "";
476
- lines.push(`${ICON[c.outcome]} ${c.tier} › ${c.label} ${time}${tail}`);
506
+ lines.push(`${ICON[c.outcome]} ${c.tier} › ${c.label} ${time}${caseTail(c)}`);
477
507
  }
478
508
  const ran = report.cases.filter((c) => c.outcome !== "skip");
479
509
  const slowest = [...ran].sort((a, b) => b.durationMs - a.durationMs).slice(0, 5);
@@ -561,4 +591,4 @@ wrote ${args.json}`);
561
591
  }
562
592
  await main();
563
593
 
564
- //# debugId=12E113E54144234E64756E2164756E21
594
+ //# debugId=9BB1BCCFB0C4321964756E2164756E21
@@ -1,17 +1,18 @@
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/order.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/budget.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
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
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/** Resolve the `polly bdd` CLI, preferring the bundled build. */\nfunction bddRunner(): string {\n const bundled = `${import.meta.dir}/../../../bdd/src/cli.js`;\n const source = `${import.meta.dir}/../../../bdd/src/cli.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 featureFiles = await globFiles(root, \"**/*.feature\");\n if (featureFiles.length > 0) {\n tiers.push({\n name: \"bdd\",\n description: `executable Gherkin (${featureFiles.length} *.feature file(s))`,\n timeoutMs: 120_000,\n cases: [\n {\n id: \"bdd\",\n tags: [\"bdd\", \"gherkin\"],\n exec: { kind: \"command\", argv: [\"bun\", bddRunner(), \"run\"], 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
+ "/**\n * Timeout budgets and the margin left against them.\n *\n * A fixed per-case timeout silently tightens every time the work it wraps\n * grows. `coverage.enforce` re-runs the whole unit suite under `--coverage`,\n * so its cost tracks that suite's size: it drifted to 83–86% of a 180s cap,\n * then crossed the line under load and failed an `--all` run that had no\n * coverage regression in it (polly#175).\n *\n * A duration is only legible next to its budget. The engine records\n * `timeoutMs` on every case report, and reports the ratio out loud once a\n * case passes {@link BUDGET_WARN_FRACTION} of it — so the margin erodes\n * visibly, one run at a time, instead of arriving as a red run.\n */\n\n/** Report the margin once a case has consumed this much of its budget. */\nexport const BUDGET_WARN_FRACTION = 0.7;\n\n/**\n * Fraction of its timeout a case consumed, or `undefined` when there is no\n * budget to measure against.\n */\nexport function budgetUse(durationMs: number, timeoutMs: number | undefined): number | undefined {\n if (typeof timeoutMs !== \"number\" || timeoutMs <= 0) return undefined;\n return durationMs / timeoutMs;\n}\n\n/**\n * A short \"how close was that\" note, or `undefined` when the case sat below\n * {@link BUDGET_WARN_FRACTION} and the margin needs no comment.\n *\n * @example\n * ```typescript\n * formatBudgetUse(154_235, 180_000); // \"86% of its 180000ms timeout budget\"\n * formatBudgetUse(4_633, 180_000); // undefined\n * ```\n */\nexport function formatBudgetUse(\n durationMs: number,\n timeoutMs: number | undefined\n): string | undefined {\n const used = budgetUse(durationMs, timeoutMs);\n if (used === undefined || used < BUDGET_WARN_FRACTION) return undefined;\n return `${Math.round(used * 100)}% of its ${timeoutMs}ms timeout budget`;\n}\n",
8
9
  "/**\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
10
  "/**\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",
10
11
  "/**\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",
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
+ "/**\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 { formatBudgetUse } from \"./budget\";\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 caseEnv = spec.exec.kind === \"command\" ? spec.exec.env : undefined;\n const env: Record<string, string | undefined> = {\n ...process.env,\n ...options.env,\n ...caseEnv,\n };\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 // A case that finishes just under its cap is a run away from failing on\n // machine load rather than on the thing it tests, so say how close it came\n // (polly#175). A timeout already reports its own budget in the message.\n const budgetNote =\n verdict.outcome === \"timeout\" ? undefined : formatBudgetUse(durationMs, timeoutMs);\n const tail = verdict.message ? ` — ${verdict.message}` : budgetNote ? ` — ${budgetNote}` : \"\";\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 timeoutMs,\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",
13
+ "/**\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 { formatBudgetUse } from \"./budget\";\nimport type { RunReport, TierPlan } from \"./types\";\n\nconst ICON = { pass: \"✓\", fail: \"✗\", skip: \"⊘\", timeout: \"⏱\" } as const;\n\n/** What follows the timing: the skip reason, the failure, or — for a case\n * that ran clean but close to its cap — how much budget it used (polly#175). */\nfunction caseTail(c: RunReport[\"cases\"][number]): string {\n if (c.outcome === \"skip\") return ` (${c.skipReason})`;\n if (c.message) return ` — ${c.message}`;\n if (c.outcome === \"timeout\") return \"\";\n const budgetNote = formatBudgetUse(c.durationMs, c.timeoutMs);\n return budgetNote ? ` — ${budgetNote}` : \"\";\n}\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 lines.push(`${ICON[c.outcome]} ${c.tier} › ${c.label} ${time}${caseTail(c)}`);\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"
13
14
  ],
14
- "mappings": "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",
15
- "debugId": "12E113E54144234E64756E2164756E21",
15
+ "mappings": "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",
16
+ "debugId": "9BB1BCCFB0C4321964756E2164756E21",
16
17
  "names": []
17
18
  }
@@ -7,6 +7,7 @@
7
7
  * `polly test` command are both front-ends over this.
8
8
  */
9
9
  export { DEFAULT_JSON, parseTierArgs, type TierArgs } from "./args";
10
+ export { BUDGET_WARN_FRACTION, budgetUse, formatBudgetUse } from "./budget";
10
11
  export { firstUnmetNeed, hasNeed } from "./detect";
11
12
  export { discoverPlan } from "./discover";
12
13
  export { runPlan } from "./engine";
@@ -1,8 +1,3 @@
1
- /**
2
- * Reporting for engine runs: a human summary table (with per-case timing and a
3
- * slowest-N list, the data the old `&&` chains never captured) and a JSON
4
- * artefact for tooling. No cloud reporters — everything lands on disk locally.
5
- */
6
1
  import type { RunReport, TierPlan } from "./types";
7
2
  /** One-line-per-case summary plus totals and slowest cases. */
8
3
  export declare function formatSummary(report: RunReport): string;
@@ -26,6 +26,12 @@ export type CaseExec = {
26
26
  kind: "command";
27
27
  argv: string[];
28
28
  cwd?: string;
29
+ /**
30
+ * Extra environment for this case only, merged over the run-level `env`.
31
+ * Lets one case opt out of what a sibling needs — e.g. SKIP_DOCKER=1 to
32
+ * keep a fast tier off the daemon while a heavy tier drives it.
33
+ */
34
+ env?: Record<string, string | undefined>;
29
35
  };
30
36
  /** One runnable unit within a tier. */
31
37
  export interface CaseSpec {
@@ -70,6 +76,9 @@ export interface CaseReport {
70
76
  label: string;
71
77
  outcome: CaseOutcome;
72
78
  durationMs: number;
79
+ /** The timeout the case ran under. Carried so the JSON artefact shows the
80
+ * margin a case left against its budget, not just how long it took. */
81
+ timeoutMs?: number;
73
82
  message?: string;
74
83
  /** Reason a case was skipped (unmet need). */
75
84
  skipReason?: string;
@@ -57,4 +57,4 @@ if (__require.main == __require.module) {
57
57
  process.exit(0);
58
58
  }
59
59
 
60
- //# debugId=0FA2FEFC484C1D5964756E2164756E21
60
+ //# debugId=7AD29AD0CEBE769564756E2164756E21
@@ -7,6 +7,6 @@
7
7
  "#!/usr/bin/env bun\n/**\n * Subprocess entry for a single \"module\" case.\n *\n * Spawned by the engine as `bun worker.ts <modulePath> <id>`. Running each case\n * in its own process is deliberate: the e2e scripts mutate globals (happy-dom),\n * bind ephemeral ports, and drive Puppeteer — they were written assuming\n * process isolation, and the engine preserves it.\n *\n * Protocol: the worker prints exactly one sentinel line\n * __TIER_RESULT__{\"pass\":true,...}\n * to stdout. Everything else on stdout is the case's own logging, forwarded by\n * the parent. If the case hard-exits (legacy `process.exit(1)`) before the\n * sentinel, the parent falls back to the worker's exit code.\n */\nimport { standaloneContext, type TierResult } from \"../e2e-shared/contract\";\nimport { SENTINEL } from \"./protocol\";\n\nfunction emit(result: TierResult): void {\n process.stdout.write(`\\n${SENTINEL}${JSON.stringify(result)}\\n`);\n}\n\nasync function runWorker(): Promise<void> {\n const modulePath = process.argv[2];\n if (!modulePath) {\n emit({ pass: false, message: \"worker: no module path given\" });\n return;\n }\n\n try {\n // Importing a converted script is side-effect-free (its self-run footer is\n // guarded by import.meta.main). Importing a legacy script runs its top-level\n // main() now, which sets process.exitCode.\n const mod: { run?: (ctx: unknown) => Promise<TierResult> } = await import(modulePath);\n\n if (typeof mod.run === \"function\") {\n const result = await mod.run(standaloneContext());\n emit({ pass: Boolean(result?.pass), message: result?.message, detail: result?.detail });\n } else {\n // Legacy: the import side-effect already ran the test; trust its exit code.\n emit({ pass: (process.exitCode ?? 0) === 0 });\n }\n } catch (err) {\n emit({ pass: false, message: err instanceof Error ? err.message : String(err) });\n }\n}\n\n// Only execute when invoked directly; the engine also imports SENTINEL from here.\nif (import.meta.main) {\n await runWorker();\n // Force exit so an open Puppeteer/server handle can't keep the worker alive;\n // the result has already been emitted and captured by the parent.\n process.exit(0);\n}\n"
8
8
  ],
9
9
  "mappings": ";;;;;;;;;;;;;;;;;;;;AAsCO,SAAS,iBAAiB,GAAgB;AAAA,EAC/C,OAAO;AAAA,IACL,KAAK,CAAC,YAAoB,QAAQ,IAAI,OAAO;AAAA,IAC7C,KAAK,QAAQ;AAAA,EACf;AAAA;;;ACjCK,IAAM,WAAW;;;ACSxB,SAAS,IAAI,CAAC,QAA0B;AAAA,EACtC,QAAQ,OAAO,MAAM;AAAA,EAAK,WAAW,KAAK,UAAU,MAAM;AAAA,CAAK;AAAA;AAGjE,eAAe,SAAS,GAAkB;AAAA,EACxC,MAAM,aAAa,QAAQ,KAAK;AAAA,EAChC,IAAI,CAAC,YAAY;AAAA,IACf,KAAK,EAAE,MAAM,OAAO,SAAS,+BAA+B,CAAC;AAAA,IAC7D;AAAA,EACF;AAAA,EAEA,IAAI;AAAA,IAIF,MAAM,MAAuD,MAAa;AAAA,IAE1E,IAAI,OAAO,IAAI,QAAQ,YAAY;AAAA,MACjC,MAAM,SAAS,MAAM,IAAI,IAAI,kBAAkB,CAAC;AAAA,MAChD,KAAK,EAAE,MAAM,QAAQ,QAAQ,IAAI,GAAG,SAAS,QAAQ,SAAS,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACxF,EAAO;AAAA,MAEL,KAAK,EAAE,OAAO,QAAQ,YAAY,OAAO,EAAE,CAAC;AAAA;AAAA,IAE9C,OAAO,KAAK;AAAA,IACZ,KAAK,EAAE,MAAM,OAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE,CAAC;AAAA;AAAA;AAKnF,IAAI,oCAAkB;AAAA,EACpB,MAAM,UAAU;AAAA,EAGhB,QAAQ,KAAK,CAAC;AAChB;",
10
- "debugId": "0FA2FEFC484C1D5964756E2164756E21",
10
+ "debugId": "7AD29AD0CEBE769564756E2164756E21",
11
11
  "names": []
12
12
  }