doppeldiff 0.1.0 → 0.1.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.
package/dist/index.js CHANGED
@@ -330,7 +330,7 @@ var RunnerProcess = class {
330
330
  }
331
331
  /** Execute a job; timeouts and crashes become outcomes, and the process is respawned. */
332
332
  async run(job) {
333
- const { timeoutMs } = this.options;
333
+ const timeoutMs = Math.round(this.options.timeoutMs * (job.timeoutScale ?? 1));
334
334
  const watchdogMs = timeoutMs + Math.max(150, Math.round(timeoutMs * 0.3));
335
335
  const guardKey = `${job.moduleId}#${job.exportName}`;
336
336
  const outcomes = new Array(job.inputs.length);
@@ -354,6 +354,11 @@ var RunnerProcess = class {
354
354
  if (m.t === "result" && m.reqId === reqId) {
355
355
  outcomes[offset + m.index] = m.outcome;
356
356
  count = m.index + 1;
357
+ if (m.outcome.kind === "timeout") {
358
+ this.guarded.add(guardKey);
359
+ finish({ count }, true);
360
+ return;
361
+ }
357
362
  arm();
358
363
  } else if (m.t === "done" && m.reqId === reqId) {
359
364
  finish({ count }, false);
@@ -435,18 +440,18 @@ var RunnerPool = class {
435
440
  return results[0];
436
441
  }
437
442
  /** Run inputs, spreading them across processes. Outcomes are returned in input order. */
438
- run(moduleId, exportName, inputs) {
439
- const result = this.lock.then(() => this.runUnlocked(moduleId, exportName, inputs));
443
+ run(moduleId, exportName, inputs, options = {}) {
444
+ const result = this.lock.then(() => this.runUnlocked(moduleId, exportName, inputs, options.timeoutScale));
440
445
  this.lock = result.catch(() => void 0);
441
446
  return result;
442
447
  }
443
- async runUnlocked(moduleId, exportName, inputs) {
448
+ async runUnlocked(moduleId, exportName, inputs, timeoutScale) {
444
449
  await this.start();
445
450
  const chunkSize = Math.max(16, Math.ceil(inputs.length / this.procs.length));
446
451
  const chunks = [];
447
452
  for (let i = 0; i < inputs.length; i += chunkSize) chunks.push(inputs.slice(i, i + chunkSize));
448
453
  const results = await Promise.all(
449
- chunks.map((c, i) => this.procs[i].run({ moduleId, exportName, inputs: c }))
454
+ chunks.map((c, i) => this.procs[i].run({ moduleId, exportName, inputs: c, timeoutScale }))
450
455
  );
451
456
  return results.flat();
452
457
  }
@@ -1046,6 +1051,19 @@ function numberArb(ctx) {
1046
1051
  );
1047
1052
  return weighted(typeDriven, ctx.mined.numbers, ctx);
1048
1053
  }
1054
+ var HUGE_SIZES = [2 ** 31 - 1, 2 ** 32, Number.MAX_SAFE_INTEGER, 1e15, Infinity, -Infinity, NaN];
1055
+ function sizeArb(ctx) {
1056
+ const typeDriven = fc2.oneof(
1057
+ { arbitrary: fc2.integer({ min: 0, max: 10 }), weight: 40 },
1058
+ { arbitrary: fc2.integer({ min: 0, max: 100 }), weight: 25 },
1059
+ { arbitrary: fc2.integer({ min: 0, max: 1e3 }), weight: 8 },
1060
+ { arbitrary: fc2.constantFrom(-1, -2, -10), weight: 3 },
1061
+ { arbitrary: fc2.constantFrom(0.5, 1.5, 2.25), weight: 2 },
1062
+ { arbitrary: fc2.constantFrom(...HUGE_SIZES), weight: 1 }
1063
+ );
1064
+ const mined = ctx.mined.numbers.filter((n3) => Number.isInteger(n3) && n3 >= -10 && n3 <= 1e3);
1065
+ return weighted(typeDriven, mined, ctx);
1066
+ }
1049
1067
  var regexCache = /* @__PURE__ */ new WeakMap();
1050
1068
  var sampleCache = /* @__PURE__ */ new WeakMap();
1051
1069
  function regexSamples(arbs) {
@@ -1186,7 +1204,7 @@ function anythingArb(ctx) {
1186
1204
  function compile(spec, ctx) {
1187
1205
  switch (spec.kind) {
1188
1206
  case "number":
1189
- return numberArb(ctx);
1207
+ return spec.size ? sizeArb(ctx) : numberArb(ctx);
1190
1208
  case "bigint":
1191
1209
  return fc2.oneof(fc2.bigInt({ min: -1000n, max: 1000n }), fc2.bigInt());
1192
1210
  case "string":
@@ -1416,8 +1434,87 @@ function referencedModuleValues(nodes) {
1416
1434
  return [...result];
1417
1435
  }
1418
1436
 
1437
+ // src/core/analyze/sizeParams.ts
1438
+ import { Node as Node3, SyntaxKind as SyntaxKind3 } from "ts-morph";
1439
+ var SIZE_NAME = /^(n|k|count|size|length|len|times|limit|index|idx|width|height|depth|pages?|parts|chunks?|rows|cols|columns|steps|retries|attempts|digits|places|precision|decimals|people|items|level|levels)$|(Count|Size|Length|Index|Limit|Width|Height|Depth|Times)$/;
1440
+ var LENGTH_CALLS = /* @__PURE__ */ new Set([
1441
+ "repeat",
1442
+ "padStart",
1443
+ "padEnd",
1444
+ "at",
1445
+ "slice",
1446
+ "substring",
1447
+ "substr",
1448
+ "splice"
1449
+ ]);
1450
+ function isLoopCondition(node) {
1451
+ for (let p = node.getParent(); p; p = p.getParent()) {
1452
+ if (Node3.isForStatement(p)) return p.getCondition() !== void 0 && isWithin(node, p.getCondition());
1453
+ if (Node3.isWhileStatement(p) || Node3.isDoStatement(p)) return isWithin(node, p.getExpression());
1454
+ if (Node3.isBlock(p) || Node3.isFunctionLikeDeclaration(p)) return false;
1455
+ }
1456
+ return false;
1457
+ }
1458
+ function isWithin(node, container) {
1459
+ return node.getPos() >= container.getPos() && node.getEnd() <= container.getEnd();
1460
+ }
1461
+ function usedAsSize(id) {
1462
+ const parent = id.getParent();
1463
+ if (!parent) return false;
1464
+ if (Node3.isBinaryExpression(parent)) {
1465
+ const op = parent.getOperatorToken().getKind();
1466
+ const comparison = op === SyntaxKind3.LessThanToken || op === SyntaxKind3.LessThanEqualsToken || op === SyntaxKind3.GreaterThanToken || op === SyntaxKind3.GreaterThanEqualsToken;
1467
+ if (comparison && isLoopCondition(parent)) return true;
1468
+ }
1469
+ if (Node3.isElementAccessExpression(parent) && parent.getArgumentExpression() === id) return true;
1470
+ if (Node3.isPropertyAssignment(parent) && parent.getName() === "length" && parent.getInitializer() === id)
1471
+ return true;
1472
+ if (Node3.isShorthandPropertyAssignment(parent) && parent.getName() === "length") return true;
1473
+ if ((Node3.isCallExpression(parent) || Node3.isNewExpression(parent)) && parent.getArguments().includes(id)) {
1474
+ const callee = parent.getExpression();
1475
+ const name = Node3.isPropertyAccessExpression(callee) ? callee.getName() : callee.getText();
1476
+ if (name === "Array" || LENGTH_CALLS.has(name)) return true;
1477
+ }
1478
+ return false;
1479
+ }
1480
+ function sizeLikeParams(fns) {
1481
+ const out = /* @__PURE__ */ new Set();
1482
+ for (const fn of fns) {
1483
+ if (!(Node3.isFunctionDeclaration(fn) || Node3.isFunctionExpression(fn) || Node3.isArrowFunction(fn)))
1484
+ continue;
1485
+ const params = fn.getParameters().map((p) => p.getNameNode()).filter((n3) => Node3.isIdentifier(n3)).map((n3) => n3.getText());
1486
+ for (const name of params) {
1487
+ if (SIZE_NAME.test(name)) {
1488
+ out.add(name);
1489
+ continue;
1490
+ }
1491
+ const body = fn.getBody();
1492
+ if (!body) continue;
1493
+ const refs = body.getDescendantsOfKind(SyntaxKind3.Identifier).filter((id) => id.getText() === name).filter((id) => {
1494
+ const p = id.getParent();
1495
+ return !(Node3.isPropertyAccessExpression(p) && p.getNameNode() === id);
1496
+ });
1497
+ if (refs.some(usedAsSize)) {
1498
+ out.add(name);
1499
+ continue;
1500
+ }
1501
+ for (const decl of body.getDescendantsOfKind(SyntaxKind3.VariableDeclaration)) {
1502
+ const init = decl.getInitializer();
1503
+ const local = decl.getNameNode();
1504
+ if (!init || !Node3.isIdentifier(local) || !refs.some((r) => isWithin(r, init))) continue;
1505
+ const localRefs = body.getDescendantsOfKind(SyntaxKind3.Identifier).filter((id) => id.getText() === local.getText() && id !== local);
1506
+ if (localRefs.some(usedAsSize)) {
1507
+ out.add(name);
1508
+ break;
1509
+ }
1510
+ }
1511
+ }
1512
+ }
1513
+ return out;
1514
+ }
1515
+
1419
1516
  // src/core/detect/toplevel.ts
1420
- import { Node as Node3, SyntaxKind as SyntaxKind3, ts as ts2 } from "ts-morph";
1517
+ import { Node as Node4, SyntaxKind as SyntaxKind4, ts as ts2 } from "ts-morph";
1421
1518
  function normalize(node) {
1422
1519
  const sf = node.getSourceFile().compilerNode;
1423
1520
  const out = [];
@@ -1435,11 +1532,11 @@ function normalize(node) {
1435
1532
  return out.join(" ");
1436
1533
  }
1437
1534
  function topLevelNameOf(decl) {
1438
- if (Node3.isFunctionDeclaration(decl) || Node3.isClassDeclaration(decl) || Node3.isEnumDeclaration(decl)) {
1535
+ if (Node4.isFunctionDeclaration(decl) || Node4.isClassDeclaration(decl) || Node4.isEnumDeclaration(decl)) {
1439
1536
  return decl.getName() ?? "default";
1440
1537
  }
1441
- if (Node3.isVariableDeclaration(decl)) return decl.getName();
1442
- if (Node3.isExportAssignment(decl)) return "default";
1538
+ if (Node4.isVariableDeclaration(decl)) return decl.getName();
1539
+ if (Node4.isExportAssignment(decl)) return "default";
1443
1540
  return void 0;
1444
1541
  }
1445
1542
  function indexModule(sf) {
@@ -1449,7 +1546,7 @@ function indexModule(sf) {
1449
1546
  const cjsStatements = [];
1450
1547
  const add = (name, kind, node, printed = node) => decls.set(name, { name, kind, node, normalized: normalize(printed), raw: printed.getText() });
1451
1548
  for (const st of sf.getStatements()) {
1452
- if (Node3.isFunctionDeclaration(st)) {
1549
+ if (Node4.isFunctionDeclaration(st)) {
1453
1550
  const name = st.getName() ?? "default";
1454
1551
  const prev = decls.get(name);
1455
1552
  add(name, "function", st);
@@ -1458,21 +1555,21 @@ function indexModule(sf) {
1458
1555
  cur.normalized = prev.normalized + cur.normalized;
1459
1556
  cur.raw = prev.raw + cur.raw;
1460
1557
  }
1461
- } else if (Node3.isVariableStatement(st)) {
1558
+ } else if (Node4.isVariableStatement(st)) {
1462
1559
  for (const d of st.getDeclarations()) {
1463
1560
  const nameNode = d.getNameNode();
1464
- if (Node3.isIdentifier(nameNode)) {
1561
+ if (Node4.isIdentifier(nameNode)) {
1465
1562
  add(d.getName(), "variable", d);
1466
1563
  } else {
1467
- for (const id of nameNode.getDescendantsOfKind(SyntaxKind3.Identifier))
1564
+ for (const id of nameNode.getDescendantsOfKind(SyntaxKind4.Identifier))
1468
1565
  add(id.getText(), "variable", d);
1469
1566
  }
1470
1567
  }
1471
- } else if (Node3.isClassDeclaration(st)) {
1568
+ } else if (Node4.isClassDeclaration(st)) {
1472
1569
  add(st.getName() ?? "default", "class", st);
1473
- } else if (Node3.isEnumDeclaration(st)) {
1570
+ } else if (Node4.isEnumDeclaration(st)) {
1474
1571
  add(st.getName(), "enum", st);
1475
- } else if (Node3.isImportDeclaration(st)) {
1572
+ } else if (Node4.isImportDeclaration(st)) {
1476
1573
  if (st.isTypeOnly()) continue;
1477
1574
  const spec = st.getModuleSpecifierValue();
1478
1575
  const def = st.getDefaultImport();
@@ -1504,12 +1601,12 @@ function indexModule(sf) {
1504
1601
  raw: `${n3.getName()} from ${spec}`
1505
1602
  });
1506
1603
  }
1507
- } else if (Node3.isExportAssignment(st)) {
1604
+ } else if (Node4.isExportAssignment(st)) {
1508
1605
  add("default", "default", st);
1509
1606
  } else if (isCjsExport(st)) {
1510
1607
  cjsStatements.push(st);
1511
1608
  continue;
1512
- } else if (Node3.isInterfaceDeclaration(st) || Node3.isTypeAliasDeclaration(st) || Node3.isExportDeclaration(st) || Node3.isModuleDeclaration(st) || Node3.isEmptyStatement(st)) {
1609
+ } else if (Node4.isInterfaceDeclaration(st) || Node4.isTypeAliasDeclaration(st) || Node4.isExportDeclaration(st) || Node4.isModuleDeclaration(st) || Node4.isEmptyStatement(st)) {
1513
1610
  continue;
1514
1611
  } else {
1515
1612
  sideEffects.push(normalize(st));
@@ -1530,9 +1627,9 @@ function indexModule(sf) {
1530
1627
  return { sf, decls, sideEffects, exports };
1531
1628
  }
1532
1629
  function isCjsExport(st) {
1533
- if (!Node3.isExpressionStatement(st)) return false;
1630
+ if (!Node4.isExpressionStatement(st)) return false;
1534
1631
  const expr = st.getExpression();
1535
- return Node3.isBinaryExpression(expr) && expr.getOperatorToken().getKind() === SyntaxKind3.EqualsToken && cjsTarget(expr.getLeft()) !== void 0;
1632
+ return Node4.isBinaryExpression(expr) && expr.getOperatorToken().getKind() === SyntaxKind4.EqualsToken && cjsTarget(expr.getLeft()) !== void 0;
1536
1633
  }
1537
1634
  function cjsTarget(left) {
1538
1635
  const text2 = left.getText().replace(/\s+/g, "");
@@ -1541,19 +1638,19 @@ function cjsTarget(left) {
1541
1638
  return m ? m[1] : void 0;
1542
1639
  }
1543
1640
  function cjsExport(st, decls, exportsMap, add) {
1544
- if (!Node3.isExpressionStatement(st)) return false;
1641
+ if (!Node4.isExpressionStatement(st)) return false;
1545
1642
  const expr = st.getExpression();
1546
- if (!Node3.isBinaryExpression(expr) || expr.getOperatorToken().getKind() !== SyntaxKind3.EqualsToken)
1643
+ if (!Node4.isBinaryExpression(expr) || expr.getOperatorToken().getKind() !== SyntaxKind4.EqualsToken)
1547
1644
  return false;
1548
1645
  const target = cjsTarget(expr.getLeft());
1549
1646
  if (target === void 0) return false;
1550
1647
  const bind = (exportName, value) => {
1551
- if (Node3.isIdentifier(value) && decls.has(value.getText())) {
1648
+ if (Node4.isIdentifier(value) && decls.has(value.getText())) {
1552
1649
  exportsMap.set(exportName, value.getText());
1553
1650
  return;
1554
1651
  }
1555
1652
  const synthetic = `exports.${exportName}`;
1556
- const isFn = Node3.isArrowFunction(value) || Node3.isFunctionExpression(value);
1653
+ const isFn = Node4.isArrowFunction(value) || Node4.isFunctionExpression(value);
1557
1654
  add(synthetic, isFn ? "function" : "variable", value);
1558
1655
  exportsMap.set(exportName, synthetic);
1559
1656
  };
@@ -1562,12 +1659,12 @@ function cjsExport(st, decls, exportsMap, add) {
1562
1659
  bind(target, rhs);
1563
1660
  return true;
1564
1661
  }
1565
- if (Node3.isObjectLiteralExpression(rhs)) {
1662
+ if (Node4.isObjectLiteralExpression(rhs)) {
1566
1663
  for (const prop of rhs.getProperties()) {
1567
- if (Node3.isShorthandPropertyAssignment(prop)) bind(prop.getName(), prop.getNameNode());
1568
- else if (Node3.isPropertyAssignment(prop))
1664
+ if (Node4.isShorthandPropertyAssignment(prop)) bind(prop.getName(), prop.getNameNode());
1665
+ else if (Node4.isPropertyAssignment(prop))
1569
1666
  bind(prop.getName().replace(/^['"]|['"]$/g, ""), prop.getInitializerOrThrow());
1570
- else if (Node3.isMethodDeclaration(prop)) {
1667
+ else if (Node4.isMethodDeclaration(prop)) {
1571
1668
  add(`exports.${prop.getName()}`, "variable", prop);
1572
1669
  exportsMap.set(prop.getName(), `exports.${prop.getName()}`);
1573
1670
  }
@@ -1594,13 +1691,13 @@ function reach(index, start, depth) {
1594
1691
  for (let d = 0; d < depth && frontier.length > 0; d++) {
1595
1692
  const next = [];
1596
1693
  for (const { node, path } of frontier) {
1597
- for (const id of node.getDescendantsOfKind(SyntaxKind3.Identifier)) {
1694
+ for (const id of node.getDescendantsOfKind(SyntaxKind4.Identifier)) {
1598
1695
  const name = id.getText();
1599
1696
  const top = index.decls.get(name);
1600
1697
  if (!top || local.has(name) || top.node === start) continue;
1601
1698
  const sym = id.getSymbol();
1602
1699
  const decls = sym?.getDeclarations() ?? [];
1603
- if (sym && !decls.some((dn) => isWithin(dn, top.node))) continue;
1700
+ if (sym && !decls.some((dn) => isWithin2(dn, top.node))) continue;
1604
1701
  if (top.kind === "import") {
1605
1702
  const aliased = sym?.isAlias() ? sym.getAliasedSymbol() : void 0;
1606
1703
  for (const ad of aliased?.getDeclarations() ?? []) {
@@ -1623,7 +1720,7 @@ function reach(index, start, depth) {
1623
1720
  }
1624
1721
  return { local, imported };
1625
1722
  }
1626
- function isWithin(node, ancestor) {
1723
+ function isWithin2(node, ancestor) {
1627
1724
  for (let cur = node; cur; cur = cur.getParent()) if (cur === ancestor) return true;
1628
1725
  return false;
1629
1726
  }
@@ -1797,6 +1894,13 @@ function num(n3) {
1797
1894
  if (Object.is(n3, -0)) return "-0";
1798
1895
  return String(n3);
1799
1896
  }
1897
+ var MAX_ITEMS = 10;
1898
+ var SHOWN_ITEMS = 6;
1899
+ var abbreviateLists = true;
1900
+ function list(items, f) {
1901
+ if (!abbreviateLists || items.length <= MAX_ITEMS) return items.map(f).join(", ");
1902
+ return `${items.slice(0, SHOWN_ITEMS).map(f).join(", ")}, \u2026 ${items.length - SHOWN_ITEMS} more`;
1903
+ }
1800
1904
  var IDENT = /^[A-Za-z_$][\w$]*$/;
1801
1905
  var key = (k) => IDENT.test(k) ? k : JSON.stringify(k);
1802
1906
  function formatValue(v, max = MAX_LEN) {
@@ -1826,12 +1930,11 @@ function formatValue(v, max = MAX_LEN) {
1826
1930
  if (seen.has(x)) return "[Circular]";
1827
1931
  seen.add(x);
1828
1932
  try {
1829
- if (Array.isArray(x)) return `[${x.map(f).join(", ")}]`;
1933
+ if (Array.isArray(x)) return `[${list(x, f)}]`;
1830
1934
  if (x instanceof Date)
1831
1935
  return Number.isNaN(x.getTime()) ? "new Date(NaN)" : `new Date(${JSON.stringify(x.toISOString())})`;
1832
- if (x instanceof Map)
1833
- return `new Map([${[...x].map(([k, val]) => `[${f(k)}, ${f(val)}]`).join(", ")}])`;
1834
- if (x instanceof Set) return `new Set([${[...x].map(f).join(", ")}])`;
1936
+ if (x instanceof Map) return `new Map([${list([...x], ([k, val]) => `[${f(k)}, ${f(val)}]`)}])`;
1937
+ if (x instanceof Set) return `new Set([${list([...x], f)}])`;
1835
1938
  if (x instanceof RegExp) return String(x);
1836
1939
  if (isProtoDescriptor(x)) {
1837
1940
  const { proto, own } = x[PROTO_TAG];
@@ -1845,7 +1948,7 @@ function formatValue(v, max = MAX_LEN) {
1845
1948
  return `new ${x.constructor.name}([${Array.from(x).join(", ")}])`;
1846
1949
  const entries = Object.entries(x);
1847
1950
  if (entries.length === 0) return "{}";
1848
- return `{ ${entries.map(([k, val]) => `${key(k)}: ${f(val)}`).join(", ")} }`;
1951
+ return `{ ${list(entries, ([k, val]) => `${key(k)}: ${f(val)}`)} }`;
1849
1952
  } finally {
1850
1953
  seen.delete(x);
1851
1954
  }
@@ -1855,7 +1958,16 @@ function formatValue(v, max = MAX_LEN) {
1855
1958
  function formatArgs(args, max = MAX_LEN) {
1856
1959
  return clip(args.map((a) => formatValue(a, max)).join(", "), max);
1857
1960
  }
1858
- function formatEnc(e, max = MAX_LEN) {
1961
+ function formatEnc(e, max = MAX_LEN, abbreviate = true) {
1962
+ const previous = abbreviateLists;
1963
+ abbreviateLists = abbreviate;
1964
+ try {
1965
+ return formatEncInner(e, max);
1966
+ } finally {
1967
+ abbreviateLists = previous;
1968
+ }
1969
+ }
1970
+ function formatEncInner(e, max) {
1859
1971
  const f = (x) => {
1860
1972
  switch (x.t) {
1861
1973
  case "undefined":
@@ -1873,18 +1985,18 @@ function formatEnc(e, max = MAX_LEN) {
1873
1985
  case "symbol":
1874
1986
  return `Symbol(${x.d})`;
1875
1987
  case "array":
1876
- return `[${x.items.map(f).join(", ")}]`;
1988
+ return `[${list(x.items, f)}]`;
1877
1989
  case "object": {
1878
1990
  const prefix = x.ctor && x.ctor !== "null-prototype" ? `${x.ctor} ` : "";
1879
1991
  if (x.entries.length === 0) return `${prefix}{}`;
1880
- return `${prefix}{ ${x.entries.map(([k, v]) => `${key(k)}: ${f(v)}`).join(", ")} }`;
1992
+ return `${prefix}{ ${list(x.entries, ([k, v]) => `${key(k)}: ${f(v)}`)} }`;
1881
1993
  }
1882
1994
  case "date":
1883
1995
  return Number.isNaN(x.v) ? "Invalid Date" : new Date(x.v).toISOString();
1884
1996
  case "map":
1885
- return `Map(${x.entries.length}) { ${x.entries.map(([k, v]) => `${f(k)} => ${f(v)}`).join(", ")} }`;
1997
+ return `Map(${x.entries.length}) { ${list(x.entries, ([k, v]) => `${f(k)} => ${f(v)}`)} }`;
1886
1998
  case "set":
1887
- return `Set(${x.items.length}) { ${x.items.map(f).join(", ")} }`;
1999
+ return `Set(${x.items.length}) { ${list(x.items, f)} }`;
1888
2000
  case "regexp":
1889
2001
  return `/${x.source}/${x.flags}`;
1890
2002
  case "function":
@@ -1892,7 +2004,7 @@ function formatEnc(e, max = MAX_LEN) {
1892
2004
  case "error":
1893
2005
  return `${x.ctor}: ${x.message}`;
1894
2006
  case "typed":
1895
- return `${x.ctor} [${x.items.join(", ")}]`;
2007
+ return `${x.ctor} [${list(x.items, String)}]`;
1896
2008
  case "promise":
1897
2009
  return "Promise";
1898
2010
  case "cycle":
@@ -1903,12 +2015,12 @@ function formatEnc(e, max = MAX_LEN) {
1903
2015
  };
1904
2016
  return clip(f(e), max);
1905
2017
  }
1906
- function formatOutcome(o, max = MAX_LEN) {
2018
+ function formatOutcome(o, max = MAX_LEN, abbreviate = true) {
1907
2019
  switch (o.kind) {
1908
2020
  case "return":
1909
- return o.async ? `resolves ${formatEnc(o.value, max)}` : formatEnc(o.value, max);
2021
+ return o.async ? `resolves ${formatEnc(o.value, max, abbreviate)}` : formatEnc(o.value, max, abbreviate);
1910
2022
  case "throw": {
1911
- const e = o.error.t === "error" ? `${o.error.ctor}: ${o.error.message}` : formatEnc(o.error, max);
2023
+ const e = o.error.t === "error" ? `${o.error.ctor}: ${o.error.message}` : formatEnc(o.error, max, abbreviate);
1912
2024
  return clip(`${o.async ? "rejects" : "throws"} ${e}`, max);
1913
2025
  }
1914
2026
  case "timeout":
@@ -2213,6 +2325,10 @@ function biasFor(runIndex) {
2213
2325
  return 2 + Math.floor(Math.log(runIndex + 1) / Math.log(10));
2214
2326
  }
2215
2327
  var size = (input) => formatArgs(input, 1e4).length;
2328
+ function witnessCost(input, r) {
2329
+ const out = r ? formatOutcome(r.base, 2e3, false).length + formatOutcome(r.head, 2e3, false).length : 0;
2330
+ return inputComplexity(input) + Math.max(0, out - 40) / 20;
2331
+ }
2216
2332
  async function explore(options) {
2217
2333
  const {
2218
2334
  arbitrary,
@@ -2225,6 +2341,8 @@ async function explore(options) {
2225
2341
  shrinkBudget = 500,
2226
2342
  maxWitnesses = 3,
2227
2343
  maxFailures = 20,
2344
+ maxEdgeFailures = 2,
2345
+ maxTimeoutChecks = 12,
2228
2346
  selfCheck = 50,
2229
2347
  humanizeBudget = 150
2230
2348
  } = options;
@@ -2242,7 +2360,13 @@ async function explore(options) {
2242
2360
  return t;
2243
2361
  };
2244
2362
  let outOfDomain = 0;
2363
+ let edgeFailures = 0;
2364
+ let skippedEdgeInputs = 0;
2245
2365
  const wanted = (input) => {
2366
+ if (options.realism && edgeFailures >= maxEdgeFailures && tierOf(input) === 0) {
2367
+ skippedEdgeInputs++;
2368
+ return false;
2369
+ }
2246
2370
  if (!options.inDomain || options.inDomain(input)) return true;
2247
2371
  if (options.strictDomain) return false;
2248
2372
  return outOfDomain++ % 4 === 0;
@@ -2261,8 +2385,30 @@ async function explore(options) {
2261
2385
  let failures = 0;
2262
2386
  let shrinkEvaluations = 0;
2263
2387
  let stoppedBy = "runs";
2264
- const countFailures = (r) => {
2265
- if ([r.base, r.head].some((o) => o.kind === "timeout" || o.kind === "crash")) failures++;
2388
+ const countFailures = (input, r) => {
2389
+ if (![r.base, r.head].some((o) => o.kind === "timeout" || o.kind === "crash")) return;
2390
+ failures++;
2391
+ if (options.realism && tierOf(input) === 0) edgeFailures++;
2392
+ };
2393
+ const realisticFailures = () => failures - edgeFailures;
2394
+ let timeoutChecks = 0;
2395
+ const timedOut = (r) => r.base.kind === "timeout" || r.head.kind === "timeout";
2396
+ const confirmTimeouts = async (inputs, results) => {
2397
+ const idx2 = results.map((r, i) => i).filter((i) => timedOut(results[i]) && !(options.realism && tierOf(inputs[i]) === 0)).slice(0, Math.max(0, maxTimeoutChecks - timeoutChecks));
2398
+ if (idx2.length === 0) return;
2399
+ timeoutChecks += idx2.length;
2400
+ const again = await evaluate(
2401
+ idx2.map((i) => inputs[i]),
2402
+ { timeoutScale: 4 }
2403
+ );
2404
+ idx2.forEach((i, j) => {
2405
+ const first2 = results[i];
2406
+ const second = again[j];
2407
+ results[i] = {
2408
+ base: first2.base.kind === "timeout" ? second.base : first2.base,
2409
+ head: first2.head.kind === "timeout" ? second.head : first2.head
2410
+ };
2411
+ });
2266
2412
  };
2267
2413
  const evalCached = async (inputs) => {
2268
2414
  const keys = inputs.map(stableKey);
@@ -2276,9 +2422,10 @@ async function explore(options) {
2276
2422
  });
2277
2423
  if (missing.length > 0) {
2278
2424
  const results = await evaluate(missing);
2425
+ await confirmTimeouts(missing, results);
2279
2426
  results.forEach((r, i) => {
2280
2427
  cache.set(missingKeys[i], r);
2281
- countFailures(r);
2428
+ countFailures(missing[i], r);
2282
2429
  });
2283
2430
  }
2284
2431
  return keys.map((k) => cache.get(k));
@@ -2353,12 +2500,14 @@ async function explore(options) {
2353
2500
  flakyClusters: 0,
2354
2501
  stoppedBy: "runs",
2355
2502
  shrinkEvaluations: 0,
2356
- failures
2503
+ failures,
2504
+ edgeFailures,
2505
+ skippedEdgeInputs
2357
2506
  };
2358
2507
  }
2359
2508
  }
2360
2509
  cache.set(stableKey(inputs[i]), a[i]);
2361
- countFailures(a[i]);
2510
+ countFailures(inputs[i], a[i]);
2362
2511
  record(first[i], a[i]);
2363
2512
  }
2364
2513
  inputsRun = inputs.length;
@@ -2371,7 +2520,7 @@ async function explore(options) {
2371
2520
  stoppedBy = "deadline";
2372
2521
  break;
2373
2522
  }
2374
- if (failures >= maxFailures) {
2523
+ if (realisticFailures() >= maxFailures) {
2375
2524
  stoppedBy = "failures";
2376
2525
  break;
2377
2526
  }
@@ -2397,9 +2546,13 @@ async function explore(options) {
2397
2546
  }
2398
2547
  staleBatches = 0;
2399
2548
  const results = await evaluate(batch.map((p) => p.value.value));
2549
+ await confirmTimeouts(
2550
+ batch.map((p) => p.value.value),
2551
+ results
2552
+ );
2400
2553
  results.forEach((r, i) => {
2401
2554
  cache.set(batch[i].key, r);
2402
- countFailures(r);
2555
+ countFailures(batch[i].value.value, r);
2403
2556
  record(batch[i].value, r);
2404
2557
  });
2405
2558
  inputsRun += batch.length;
@@ -2409,6 +2562,12 @@ async function explore(options) {
2409
2562
  for (const cluster of clusters.values()) {
2410
2563
  let cur = cluster.seed;
2411
2564
  let evals = 0;
2565
+ const w0 = cluster.witnesses[0];
2566
+ if (w0.base.kind === "timeout" || w0.head.kind === "timeout") {
2567
+ cluster.witnesses.length = 1;
2568
+ cluster.witnesses[0].minimal = true;
2569
+ continue;
2570
+ }
2412
2571
  if (exampleValues.has(cur) && !arbitrary.canShrinkWithoutContext(cur.value)) continue;
2413
2572
  let improved = true;
2414
2573
  while (improved && evals < shrinkBudget) {
@@ -2435,7 +2594,7 @@ async function explore(options) {
2435
2594
  break;
2436
2595
  }
2437
2596
  }
2438
- if (failures >= maxFailures * 2) break;
2597
+ if (realisticFailures() >= maxFailures * 2) break;
2439
2598
  }
2440
2599
  shrinkEvaluations += evals;
2441
2600
  const sameCluster = async (candidates) => {
@@ -2450,7 +2609,9 @@ async function explore(options) {
2450
2609
  finals.set(stableKey(h.input), h.input);
2451
2610
  finals.set(stableKey(start), start);
2452
2611
  }
2453
- const ranked = [...finals.values()].filter((input) => classify(input, cache.get(stableKey(input)))?.key === cluster.key).sort((a, b) => tierOf(b) - tierOf(a) || inputComplexity(a) - inputComplexity(b)).slice(0, maxWitnesses);
2612
+ const ranked = [...finals.values()].filter((input) => classify(input, cache.get(stableKey(input)))?.key === cluster.key).sort(
2613
+ (a, b) => tierOf(b) - tierOf(a) || witnessCost(a, cache.get(stableKey(a))) - witnessCost(b, cache.get(stableKey(b)))
2614
+ ).slice(0, maxWitnesses);
2454
2615
  cluster.witnesses = ranked.map((input, i) => {
2455
2616
  const r = cache.get(stableKey(input));
2456
2617
  const w = {
@@ -2468,7 +2629,7 @@ async function explore(options) {
2468
2629
  for (const cluster of clusters.values()) {
2469
2630
  for (const w of cluster.witnesses) w.realism ??= options.realism(w.input);
2470
2631
  cluster.witnesses.sort(
2471
- (a, b) => b.realism.tier - a.realism.tier || inputComplexity(a.input) - inputComplexity(b.input)
2632
+ (a, b) => b.realism.tier - a.realism.tier || witnessCost(a.input, { base: a.base, head: a.head }) - witnessCost(b.input, { base: b.base, head: b.head })
2472
2633
  );
2473
2634
  cluster.witnesses.forEach((w, i) => w.minimal = i === 0);
2474
2635
  }
@@ -2500,13 +2661,15 @@ async function explore(options) {
2500
2661
  flakyClusters,
2501
2662
  stoppedBy,
2502
2663
  shrinkEvaluations,
2503
- failures
2664
+ failures,
2665
+ edgeFailures,
2666
+ skippedEdgeInputs
2504
2667
  };
2505
2668
  }
2506
2669
 
2507
2670
  // src/core/types/fromType.ts
2508
2671
  import {
2509
- Node as Node4,
2672
+ Node as Node5,
2510
2673
  ts as ts3
2511
2674
  } from "ts-morph";
2512
2675
 
@@ -2611,6 +2774,11 @@ function printSpec(spec) {
2611
2774
  return spec.kind;
2612
2775
  }
2613
2776
  }
2777
+ function markSize(spec) {
2778
+ if (spec.kind === "number") return { kind: "number", size: true };
2779
+ if (spec.kind === "union") return { ...spec, options: spec.options.map(markSize) };
2780
+ return spec;
2781
+ }
2614
2782
 
2615
2783
  // src/core/types/fromType.ts
2616
2784
  var MAX_UNION_OPTIONS = 64;
@@ -2753,7 +2921,7 @@ function objectLike(type, ctx) {
2753
2921
  }
2754
2922
  function isClassInstance(type) {
2755
2923
  const decls = type.getSymbol()?.getDeclarations() ?? [];
2756
- return decls.some((d) => Node4.isClassDeclaration(d) || Node4.isClassExpression(d));
2924
+ return decls.some((d) => Node5.isClassDeclaration(d) || Node5.isClassExpression(d));
2757
2925
  }
2758
2926
  function unwrapPromise(type) {
2759
2927
  const name = symbolName(type);
@@ -2832,7 +3000,7 @@ function paramSpec(p, location, index) {
2832
3000
  if (optional && !rest) {
2833
3001
  spec = spec.kind === "union" ? spec.options.some((o) => o.kind === "undefined") ? spec : { kind: "union", options: [...spec.options, { kind: "undefined" }] } : spec.kind === "undefined" ? spec : { kind: "union", options: [spec, { kind: "undefined" }] };
2834
3002
  }
2835
- const name = Node4.isIdentifier(p.getNameNode()) ? p.getName() : `arg${index}`;
3003
+ const name = Node5.isIdentifier(p.getNameNode()) ? p.getName() : `arg${index}`;
2836
3004
  return { name, spec, optional, rest };
2837
3005
  }
2838
3006
  function signatureFromNode(fn) {
@@ -2846,7 +3014,7 @@ function signatureFromCallable(decl) {
2846
3014
  const checker = decl.getProject().getTypeChecker();
2847
3015
  const params = sig.getParameters().map((sym, i) => {
2848
3016
  const pdecl = sym.getValueDeclaration();
2849
- const isParam = pdecl !== void 0 && Node4.isParameterDeclaration(pdecl);
3017
+ const isParam = pdecl !== void 0 && Node5.isParameterDeclaration(pdecl);
2850
3018
  const rest = isParam && pdecl.isRestParameter();
2851
3019
  const optional = !rest && ((sym.getFlags() & ts3.SymbolFlags.Optional) !== 0 || isParam && (pdecl.isOptional() || pdecl.hasInitializer()));
2852
3020
  let type = checker.getTypeOfSymbolAtLocation(sym, decl);
@@ -2861,26 +3029,26 @@ function signatureFromCallable(decl) {
2861
3029
  return { params, async: unwrapPromise(sig.getReturnType()) !== void 0 };
2862
3030
  }
2863
3031
  function signatureOf(node) {
2864
- return Node4.isVariableDeclaration(node) ? signatureFromCallable(node) : signatureFromNode(node);
3032
+ return Node5.isVariableDeclaration(node) ? signatureFromCallable(node) : signatureFromNode(node);
2865
3033
  }
2866
3034
 
2867
3035
  // src/core/analyze/guards.ts
2868
- import { Node as Node5, SyntaxKind as SyntaxKind4 } from "ts-morph";
3036
+ import { Node as Node6, SyntaxKind as SyntaxKind5 } from "ts-morph";
2869
3037
  var UNKNOWN = /* @__PURE__ */ Symbol("unknown");
2870
3038
  function compile2(node, params) {
2871
- if (Node5.isParenthesizedExpression(node)) return compile2(node.getExpression(), params);
2872
- if (Node5.isNumericLiteral(node)) {
3039
+ if (Node6.isParenthesizedExpression(node)) return compile2(node.getExpression(), params);
3040
+ if (Node6.isNumericLiteral(node)) {
2873
3041
  const v = node.getLiteralValue();
2874
3042
  return () => v;
2875
3043
  }
2876
- if (Node5.isStringLiteral(node) || Node5.isNoSubstitutionTemplateLiteral(node)) {
3044
+ if (Node6.isStringLiteral(node) || Node6.isNoSubstitutionTemplateLiteral(node)) {
2877
3045
  const v = node.getLiteralValue();
2878
3046
  return () => v;
2879
3047
  }
2880
- if (node.getKind() === SyntaxKind4.TrueKeyword) return () => true;
2881
- if (node.getKind() === SyntaxKind4.FalseKeyword) return () => false;
2882
- if (node.getKind() === SyntaxKind4.NullKeyword) return () => null;
2883
- if (Node5.isIdentifier(node)) {
3048
+ if (node.getKind() === SyntaxKind5.TrueKeyword) return () => true;
3049
+ if (node.getKind() === SyntaxKind5.FalseKeyword) return () => false;
3050
+ if (node.getKind() === SyntaxKind5.NullKeyword) return () => null;
3051
+ if (Node6.isIdentifier(node)) {
2884
3052
  const name = node.getText();
2885
3053
  if (name === "undefined") return () => void 0;
2886
3054
  if (name === "NaN") return () => NaN;
@@ -2888,7 +3056,7 @@ function compile2(node, params) {
2888
3056
  if (params.has(name)) return (env) => env.get(name);
2889
3057
  return void 0;
2890
3058
  }
2891
- if (Node5.isPropertyAccessExpression(node) && node.getName() === "length") {
3059
+ if (Node6.isPropertyAccessExpression(node) && node.getName() === "length") {
2892
3060
  const obj = compile2(node.getExpression(), params);
2893
3061
  if (!obj) return void 0;
2894
3062
  return (env) => {
@@ -2896,7 +3064,7 @@ function compile2(node, params) {
2896
3064
  return typeof v === "string" || Array.isArray(v) ? v.length : UNKNOWN;
2897
3065
  };
2898
3066
  }
2899
- if (Node5.isTypeOfExpression(node)) {
3067
+ if (Node6.isTypeOfExpression(node)) {
2900
3068
  const e = compile2(node.getExpression(), params);
2901
3069
  if (!e) return void 0;
2902
3070
  return (env) => {
@@ -2904,16 +3072,16 @@ function compile2(node, params) {
2904
3072
  return v === UNKNOWN ? UNKNOWN : v === null ? "object" : typeof v;
2905
3073
  };
2906
3074
  }
2907
- if (Node5.isPrefixUnaryExpression(node)) {
3075
+ if (Node6.isPrefixUnaryExpression(node)) {
2908
3076
  const e = compile2(node.getOperand(), params);
2909
3077
  if (!e) return void 0;
2910
3078
  const op = node.getOperatorToken();
2911
- if (op === SyntaxKind4.ExclamationToken) return (env) => e(env) === UNKNOWN ? UNKNOWN : !e(env);
2912
- if (op === SyntaxKind4.MinusToken)
3079
+ if (op === SyntaxKind5.ExclamationToken) return (env) => e(env) === UNKNOWN ? UNKNOWN : !e(env);
3080
+ if (op === SyntaxKind5.MinusToken)
2913
3081
  return (env) => typeof e(env) === "number" ? -e(env) : UNKNOWN;
2914
3082
  return void 0;
2915
3083
  }
2916
- if (Node5.isCallExpression(node)) {
3084
+ if (Node6.isCallExpression(node)) {
2917
3085
  const callee = node.getExpression().getText().replace(/\s+/g, "");
2918
3086
  const fns = {
2919
3087
  "Number.isInteger": Number.isInteger,
@@ -2934,7 +3102,7 @@ function compile2(node, params) {
2934
3102
  return v === UNKNOWN ? UNKNOWN : fn(v);
2935
3103
  };
2936
3104
  }
2937
- if (Node5.isBinaryExpression(node)) {
3105
+ if (Node6.isBinaryExpression(node)) {
2938
3106
  const l = compile2(node.getLeft(), params);
2939
3107
  const r = compile2(node.getRight(), params);
2940
3108
  if (!l || !r) return void 0;
@@ -2945,29 +3113,29 @@ function compile2(node, params) {
2945
3113
  return a === UNKNOWN || b === UNKNOWN ? UNKNOWN : f(a, b);
2946
3114
  };
2947
3115
  switch (op) {
2948
- case SyntaxKind4.LessThanToken:
3116
+ case SyntaxKind5.LessThanToken:
2949
3117
  return cmp((a, b) => a < b);
2950
- case SyntaxKind4.LessThanEqualsToken:
3118
+ case SyntaxKind5.LessThanEqualsToken:
2951
3119
  return cmp((a, b) => a <= b);
2952
- case SyntaxKind4.GreaterThanToken:
3120
+ case SyntaxKind5.GreaterThanToken:
2953
3121
  return cmp((a, b) => a > b);
2954
- case SyntaxKind4.GreaterThanEqualsToken:
3122
+ case SyntaxKind5.GreaterThanEqualsToken:
2955
3123
  return cmp((a, b) => a >= b);
2956
- case SyntaxKind4.EqualsEqualsEqualsToken:
3124
+ case SyntaxKind5.EqualsEqualsEqualsToken:
2957
3125
  return cmp((a, b) => a === b);
2958
- case SyntaxKind4.ExclamationEqualsEqualsToken:
3126
+ case SyntaxKind5.ExclamationEqualsEqualsToken:
2959
3127
  return cmp((a, b) => a !== b);
2960
- case SyntaxKind4.EqualsEqualsToken:
3128
+ case SyntaxKind5.EqualsEqualsToken:
2961
3129
  return cmp((a, b) => a == b);
2962
- case SyntaxKind4.ExclamationEqualsToken:
3130
+ case SyntaxKind5.ExclamationEqualsToken:
2963
3131
  return cmp((a, b) => a != b);
2964
- case SyntaxKind4.AmpersandAmpersandToken:
3132
+ case SyntaxKind5.AmpersandAmpersandToken:
2965
3133
  return (env) => {
2966
3134
  const a = l(env);
2967
3135
  if (a === UNKNOWN) return UNKNOWN;
2968
3136
  return a ? r(env) : a;
2969
3137
  };
2970
- case SyntaxKind4.BarBarToken:
3138
+ case SyntaxKind5.BarBarToken:
2971
3139
  return (env) => {
2972
3140
  const a = l(env);
2973
3141
  if (a === UNKNOWN) return UNKNOWN;
@@ -2980,30 +3148,30 @@ function compile2(node, params) {
2980
3148
  return void 0;
2981
3149
  }
2982
3150
  function isExit(stmt) {
2983
- if (Node5.isThrowStatement(stmt) || Node5.isReturnStatement(stmt)) return true;
2984
- if (Node5.isBlock(stmt)) {
3151
+ if (Node6.isThrowStatement(stmt) || Node6.isReturnStatement(stmt)) return true;
3152
+ if (Node6.isBlock(stmt)) {
2985
3153
  const s = stmt.getStatements();
2986
3154
  return s.length >= 1 && isExit(s[s.length - 1]);
2987
3155
  }
2988
3156
  return false;
2989
3157
  }
2990
3158
  function inferGuards(fn) {
2991
- if (!(Node5.isFunctionDeclaration(fn) || Node5.isFunctionExpression(fn) || Node5.isArrowFunction(fn)))
3159
+ if (!(Node6.isFunctionDeclaration(fn) || Node6.isFunctionExpression(fn) || Node6.isArrowFunction(fn)))
2992
3160
  return void 0;
2993
3161
  const body = fn.getBody();
2994
- if (!body || !Node5.isBlock(body)) return void 0;
3162
+ if (!body || !Node6.isBlock(body)) return void 0;
2995
3163
  const paramDecls = fn.getParameters();
2996
- const names = paramDecls.map((p) => Node5.isIdentifier(p.getNameNode()) ? p.getName() : void 0);
3164
+ const names = paramDecls.map((p) => Node6.isIdentifier(p.getNameNode()) ? p.getName() : void 0);
2997
3165
  const params = new Set(names.filter((n3) => !!n3));
2998
3166
  const checks = [];
2999
3167
  for (const stmt of body.getStatements()) {
3000
- if (Node5.isIfStatement(stmt) && !stmt.getElseStatement() && isExit(stmt.getThenStatement())) {
3168
+ if (Node6.isIfStatement(stmt) && !stmt.getElseStatement() && isExit(stmt.getThenStatement())) {
3001
3169
  const expr = compile2(stmt.getExpression(), params);
3002
3170
  if (expr) checks.push({ text: stmt.getExpression().getText(), expr });
3003
3171
  continue;
3004
3172
  }
3005
- if (Node5.isExpressionStatement(stmt) && Node5.isCallExpression(stmt.getExpression())) continue;
3006
- if (Node5.isVariableStatement(stmt) && checks.length === 0) continue;
3173
+ if (Node6.isExpressionStatement(stmt) && Node6.isCallExpression(stmt.getExpression())) continue;
3174
+ if (Node6.isVariableStatement(stmt) && checks.length === 0) continue;
3007
3175
  break;
3008
3176
  }
3009
3177
  if (checks.length === 0) return void 0;
@@ -3113,7 +3281,7 @@ function inputRealism(input, ctx) {
3113
3281
  }
3114
3282
 
3115
3283
  // src/core/verify/verifyFunction.ts
3116
- import { Node as Node6 } from "ts-morph";
3284
+ import { Node as Node7 } from "ts-morph";
3117
3285
 
3118
3286
  // src/core/types/accepts.ts
3119
3287
  function accepts(base, head) {
@@ -3279,11 +3447,16 @@ async function verifyFunction(session, target, options) {
3279
3447
  values: usage.numbers.length + usage.strings.length
3280
3448
  };
3281
3449
  }
3282
- const guards = Node6.isVariableDeclaration(baseLoc.node) ? void 0 : inferGuards(baseLoc.node);
3450
+ const guards = Node7.isVariableDeclaration(baseLoc.node) ? void 0 : inferGuards(baseLoc.node);
3283
3451
  if (guards) base.guards = guards.conditions;
3284
3452
  const realismCtx = realismContext(usage);
3285
3453
  base.mined = { numbers: mined.numbers.length, strings: mined.strings.length, thresholds: mined.thresholds };
3286
- const arbitrary = options.arbitrary ?? compileSignature(headSig, { mined });
3454
+ const sizeNames = sizeLikeParams([baseLoc.node, headLoc.node]);
3455
+ const genSig = sizeNames.size === 0 ? headSig : {
3456
+ ...headSig,
3457
+ params: headSig.params.map((p) => sizeNames.has(p.name) ? { ...p, spec: markSize(p.spec) } : p)
3458
+ };
3459
+ const arbitrary = options.arbitrary ?? compileSignature(genSig, { mined });
3287
3460
  if (!arbitrary) return skip("could not build an input generator for the signature");
3288
3461
  let examples = [...usage?.tuples ?? [], ...options.examples ?? []];
3289
3462
  if (options.where) examples = examples.filter((e) => safeWhere(options.where, e));
@@ -3324,10 +3497,10 @@ async function verifyFunction(session, target, options) {
3324
3497
  if (!m.load.exports.includes(target.exportName))
3325
3498
  return skip(`export \`${target.exportName}\` not found at runtime (${label})`);
3326
3499
  }
3327
- const evaluate = async (inputs) => {
3500
+ const evaluate = async (inputs, opts) => {
3328
3501
  const [b, h] = await Promise.all([
3329
- session.pools.base.run(baseMod.moduleId, target.exportName, inputs),
3330
- session.pools.head.run(headMod.moduleId, target.exportName, inputs)
3502
+ session.pools.base.run(baseMod.moduleId, target.exportName, inputs, opts),
3503
+ session.pools.head.run(headMod.moduleId, target.exportName, inputs, opts)
3331
3504
  ]);
3332
3505
  return b.map((o, i) => ({ base: o, head: h[i] }));
3333
3506
  };
@@ -3352,6 +3525,8 @@ async function verifyFunction(session, target, options) {
3352
3525
  flakyClusters: result.flakyClusters,
3353
3526
  stoppedBy: result.stoppedBy,
3354
3527
  failures: result.failures,
3528
+ edgeFailures: result.edgeFailures,
3529
+ skippedEdgeInputs: result.skippedEdgeInputs,
3355
3530
  shrinkEvaluations: result.shrinkEvaluations,
3356
3531
  durationMs: Date.now() - started
3357
3532
  };
@@ -5047,6 +5222,10 @@ var FunctionReport = z.object({
5047
5222
  inputsRun: z.number().int().nonnegative(),
5048
5223
  stoppedBy: z.enum(["runs", "deadline", "failures", "exhausted"]).optional(),
5049
5224
  failures: z.number().int().nonnegative(),
5225
+ /** Timeouts/crashes on edge-case inputs (huge numbers, NaN, …), included in `failures`. */
5226
+ edgeTimeouts: z.number().int().nonnegative().optional(),
5227
+ /** Edge-case inputs skipped after repeated timeouts on edge-case inputs. */
5228
+ skippedEdgeInputs: z.number().int().nonnegative().optional(),
5050
5229
  durationMs: z.number().nonnegative(),
5051
5230
  seed: z.number().int(),
5052
5231
  usage: z.object({ files: z.number().int(), callSites: z.number().int(), values: z.number().int() }).optional(),
@@ -5151,14 +5330,14 @@ function applyRuleLabels(report, forceRefactor = false) {
5151
5330
  return report;
5152
5331
  }
5153
5332
  var MAX_DISPLAY = 300;
5154
- function outcomeView(o) {
5333
+ function outcomeView(o, abbreviate = true) {
5155
5334
  switch (o.kind) {
5156
5335
  case "return": {
5157
5336
  const code2 = encToCode(o.value);
5158
5337
  return {
5159
5338
  kind: "return",
5160
5339
  async: o.async,
5161
- display: formatOutcome(o, MAX_DISPLAY),
5340
+ display: formatOutcome(o, MAX_DISPLAY, abbreviate),
5162
5341
  ...code2 !== void 0 && code2.length < 4e3 ? { code: code2 } : {}
5163
5342
  };
5164
5343
  }
@@ -5167,7 +5346,7 @@ function outcomeView(o) {
5167
5346
  return {
5168
5347
  kind: "throw",
5169
5348
  async: o.async,
5170
- display: formatOutcome(o, MAX_DISPLAY),
5349
+ display: formatOutcome(o, MAX_DISPLAY, abbreviate),
5171
5350
  ...e.t === "error" ? { errorClass: e.ctor.slice(0, 200), message: e.message.slice(0, 4e3) } : {}
5172
5351
  };
5173
5352
  }
@@ -5184,16 +5363,21 @@ function exampleFrom(exportName, w) {
5184
5363
  new: outcomeView(w.head),
5185
5364
  minimal: w.minimal
5186
5365
  };
5366
+ if (ex.old.display === ex.new.display) {
5367
+ ex.old = outcomeView(w.base, false);
5368
+ ex.new = outcomeView(w.head, false);
5369
+ }
5187
5370
  if (w.diff.aspect === "mutation" && (w.base.kind === "return" || w.base.kind === "throw") && (w.head.kind === "return" || w.head.kind === "throw")) {
5188
5371
  const i = Number(w.diff.path[0]);
5189
5372
  const a = w.base.args[i];
5190
5373
  const b = w.head.args[i];
5191
5374
  if (a && b) {
5192
5375
  const newCode = encToCode(b);
5376
+ const full = formatEnc(a, MAX_DISPLAY) === formatEnc(b, MAX_DISPLAY);
5193
5377
  ex.mutation = {
5194
5378
  argIndex: i,
5195
- old: formatEnc(a, MAX_DISPLAY),
5196
- new: formatEnc(b, MAX_DISPLAY),
5379
+ old: formatEnc(a, MAX_DISPLAY, !full),
5380
+ new: formatEnc(b, MAX_DISPLAY, !full),
5197
5381
  ...newCode !== void 0 && newCode.length < 4e3 ? { newCode } : {}
5198
5382
  };
5199
5383
  }
@@ -5225,6 +5409,8 @@ function functionReport(f) {
5225
5409
  inputsRun: f.inputsRun,
5226
5410
  ...f.stoppedBy ? { stoppedBy: f.stoppedBy } : {},
5227
5411
  failures: f.failures,
5412
+ ...f.edgeFailures ? { edgeTimeouts: f.edgeFailures } : {},
5413
+ ...f.skippedEdgeInputs ? { skippedEdgeInputs: f.skippedEdgeInputs } : {},
5228
5414
  durationMs: f.durationMs,
5229
5415
  seed: f.seed,
5230
5416
  ...f.usage ? { usage: f.usage } : {},
@@ -5406,6 +5592,18 @@ function render(r, maxExamples, sticky) {
5406
5592
  const edge = r.functions.flatMap(
5407
5593
  (f) => f.behaviors.filter((b) => b.realism === "edge").map((b) => ({ f, b }))
5408
5594
  );
5595
+ const timedOut = r.functions.filter((f) => (f.edgeTimeouts ?? 0) > 0);
5596
+ const timeoutLine = timedOut.length ? `\u23F1\uFE0F Timed out on edge-case inputs (huge numbers, NaN, \u2026); similar inputs were skipped: ${timedOut.map((f) => `${code(f.exportName, 60)} (${n(f.edgeTimeouts ?? 0)})`).join(", ")}.` : "";
5597
+ if (edge.length === 0 && timeoutLine) {
5598
+ lines.push(
5599
+ "",
5600
+ `<details><summary>\u23F1\uFE0F Some edge-case inputs timed out</summary>`,
5601
+ "",
5602
+ timeoutLine,
5603
+ "",
5604
+ "</details>"
5605
+ );
5606
+ }
5409
5607
  if (edge.length > 0) {
5410
5608
  const reasons = [...new Set(edge.map(({ b }) => b.realismNote).filter(Boolean))].slice(0, 4).join(", ");
5411
5609
  const tag = {
@@ -5418,7 +5616,9 @@ function render(r, maxExamples, sticky) {
5418
5616
  "",
5419
5617
  `<details><summary>\u{1F9EA} ${edge.length} behavior change${edge.length === 1 ? "" : "s"} only on edge-case inputs${reasons ? ` (${escapeText(reasons)})` : ""}</summary>`,
5420
5618
  "",
5421
- edge.map(({ f, b }) => `${tag[b.label] ?? ""}${behaviorBlock(f, b, maxExamples)}`).join("\n\n"),
5619
+ // Compact: one example per edge-case behavior.
5620
+ edge.map(({ f, b }) => `${tag[b.label] ?? ""}${behaviorBlock(f, b, 1)}`).join("\n\n"),
5621
+ ...timeoutLine ? ["", timeoutLine] : [],
5422
5622
  "",
5423
5623
  "</details>"
5424
5624
  );