@elaraai/e3-ui-components 1.0.80 → 1.0.81

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 (40) hide show
  1. package/dist/components/DatasetPreview.d.ts +10 -2
  2. package/dist/components/DatasetPreview.d.ts.map +1 -1
  3. package/dist/components/EastValueViewer.d.ts.map +1 -1
  4. package/dist/components/PagedDatasetPreview.d.ts +15 -1
  5. package/dist/components/PagedDatasetPreview.d.ts.map +1 -1
  6. package/dist/decision/constraint-format.d.ts +15 -7
  7. package/dist/decision/constraint-format.d.ts.map +1 -1
  8. package/dist/decision/contract.d.ts +28 -0
  9. package/dist/decision/contract.d.ts.map +1 -0
  10. package/dist/decision/facets.d.ts +21 -3
  11. package/dist/decision/facets.d.ts.map +1 -1
  12. package/dist/decision/grouping.d.ts +11 -0
  13. package/dist/decision/grouping.d.ts.map +1 -1
  14. package/dist/decision/handle-runtime.d.ts.map +1 -1
  15. package/dist/decision/journal.d.ts.map +1 -1
  16. package/dist/decision/lever-editor.d.ts +11 -18
  17. package/dist/decision/lever-editor.d.ts.map +1 -1
  18. package/dist/decision/queue.d.ts.map +1 -1
  19. package/dist/diff/format.d.ts +20 -12
  20. package/dist/diff/format.d.ts.map +1 -1
  21. package/dist/diff/index.d.ts.map +1 -1
  22. package/dist/diff/manual.d.ts +37 -18
  23. package/dist/diff/manual.d.ts.map +1 -1
  24. package/dist/diff/walker.d.ts +14 -6
  25. package/dist/diff/walker.d.ts.map +1 -1
  26. package/dist/experiment/charts.d.ts +4 -1
  27. package/dist/experiment/charts.d.ts.map +1 -1
  28. package/dist/experiment/derive.d.ts +25 -5
  29. package/dist/experiment/derive.d.ts.map +1 -1
  30. package/dist/experiment/index.d.ts.map +1 -1
  31. package/dist/experiment/run-runtime.d.ts +4 -8
  32. package/dist/experiment/run-runtime.d.ts.map +1 -1
  33. package/dist/index.cjs +621 -709
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.js +641 -729
  36. package/dist/index.js.map +1 -1
  37. package/dist/platform/func-runtime.d.ts +2 -2
  38. package/dist/platform/func-runtime.d.ts.map +1 -1
  39. package/dist/platform/paged-runtime.d.ts.map +1 -1
  40. package/package.json +16 -15
package/dist/index.cjs CHANGED
@@ -2998,7 +2998,7 @@ function clearStagedStoreSingleton() {
2998
2998
  }
2999
2999
  const UNCHANGED_VARIANT = east.variant("unchanged", null);
3000
3000
  const blobEqual = east.equalFor(east.BlobType);
3001
- const eastTypeEqual$2 = east.equalFor(internal.EastTypeType);
3001
+ const eastTypeEqual$1 = east.equalFor(internal.EastTypeType);
3002
3002
  const helpersCache = new east.SortedMap(
3003
3003
  void 0,
3004
3004
  east.compareFor(internal.EastTypeType)
@@ -3207,11 +3207,11 @@ class BindRuntime {
3207
3207
  const key = datasetCacheKey(workspace, sourcePath);
3208
3208
  const existing = this.bindingRegistry.get(key);
3209
3209
  if (existing) {
3210
- if (existing.mode === info.mode && existing.hasPatchDataset === info.hasPatchDataset && existing.sourceType === info.sourceType) {
3210
+ if (existing.mode === info.mode && existing.hasPatchDataset === info.hasPatchDataset && Object.is(existing.sourceType, info.sourceType)) {
3211
3211
  return;
3212
3212
  }
3213
3213
  const shapeChanged = existing.mode !== info.mode || existing.hasPatchDataset !== info.hasPatchDataset;
3214
- const typeChanged = !eastTypeEqual$2(existing.sourceType, info.sourceType);
3214
+ const typeChanged = !eastTypeEqual$1(existing.sourceType, info.sourceType);
3215
3215
  if (!shapeChanged && !typeChanged) {
3216
3216
  this.bindingRegistry.set(key, info);
3217
3217
  return;
@@ -3401,7 +3401,7 @@ class BindRuntime {
3401
3401
  };
3402
3402
  const bindingDescriptor = {
3403
3403
  source: sourcePath,
3404
- patch: patchPath ? east.variant("some", patchPath) : east.variant("none", null),
3404
+ patch: patchPath ? east.some(patchPath) : east.none,
3405
3405
  mode: east.variant(mode, null)
3406
3406
  };
3407
3407
  const writeStaged = (value) => {
@@ -4494,13 +4494,12 @@ function createDefaultFunctionApi(apiUrl, repo, getToken) {
4494
4494
  async call(workspace, fn3, req) {
4495
4495
  return e3ApiClient.workspaceFunctionCall(apiUrl, repo, workspace, fn3, {
4496
4496
  args: req.args,
4497
- runner: east.variant("none", null),
4498
- limits: east.variant("none", null)
4497
+ runner: east.none,
4498
+ limits: east.none
4499
4499
  }, opts());
4500
4500
  }
4501
4501
  };
4502
4502
  }
4503
- const eastTypeEqual$1 = east.equalFor(internal.EastTypeType);
4504
4503
  function signatureOfFuncHandleType(handleType) {
4505
4504
  var _a2, _b2;
4506
4505
  if (handleType.type !== "Struct") {
@@ -4644,8 +4643,8 @@ class FuncRuntime extends TrackedChannelStore {
4644
4643
  stderr: ""
4645
4644
  };
4646
4645
  }
4647
- const inputsMatch = deployed.inputTypes.length === sig.inputs.length && deployed.inputTypes.every((t4, i) => eastTypeEqual$1(t4, sig.inputs[i]));
4648
- const outputMatches = eastTypeEqual$1(deployed.outputType, sig.output);
4646
+ const inputsMatch = deployed.inputTypes.length === sig.inputs.length && deployed.inputTypes.every((t4, i) => east.isTypeValueEqual(t4, sig.inputs[i]));
4647
+ const outputMatches = east.isTypeValueEqual(deployed.outputType, sig.output);
4649
4648
  if (!inputsMatch || !outputMatches) {
4650
4649
  const message = `signature mismatch for "${name}": bound (${sig.inputs.length} inputs) disagrees with the deployed package`;
4651
4650
  return {
@@ -4748,7 +4747,7 @@ class FuncRuntime extends TrackedChannelStore {
4748
4747
  internal$1.FuncBindPrimitives.read.implement((_outputType) => (nameArg) => {
4749
4748
  const { key, entry } = channel(nameArg);
4750
4749
  runtime.track(key);
4751
- return entry.result !== void 0 ? east.variant("some", entry.result) : east.variant("none", null);
4750
+ return entry.result !== void 0 ? east.some(entry.result) : east.none;
4752
4751
  }),
4753
4752
  internal$1.FuncBindPrimitives.status.implement((nameArg) => {
4754
4753
  const { key, entry } = channel(nameArg);
@@ -4758,7 +4757,7 @@ class FuncRuntime extends TrackedChannelStore {
4758
4757
  internal$1.FuncBindPrimitives.error.implement((nameArg) => {
4759
4758
  const { key, entry } = channel(nameArg);
4760
4759
  runtime.track(key);
4761
- return entry.status === "failed" && entry.error !== void 0 ? east.variant("some", entry.error) : east.variant("none", null);
4760
+ return entry.status === "failed" && entry.error !== void 0 ? east.some(entry.error) : east.none;
4762
4761
  }),
4763
4762
  internal$1.FuncBindPrimitives.pending.implement((nameArg) => {
4764
4763
  const { key, entry } = channel(nameArg);
@@ -9258,12 +9257,11 @@ function collectLeaves(node2, into = []) {
9258
9257
  else for (const c2 of node2.children) collectLeaves(c2, into);
9259
9258
  return into;
9260
9259
  }
9260
+ const readString = east.parseFor(east.StringType);
9261
9261
  function leafDisplayLabel(seg) {
9262
- if (seg.kind === "key" && typeof seg.key === "string" && seg.key.length >= 2 && seg.key.startsWith('"') && seg.key.endsWith('"')) {
9263
- try {
9264
- return JSON.parse(seg.key);
9265
- } catch {
9266
- }
9262
+ if (seg.kind === "key") {
9263
+ const read = readString(seg.key);
9264
+ if (read.success) return read.value;
9267
9265
  }
9268
9266
  return east.pathDisplay(seg);
9269
9267
  }
@@ -9315,57 +9313,28 @@ function walkPatchToTree(typeValue, patch, rootLabel) {
9315
9313
  return root2;
9316
9314
  }
9317
9315
  const MAX_INLINE_CHARS = 48;
9318
- function formatLeafValue(typeValue, value) {
9319
- if (value === null || value === void 0) return "null";
9320
- if (!typeValue) return "<value>";
9321
- switch (typeValue.type) {
9322
- case "Null":
9323
- return "null";
9324
- case "Boolean":
9325
- return value ? "true" : "false";
9326
- case "Integer":
9327
- return typeof value === "bigint" ? value.toString() : String(value);
9328
- case "Float":
9329
- return formatFloat(value);
9330
- case "String":
9331
- return value === "" ? '""' : String(value);
9332
- case "DateTime":
9333
- return value instanceof Date ? value.toISOString() : String(value);
9334
- case "Blob":
9335
- return value instanceof Uint8Array ? `${value.length} bytes` : truncate(east.printFor(typeValue)(value));
9336
- case "Variant":
9337
- if (east.isVariant(value)) {
9338
- const cases = typeValue.value;
9339
- const sub = cases.find((c2) => c2.name === value.type);
9340
- if (value.value === null || value.value === void 0 || !sub) return value.type;
9341
- return `${value.type}(${truncate(east.printFor(sub.type)(value.value))})`;
9342
- }
9343
- return "<value>";
9344
- default:
9345
- return truncate(east.printFor(typeValue)(value));
9346
- }
9347
- }
9348
- function formatFloat(v3) {
9349
- if (typeof v3 !== "number") return String(v3);
9350
- if (Number.isInteger(v3)) return v3.toFixed(1);
9351
- return Math.abs(v3) >= 1e3 ? v3.toLocaleString("en-US", { maximumFractionDigits: 2 }) : String(Number(v3.toFixed(4)));
9316
+ function formatLeafValue(leafType, value, words = eastUiComponents.formatters()) {
9317
+ if (leafType.type === "Float") return words.float(value);
9318
+ const text = east.printFor(leafType)(value);
9319
+ return leafType.type === "String" ? text : truncate(text);
9352
9320
  }
9353
9321
  function truncate(s2) {
9354
9322
  return s2.length > MAX_INLINE_CHARS ? s2.slice(0, MAX_INLINE_CHARS - 1) + "…" : s2;
9355
9323
  }
9356
- function formatBindingLabel(segments) {
9357
- if (segments.length === 0) return "(root)";
9358
- const last2 = segments[segments.length - 1];
9359
- if (last2 && typeof last2 === "object" && "type" in last2) {
9360
- if (last2.type === "field") return String(last2.value);
9361
- if (last2.type === "index") return `[${String(last2.value)}]`;
9362
- if (last2.type === "key") return String(last2.value);
9324
+ function formatBindingLabel(path2) {
9325
+ const last2 = path2[path2.length - 1];
9326
+ if (last2 === void 0) return "(root)";
9327
+ switch (last2.type) {
9328
+ case "field":
9329
+ return last2.value;
9363
9330
  }
9364
- return String(last2);
9365
9331
  }
9366
- function isPrimitiveLeafType(t4) {
9367
- if (!t4) return false;
9368
- switch (t4.type) {
9332
+ const DATETIME_LOCAL = internal.tokenizeDateTimeFormat("YYYY-MM-DDTHH:mm");
9333
+ const readBoolean = east.parseFor(east.BooleanType);
9334
+ const readInteger = east.parseFor(east.IntegerType);
9335
+ const readFloat = east.parseFor(east.FloatType);
9336
+ function isPrimitiveLeafType(leafType) {
9337
+ switch (leafType.type) {
9369
9338
  case "Boolean":
9370
9339
  case "Integer":
9371
9340
  case "Float":
@@ -9377,49 +9346,46 @@ function isPrimitiveLeafType(t4) {
9377
9346
  }
9378
9347
  }
9379
9348
  function formatManualDraft(leafType, value) {
9380
- if (!leafType || value === void 0 || value === null) return "";
9349
+ if (value === void 0) return "";
9381
9350
  switch (leafType.type) {
9382
9351
  case "Boolean":
9383
- return value ? "true" : "false";
9384
9352
  case "Integer":
9385
- return typeof value === "bigint" ? value.toString() : String(value);
9386
9353
  case "Float":
9387
- return typeof value === "number" ? String(value) : String(value);
9354
+ return east.printFor(leafType)(value);
9388
9355
  case "String":
9389
- return String(value);
9390
- case "DateTime": {
9391
- if (!(value instanceof Date)) return String(value);
9392
- return value.toISOString().slice(0, 16);
9393
- }
9356
+ return value;
9357
+ case "DateTime":
9358
+ return internal.formatDateTime(value, DATETIME_LOCAL);
9394
9359
  default:
9395
9360
  return "";
9396
9361
  }
9397
9362
  }
9398
9363
  function parseManualDraft(leafType, draft) {
9399
- try {
9400
- switch (leafType.type) {
9401
- case "Integer":
9402
- return { ok: true, value: BigInt(draft) };
9403
- case "Float": {
9404
- const n2 = Number(draft);
9405
- if (Number.isNaN(n2)) return { ok: false };
9406
- return { ok: true, value: n2 };
9407
- }
9408
- case "String":
9409
- return { ok: true, value: draft };
9410
- case "DateTime": {
9411
- const d2 = new Date(draft);
9412
- if (Number.isNaN(d2.getTime())) return { ok: false };
9413
- return { ok: true, value: d2 };
9414
- }
9415
- default:
9416
- return { ok: false };
9364
+ switch (leafType.type) {
9365
+ case "Boolean": {
9366
+ const read = readBoolean(draft);
9367
+ return read.success ? { ok: true, value: read.value } : { ok: false };
9417
9368
  }
9418
- } catch {
9419
- return { ok: false };
9369
+ case "Integer": {
9370
+ const read = readInteger(draft);
9371
+ return read.success ? { ok: true, value: read.value } : { ok: false };
9372
+ }
9373
+ case "Float": {
9374
+ const read = readFloat(draft);
9375
+ return read.success ? { ok: true, value: read.value } : { ok: false };
9376
+ }
9377
+ case "String":
9378
+ return { ok: true, value: draft };
9379
+ case "DateTime": {
9380
+ const read = internal.parseDateTimeFormatted(draft, DATETIME_LOCAL);
9381
+ return read.success ? { ok: true, value: read.value } : { ok: false };
9382
+ }
9383
+ default:
9384
+ return { ok: false };
9420
9385
  }
9421
9386
  }
9422
- const diffValueEqual = east.equalFor(internal$1.Diff.Component.schema);
9387
+ const diffValueEqual = east.equivalentFor(internal$1.Diff.Component.schema);
9388
+ const diffValueDataEqual = east.equalFor(internal$1.Diff.Component.schema);
9423
9389
  function getOpt$1(opt) {
9424
9390
  return opt.type === "some" ? opt.value : void 0;
9425
9391
  }
@@ -9645,6 +9611,7 @@ function ActionBtn({
9645
9611
  );
9646
9612
  }
9647
9613
  const DiffRow = React.memo(function DiffRow2({ row, depth, bindingPathStr, showActions, onDiscard, annotation, metrics }) {
9614
+ const words = eastUiComponents.useFormatters();
9648
9615
  const handleDiscard = React.useCallback(() => onDiscard(bindingPathStr, row.path), [onDiscard, bindingPathStr, row.path]);
9649
9616
  return /* @__PURE__ */ jsxRuntime.jsxs(
9650
9617
  react.Box,
@@ -9677,7 +9644,7 @@ const DiffRow = React.memo(function DiffRow2({ row, depth, bindingPathStr, showA
9677
9644
  row.stale && /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { fontSize: "11px", color: "fg.warning", fontWeight: 500, children: [
9678
9645
  /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faTriangleExclamation }),
9679
9646
  " ",
9680
- row.stale.actual === void 0 ? "stale — source no longer has this entry" : `stale — source actually has ${formatLeafValue(row.leafType, row.stale.actual)}`
9647
+ row.stale.actual === void 0 ? "stale — source no longer has this entry" : `stale — source actually has ${formatLeafValue(row.leafType, row.stale.actual, words)}`
9681
9648
  ] }),
9682
9649
  annotation && /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "11px", color: `${annotation.tone}.700`, fontWeight: 500, children: annotation.text })
9683
9650
  ] }),
@@ -9686,13 +9653,13 @@ const DiffRow = React.memo(function DiffRow2({ row, depth, bindingPathStr, showA
9686
9653
  row.before !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(Chip$1, { fontSize: metrics.chipFontSize, children: [
9687
9654
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", color: "fg.danger", children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faMinus }) }),
9688
9655
  " ",
9689
- formatLeafValue(row.leafType, row.before)
9656
+ formatLeafValue(row.leafType, row.before, words)
9690
9657
  ] }),
9691
9658
  row.before !== void 0 && row.after !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", color: "fg.subtle", fontSize: "11px", children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faArrowRight }) }),
9692
9659
  row.after !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(Chip$1, { fontSize: metrics.chipFontSize, children: [
9693
9660
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", color: "fg.success", children: /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faPlus }) }),
9694
9661
  " ",
9695
- formatLeafValue(row.leafType, row.after)
9662
+ formatLeafValue(row.leafType, row.after, words)
9696
9663
  ] })
9697
9664
  ] }),
9698
9665
  showActions && /* @__PURE__ */ jsxRuntime.jsx(ActionBtn, { icon: faXmark, title: "Discard this change", onClick: handleDiscard, size: metrics.actionBtnSize })
@@ -9701,9 +9668,11 @@ const DiffRow = React.memo(function DiffRow2({ row, depth, bindingPathStr, showA
9701
9668
  }
9702
9669
  );
9703
9670
  });
9671
+ const REMOVED = "(removed)";
9704
9672
  const ConflictRow = React.memo(function ConflictRow2({ row, depth, bindingPathStr, serverValue, resolution, onResolve, metrics }) {
9705
- const yoursStr = formatLeafValue(row.leafType, row.after);
9706
- const theirsStr = formatLeafValue(row.leafType, serverValue);
9673
+ const words = eastUiComponents.useFormatters();
9674
+ const yoursStr = row.after === void 0 ? REMOVED : formatLeafValue(row.leafType, row.after, words);
9675
+ const theirsStr = serverValue === void 0 ? REMOVED : formatLeafValue(row.leafType, serverValue, words);
9707
9676
  const isYours = (resolution == null ? void 0 : resolution.type) === "keepA";
9708
9677
  const isTheirs = (resolution == null ? void 0 : resolution.type) === "keepB";
9709
9678
  const isManual = (resolution == null ? void 0 : resolution.type) === "manual";
@@ -9769,7 +9738,7 @@ const ConflictRow = React.memo(function ConflictRow2({ row, depth, bindingPathSt
9769
9738
  {
9770
9739
  selected: isManual,
9771
9740
  leafType: row.leafType,
9772
- value: isManual ? resolution.value : row.after,
9741
+ value: (resolution == null ? void 0 : resolution.type) === "manual" ? resolution.value : row.after,
9773
9742
  onChange: handleManual
9774
9743
  }
9775
9744
  )
@@ -9886,9 +9855,8 @@ function ManualEditor({
9886
9855
  const fire = React.useCallback((parsed) => {
9887
9856
  queueMicrotask(() => onChange2(parsed));
9888
9857
  }, [onChange2]);
9889
- if (!leafType) return null;
9890
9858
  if (leafType.type === "Boolean") {
9891
- const checked = !!value;
9859
+ const checked = value === true;
9892
9860
  return /* @__PURE__ */ jsxRuntime.jsxs(
9893
9861
  react.Box,
9894
9862
  {
@@ -10070,9 +10038,10 @@ const EastChakraDiff = React.memo(function EastChakraDiff2({ value }) {
10070
10038
  const [conflicts, setConflicts] = React.useState(null);
10071
10039
  const [resolutions, setResolutions] = React.useState(/* @__PURE__ */ new Map());
10072
10040
  const [committing, setCommitting] = React.useState(false);
10041
+ const data4 = eastUiComponents.useDataStable(value, diffValueDataEqual);
10073
10042
  const irBindings = React.useMemo(
10074
- () => value.bindings ?? [],
10075
- [value.bindings]
10043
+ () => data4.bindings ?? [],
10044
+ [data4.bindings]
10076
10045
  );
10077
10046
  const interactive = !(getOpt$1(value.readonly) ?? false);
10078
10047
  const onCommittedFn = getOpt$1(value.onCommitted);
@@ -10106,7 +10075,7 @@ const EastChakraDiff = React.memo(function EastChakraDiff2({ value }) {
10106
10075
  React.useEffect(() => {
10107
10076
  setConflicts(null);
10108
10077
  setResolutions(/* @__PURE__ */ new Map());
10109
- }, [value, stagedVersion, datasetVersion]);
10078
+ }, [data4, stagedVersion, datasetVersion]);
10110
10079
  const visibleBindings = React.useMemo(
10111
10080
  () => bindings.filter((b2) => b2.leaves.length > 0),
10112
10081
  [bindings]
@@ -23485,13 +23454,13 @@ var hashIterableInts = function hashIterableInts2(iterator) {
23485
23454
  }
23486
23455
  return hash2;
23487
23456
  };
23488
- var hashInt = function hashInt2(num2) {
23457
+ var hashInt = function hashInt2(num) {
23489
23458
  var seed = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : DEFAULT_HASH_SEED;
23490
- return seed * K + num2 | 0;
23459
+ return seed * K + num | 0;
23491
23460
  };
23492
- var hashIntAlt = function hashIntAlt2(num2) {
23461
+ var hashIntAlt = function hashIntAlt2(num) {
23493
23462
  var seed = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : DEFAULT_HASH_SEED_ALT;
23494
- return (seed << 5) + seed + num2 | 0;
23463
+ return (seed << 5) + seed + num | 0;
23495
23464
  };
23496
23465
  var combineHashes = function combineHashes2(hash1, hash2) {
23497
23466
  return hash1 * 2097152 + hash2;
@@ -23521,7 +23490,7 @@ var hashIntsArray = function hashIntsArray2(ints, seed) {
23521
23490
  };
23522
23491
  return hashIterableInts(iterator, seed);
23523
23492
  };
23524
- var hashString$1 = function hashString(str, seed) {
23493
+ var hashString = function hashString2(str, seed) {
23525
23494
  var entry = {
23526
23495
  value: 0,
23527
23496
  done: false
@@ -23548,9 +23517,9 @@ var hashStringsArray = function hashStringsArray2(strs) {
23548
23517
  for (var i = 0; i < strs.length; i++) {
23549
23518
  var str = strs[i];
23550
23519
  if (i === 0) {
23551
- hash2 = hashString$1(str);
23520
+ hash2 = hashString(str);
23552
23521
  } else {
23553
- hash2 = hashString$1(str, hash2);
23522
+ hash2 = hashString(str, hash2);
23554
23523
  }
23555
23524
  }
23556
23525
  return hash2;
@@ -30688,7 +30657,7 @@ var cache = function cache2(fn3, name) {
30688
30657
  var _p = eles[0]._private;
30689
30658
  var tch = _p.traversalCache = _p.traversalCache || {};
30690
30659
  var ch = tch[name] = tch[name] || [];
30691
- var hash2 = hashString$1(key);
30660
+ var hash2 = hashString(key);
30692
30661
  var cacheHit = ch[hash2];
30693
30662
  if (cacheHit) {
30694
30663
  return cacheHit;
@@ -33294,13 +33263,13 @@ function styleCache(key, fn3, ele) {
33294
33263
  }
33295
33264
  }
33296
33265
  function cacheStyleFunction(key, fn3) {
33297
- key = hashString$1(key);
33266
+ key = hashString(key);
33298
33267
  return function cachedStyleFunction(ele) {
33299
33268
  return styleCache(key, fn3, ele);
33300
33269
  };
33301
33270
  }
33302
33271
  function cachePrototypeStyleFunction(key, fn3) {
33303
- key = hashString$1(key);
33272
+ key = hashString(key);
33304
33273
  var selfFn = function selfFn2(ele) {
33305
33274
  return fn3.call(ele);
33306
33275
  };
@@ -43571,7 +43540,7 @@ BRp$9.applyLabelDimensions = function(ele) {
43571
43540
  BRp$9.applyPrefixedLabelDimensions = function(ele, prefix2) {
43572
43541
  var _p = ele._private;
43573
43542
  var text = this.getLabelText(ele, prefix2);
43574
- var cacheKey = hashString$1(text, ele._private.labelDimsKey);
43543
+ var cacheKey = hashString(text, ele._private.labelDimsKey);
43575
43544
  if (getPrefixedProperty(_p.rscratch, "prefixedLabelDimsKey", prefix2) === cacheKey) {
43576
43545
  return;
43577
43546
  }
@@ -47967,7 +47936,7 @@ CRp$9.drawArrowShape = function(edge, context, fill, edgeWidth, shape, shapeWidt
47967
47936
  var shapeImpl = r2.arrowShapes[shape];
47968
47937
  if (usePaths) {
47969
47938
  var cache3 = r2.arrowPathCache = r2.arrowPathCache || [];
47970
- var key = hashString$1(shape);
47939
+ var key = hashString(shape);
47971
47940
  var cachedPath = cache3[key];
47972
47941
  if (cachedPath != null) {
47973
47942
  path2 = context = cachedPath;
@@ -58349,7 +58318,7 @@ function useBindingValue(binding) {
58349
58318
  try {
58350
58319
  return { value: handle.read(), pending: handle.pending(), error: void 0 };
58351
58320
  } catch (e3) {
58352
- console.error(`[Experiment] failed to read binding "${String(sourcePath)}":`, e3);
58321
+ console.error(`[Experiment] failed to read binding "${e3Types.pathToString(sourcePath)}":`, e3);
58353
58322
  return { value: null, pending: false, error: e3 };
58354
58323
  }
58355
58324
  }, [handle, version2]);
@@ -58365,20 +58334,25 @@ function useBindingValue(binding) {
58365
58334
  }, [handle]);
58366
58335
  return { value, mode, pending, error: error3, mutate, commit, discard };
58367
58336
  }
58337
+ function sameType(a2, b2) {
58338
+ return east.isTypeValueEqual(east.toEastTypeValue(a2), east.toEastTypeValue(b2));
58339
+ }
58340
+ function sameSignature(a2, b2) {
58341
+ const ai = a2.inputs;
58342
+ const bi = b2.inputs;
58343
+ return sameType(a2.output, b2.output) && (ai === null || bi === null ? ai === bi : ai.length === bi.length && ai.every((t4, i) => sameType(t4, bi[i])));
58344
+ }
58368
58345
  const IDLE = { call: () => {
58369
58346
  }, result: null, status: "idle", pending: false, error: null };
58370
58347
  function useFuncCall(name, inputs, output2) {
58371
58348
  const workspace = getReactiveDatasetCache().getConfig().workspace ?? "";
58372
58349
  const ready4 = !!name && !!inputs && workspace !== "";
58373
- const sigKey = React.useMemo(
58374
- () => ready4 ? JSON.stringify([inputs.map((t4) => east.toEastTypeValue(t4)), east.toEastTypeValue(output2)]) : "",
58375
- [ready4, inputs, output2]
58376
- );
58350
+ const signature = eastUiComponents.useDataStable({ inputs, output: output2 }, sameSignature);
58377
58351
  const handle = React.useMemo(() => {
58378
- if (!ready4) return null;
58379
- const handleType = east.toEastTypeValue(internal$1.FuncBindHandleType(inputs, output2));
58352
+ if (!ready4 || signature.inputs === null) return null;
58353
+ const handleType = east.toEastTypeValue(internal$1.FuncBindHandleType(signature.inputs, signature.output));
58380
58354
  return defaultFuncRuntime.buildHandle(handleType, name);
58381
- }, [ready4, name, workspace, sigKey]);
58355
+ }, [ready4, name, workspace, signature]);
58382
58356
  const channelKey = ready4 ? funcChannelKey(workspace, name) : "";
58383
58357
  const version2 = React.useSyncExternalStore(
58384
58358
  React.useCallback(
@@ -58389,7 +58363,6 @@ function useFuncCall(name, inputs, output2) {
58389
58363
  React.useCallback(() => channelKey ? defaultFuncRuntime.getKeyVersion(channelKey) : 0, [channelKey])
58390
58364
  );
58391
58365
  return React.useMemo(() => {
58392
- var _a2;
58393
58366
  if (!handle) return IDLE;
58394
58367
  let result = null;
58395
58368
  let status = "idle";
@@ -58401,10 +58374,7 @@ function useFuncCall(name, inputs, output2) {
58401
58374
  status = handle.status().type;
58402
58375
  pending = handle.pending();
58403
58376
  const err = handle.error();
58404
- if (err.type === "some") {
58405
- const v3 = err.value;
58406
- error3 = { kind: ((_a2 = v3.kind) == null ? void 0 : _a2.type) ?? "failed", message: v3.message ?? "", stdout: v3.stdout ?? "", stderr: v3.stderr ?? "" };
58407
- }
58377
+ if (err.type === "some") error3 = err.value;
58408
58378
  } catch {
58409
58379
  }
58410
58380
  return { call: (...args) => {
@@ -61022,207 +60992,14 @@ function GuidanceToggle({ on: on3, onToggle }) {
61022
60992
  }
61023
60993
  ) });
61024
60994
  }
61025
- function ChartLabel({ x: x2, y: y2, w: w2, align, size: size3, weight: weight8, color: color2, family, help, children: children2 }) {
61026
- const span = /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: `${size3}px`, fontFamily: family, fontWeight: weight8, color: color2, lineHeight: 1, whiteSpace: "nowrap" }, children: children2 });
61027
- return /* @__PURE__ */ jsxRuntime.jsx("foreignObject", { x: x2, y: y2, width: w2, height: size3 + 6, style: { overflow: "visible" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: align, fontSize: `${size3}px`, lineHeight: 1 }, children: help ? /* @__PURE__ */ jsxRuntime.jsx(Help, { id: help, children: span }) : span }) });
61028
- }
61029
- function svgText(size3, fill, family, weight8) {
61030
- return { fontSize: `${size3}px`, fill, fontFamily: family, ...weight8 !== void 0 ? { fontWeight: weight8 } : {} };
61031
- }
61032
- function useMeasuredWidth() {
61033
- const ref = React.useRef(null);
61034
- const [w2, setW] = React.useState(0);
61035
- React.useLayoutEffect(() => {
61036
- const el = ref.current;
61037
- if (!el) return;
61038
- const update2 = () => setW(el.clientWidth);
61039
- update2();
61040
- const ro = new ResizeObserver(update2);
61041
- ro.observe(el);
61042
- return () => ro.disconnect();
61043
- }, []);
61044
- return [ref, w2];
61045
- }
61046
- function useChartTheme() {
61047
- const system = react.useChakraContext();
61048
- const tok = (k2, fallback) => system.token(k2, fallback);
61049
- const tones = {
61050
- neg: tok("colors.fg.danger", "#b85a4a"),
61051
- pos: tok("colors.fg.success", "#2f7a5b"),
61052
- warn: tok("colors.fg.warning", "#b8862d"),
61053
- muted: tok("colors.fg.muted", "#6b8080"),
61054
- brand: tok("colors.brand.solid", "#3a7780")
61055
- };
61056
- return {
61057
- mono: tok("fonts.mono", '"JetBrains Mono", ui-monospace, monospace'),
61058
- body: tok("fonts.body", "system-ui, -apple-system, sans-serif"),
61059
- ink: tok("colors.fg", "#111b22"),
61060
- muted: tones.muted,
61061
- faint: tok("colors.fg.subtle", "#9bb0b0"),
61062
- rule: tok("colors.border.subtle", "#e2e8e8"),
61063
- ruleStrong: tok("colors.border.strong", "#cbd5d5"),
61064
- surface: tok("colors.bg.surface", "#ffffff"),
61065
- tone: (t4) => tones[t4] ?? tones.brand,
61066
- labelSize: 10,
61067
- titleSize: 11,
61068
- lineWidth: 1.8,
61069
- barWidth: 2.5,
61070
- dotRadius: 2.6,
61071
- scatterRadius: 3.4,
61072
- areaOpacity: 0.16
61073
- };
61074
- }
61075
- const fmt$2 = (n2) => Number.isInteger(n2) ? String(n2) : n2.toFixed(1);
61076
- const signed$1 = (n2) => (n2 > 0 ? "+" : "") + fmt$2(n2);
61077
- const niceCeil = (v3) => {
61078
- if (v3 <= 1e-9) return 0;
61079
- const mag = Math.pow(10, Math.floor(Math.log10(v3)));
61080
- const n2 = v3 / mag;
61081
- const step3 = n2 <= 1 ? 1 : n2 <= 1.5 ? 1.5 : n2 <= 2 ? 2 : n2 <= 3 ? 3 : n2 <= 4 ? 4 : n2 <= 5 ? 5 : n2 <= 6 ? 6 : n2 <= 8 ? 8 : 10;
61082
- return step3 * mag;
61083
- };
61084
- function ForestPlot({ rows, min: min4, max: max5, unit: unit2, height: height2, rowHelp }) {
61085
- const t4 = useChartTheme();
61086
- const [ref, w2] = useMeasuredWidth();
61087
- const n2 = rows.length;
61088
- const hPx = height2 ?? 26 + n2 * 38;
61089
- const padL = 124, padR = 46, padT = 20, padB = 30;
61090
- const innerW = Math.max(0, w2 - padL - padR);
61091
- const innerH = hPx - padT - padB;
61092
- const x2 = createLinearScale({ domain: [min4, max5], range: [0, innerW] });
61093
- const rowH = innerH / Math.max(1, n2);
61094
- const zeroX = Math.max(0, Math.min(innerW, x2(0)));
61095
- const frac = (v3) => max5 > min4 ? (v3 - min4) / (max5 - min4) : 0.5;
61096
- const anchorAt = (v3) => frac(v3) < 0.06 ? "start" : frac(v3) > 0.94 ? "end" : "middle";
61097
- const zf = frac(0);
61098
- const ticks2 = zf > 0.12 && zf < 0.88 ? [min4, 0, max5] : [min4, max5];
61099
- return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: padL, top: padT, children: [
61100
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: zeroX, y: -4 }, to: { x: zeroX, y: innerH }, stroke: t4.muted, strokeWidth: 1, strokeDasharray: "3 2" }),
61101
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: zeroX, y: -6, textAnchor: anchorAt(0), style: svgText(t4.labelSize, t4.muted, t4.mono), children: "no effect" }),
61102
- rows.map((r2, i) => {
61103
- const cy = rowH * i + rowH / 2;
61104
- const col = t4.tone(r2.tone);
61105
- return /* @__PURE__ */ jsxRuntime.jsxs(Group, { top: cy, children: [
61106
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: x2(r2.lo), y: 0 }, to: { x: x2(r2.hi), y: 0 }, stroke: col, strokeWidth: t4.barWidth, strokeOpacity: 0.9, strokeLinecap: "round" }),
61107
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: x2(r2.lo), y: -4 }, to: { x: x2(r2.lo), y: 4 }, stroke: col, strokeWidth: 1.5 }),
61108
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: x2(r2.hi), y: -4 }, to: { x: x2(r2.hi), y: 4 }, stroke: col, strokeWidth: 1.5 }),
61109
- /* @__PURE__ */ jsxRuntime.jsx(Circle, { cx: x2(r2.est), cy: 0, r: t4.scatterRadius, fill: col, stroke: t4.surface, strokeWidth: 1.8 }),
61110
- /* @__PURE__ */ jsxRuntime.jsx(ChartLabel, { x: -padL + 2, y: -13, w: padL - 6, align: "left", size: t4.labelSize, weight: 600, color: t4.ink, family: t4.body, ...(rowHelp == null ? void 0 : rowHelp[i]) ? { help: rowHelp[i] } : {}, children: r2.label }),
61111
- r2.note && /* @__PURE__ */ jsxRuntime.jsx("text", { x: -padL + 2, y: 9, style: svgText(9, t4.faint, t4.body), children: r2.note }),
61112
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: innerW + padR - 2, y: 4, textAnchor: "end", style: svgText(t4.titleSize, col, t4.mono, 700), children: signed$1(r2.est) })
61113
- ] }, i);
61114
- }),
61115
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: innerH }, to: { x: innerW, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61116
- ticks2.map((tk, i) => /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: Math.max(0, Math.min(innerW, x2(tk))), children: [
61117
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: innerH }, to: { x: 0, y: innerH + 4 }, stroke: t4.ruleStrong, strokeWidth: 1 }),
61118
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: 0, y: innerH + 14, textAnchor: anchorAt(tk), style: svgText(t4.labelSize, t4.muted, t4.mono), children: signed$1(tk) })
61119
- ] }, `t${i}`)),
61120
- unit2 && /* @__PURE__ */ jsxRuntime.jsx("text", { x: innerW / 2, y: innerH + 26, textAnchor: "middle", style: svgText(t4.labelSize, t4.muted, t4.mono), children: unit2 })
61121
- ] }) }) });
61122
- }
61123
- function AreaRange({ lo: lo2, mid, hi, xTicks = [], yTicks = [], zero: zero2, tone: toneName, marks = [], height: height2, yFormat = "signed" }) {
61124
- const t4 = useChartTheme();
61125
- const [ref, w2] = useMeasuredWidth();
61126
- const hPx = height2 ?? 100;
61127
- const col = t4.tone(toneName ?? "brand");
61128
- const padL = yTicks.length ? 52 : 6;
61129
- const padR = 12;
61130
- const padT = marks.length ? 22 : 8;
61131
- const padB = xTicks.length ? 22 : 12;
61132
- const innerW = Math.max(0, w2 - padL - padR);
61133
- const innerH = hPx - padT - padB;
61134
- const xScale = createLinearScale({ domain: [0, Math.max(1, mid.length - 1)], range: [0, innerW] });
61135
- const fin = (x2, fallback) => typeof x2 === "number" && Number.isFinite(x2) ? x2 : fallback;
61136
- const data4 = mid.map((m2, i) => {
61137
- const mm = fin(m2, 0);
61138
- return { i, lo: fin(lo2[i], mm), hi: fin(hi[i], mm), mid: mm };
61139
- });
61140
- const dataMin = Math.min(...data4.map((d2) => d2.lo), zero2 ?? Infinity);
61141
- const dataMax = Math.max(...data4.map((d2) => d2.hi), zero2 ?? -Infinity);
61142
- const yHiN = niceCeil(Math.max(dataMax, 0));
61143
- const yLoN = dataMin < -0.08 * yHiN ? -niceCeil(-dataMin) : 0;
61144
- const yScale = createLinearScale({ domain: [yLoN, yHiN], range: [innerH, 0] });
61145
- const yfmt = (v3) => yFormat === "percent" ? `${Math.round(v3)}%` : signed$1(v3);
61146
- const yLabels = [yfmt(yHiN), yfmt((yHiN + yLoN) / 2), yfmt(yLoN)];
61147
- return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: padL, top: padT, children: [
61148
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: 0 }, to: { x: 0, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61149
- yTicks.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
61150
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: -8, y: 10, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[0] }),
61151
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: -8, y: innerH / 2 + 3, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[1] }),
61152
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: -8, y: innerH - 1, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[2] })
61153
- ] }),
61154
- zero2 != null && /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: yScale(zero2) }, to: { x: innerW, y: yScale(zero2) }, stroke: t4.muted, strokeWidth: 1, strokeDasharray: "3 2" }),
61155
- /* @__PURE__ */ jsxRuntime.jsx(Area, { data: data4, x: (d2) => xScale(d2.i), y0: (d2) => yScale(d2.lo), y1: (d2) => yScale(d2.hi), curve: monotoneX, fill: col, fillOpacity: t4.areaOpacity, stroke: "transparent" }),
61156
- /* @__PURE__ */ jsxRuntime.jsx(LinePath, { data: data4, x: (d2) => xScale(d2.i), y: (d2) => yScale(d2.mid), curve: monotoneX, stroke: col, strokeWidth: t4.lineWidth }),
61157
- marks.map((m2, i) => {
61158
- const mc = t4.tone(m2.tone);
61159
- const dotY = yScale(fin(mid[m2.at], 0));
61160
- const labY = Math.max(9, dotY - 9);
61161
- const atEnd = m2.at >= mid.length - 2;
61162
- const atStart = m2.at <= 1;
61163
- const align = atEnd ? "right" : atStart ? "left" : "center";
61164
- const labW = m2.label.length * 6.5 + 8;
61165
- const labX = atEnd ? -labW - 5 : atStart ? 5 : -labW / 2;
61166
- return /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: xScale(m2.at), children: [
61167
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: -2 }, to: { x: 0, y: innerH }, stroke: mc, strokeWidth: 1, strokeDasharray: "2 3" }),
61168
- /* @__PURE__ */ jsxRuntime.jsx(Circle, { cx: 0, cy: dotY, r: t4.dotRadius, fill: mc, stroke: t4.surface, strokeWidth: 1.5 }),
61169
- /* @__PURE__ */ jsxRuntime.jsx(ChartLabel, { x: labX, y: labY - 11, w: labW, align, size: t4.labelSize, weight: 500, color: mc, family: t4.body, ...m2.help ? { help: m2.help } : {}, children: m2.label })
61170
- ] }, `mk${i}`);
61171
- }),
61172
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: innerH }, to: { x: innerW, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61173
- xTicks.map((tk, i) => {
61174
- const word = Number.isNaN(Number(tk));
61175
- return /* @__PURE__ */ jsxRuntime.jsx("text", { x: innerW * i / Math.max(1, xTicks.length - 1), y: innerH + 14, textAnchor: i === 0 ? "start" : i === xTicks.length - 1 ? "end" : "middle", style: svgText(word ? 9 : t4.labelSize, word ? t4.faint : t4.muted, word ? t4.body : t4.mono), children: tk }, `x${i}`);
61176
- })
61177
- ] }) }) });
61178
- }
61179
- function OverlapHistogram({ treated, control, domain = [0, 1], supportLabel, positivityOk, height: height2 }) {
61180
- const t4 = useChartTheme();
61181
- const [ref, w2] = useMeasuredWidth();
61182
- const hPx = height2 ?? 150;
61183
- const padL = 8, padR = 8, padT = 16, padB = 26;
61184
- const innerW = Math.max(0, w2 - padL - padR);
61185
- const innerH = hPx - padT - padB;
61186
- const centerY = innerH / 2;
61187
- const halfH = centerY - 4;
61188
- const bins = Math.max(treated.length, control.length);
61189
- const x2 = createLinearScale({ domain, range: [0, innerW] });
61190
- const span = domain[1] - domain[0];
61191
- const binW = bins > 0 ? innerW / bins : innerW;
61192
- const barW = Math.max(1, binW * 0.78);
61193
- const maxVal = Math.max(1e-9, ...treated, ...control);
61194
- const tCol = t4.tone("pos");
61195
- const cCol = t4.tone("muted");
61196
- const ticks2 = [domain[0], (domain[0] + domain[1]) / 2, domain[1]];
61197
- const cx2 = (i) => x2(domain[0] + (i + 0.5) / bins * span);
61198
- return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: padL, top: padT, children: [
61199
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: 0, y: -4, style: svgText(9, t4.faint, t4.body), children: "treated ↑" }),
61200
- supportLabel && /* @__PURE__ */ jsxRuntime.jsx("text", { x: innerW, y: -4, textAnchor: "end", style: svgText(t4.labelSize, positivityOk ? t4.tone("pos") : t4.tone("warn"), t4.mono, 600), children: supportLabel }),
61201
- Array.from({ length: bins }, (_2, i) => {
61202
- const ht = Number(treated[i] ?? 0) / maxVal * halfH;
61203
- const hc = Number(control[i] ?? 0) / maxVal * halfH;
61204
- const left = cx2(i) - barW / 2;
61205
- return /* @__PURE__ */ jsxRuntime.jsxs(Group, { children: [
61206
- ht > 0 && /* @__PURE__ */ jsxRuntime.jsx("rect", { x: left, y: centerY - ht, width: barW, height: ht, fill: tCol, fillOpacity: 0.85, rx: 0.5 }),
61207
- hc > 0 && /* @__PURE__ */ jsxRuntime.jsx("rect", { x: left, y: centerY, width: barW, height: hc, fill: cCol, fillOpacity: 0.6, rx: 0.5 })
61208
- ] }, i);
61209
- }),
61210
- /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: centerY }, to: { x: innerW, y: centerY }, stroke: t4.ruleStrong, strokeWidth: 1 }),
61211
- /* @__PURE__ */ jsxRuntime.jsx("text", { x: 0, y: innerH + 4, style: svgText(9, t4.faint, t4.body), children: "untreated ↓" }),
61212
- ticks2.map((tk, i) => /* @__PURE__ */ jsxRuntime.jsx("text", { x: x2(tk), y: innerH + 16, textAnchor: i === 0 ? "start" : i === ticks2.length - 1 ? "end" : "middle", style: svgText(t4.labelSize, t4.muted, t4.mono), children: fmt$2(tk) }, `x${i}`))
61213
- ] }) }) });
61214
- }
61215
60995
  const arr = (v3) => v3 ? Array.from(v3, Number) : [];
61216
60996
  const arrI = (v3) => v3 ? Array.from(v3, Number) : [];
61217
- const fmt$1 = (x2) => {
61218
- const r2 = Number.isInteger(x2) ? String(x2) : x2.toFixed(1);
61219
- return r2 === "-0.0" ? "0.0" : r2;
61220
- };
61221
- const signed = (x2) => {
61222
- const f2 = fmt$1(x2);
61223
- return f2 === "0" || f2 === "0.0" || f2.startsWith("-") ? f2 : `+${f2}`;
61224
- };
60997
+ const ONE_DECIMAL = east.variant("number", { minimumFractionDigits: east.some(1n), maximumFractionDigits: east.some(1n), signDisplay: east.none });
60998
+ const formatOf = (x2) => Number.isInteger(x2) ? void 0 : ONE_DECIMAL;
60999
+ const fmt$1 = (x2, words) => words.value(Math.abs(x2) < 0.05 ? 0 : x2, formatOf(x2));
61000
+ const signed = (x2, words) => words.value(x2, formatOf(x2), true);
61225
61001
  const clamp01 = (x2) => x2 < 0 ? 0 : x2 > 1 ? 1 : x2;
61002
+ const compareFloats = east.compareFor(east.FloatType);
61226
61003
  function band(absStd) {
61227
61004
  if (absStd >= 0.66) return { level: "large gap", tone: "neg" };
61228
61005
  if (absStd >= 0.33) return { level: "some", tone: "warn" };
@@ -61272,7 +61049,7 @@ function treatmentKind(cols, treatment) {
61272
61049
  return "value";
61273
61050
  }
61274
61051
  }
61275
- function deriveSpec(config2, cols, result, meta3, dataLen, subject) {
61052
+ function deriveSpec(config2, cols, result, meta3, dataLen, subject, words) {
61276
61053
  const outUnit = unitOf(meta3, config2.outcome);
61277
61054
  const balByCol = /* @__PURE__ */ new Map();
61278
61055
  for (const b2 of (result == null ? void 0 : result.balance) ?? []) {
@@ -61310,24 +61087,24 @@ function deriveSpec(config2, cols, result, meta3, dataLen, subject) {
61310
61087
  // n_total belongs to the Answer-tab counts strip; labelling the header
61311
61088
  // with it desyncs from the data after a population edit (and reads
61312
61089
  // wrong whenever the two legitimately differ).
61313
- dataLabel: `${dataLen} ${subject.many}`
61090
+ dataLabel: `${words.number(dataLen)} ${subject.many}`
61314
61091
  };
61315
61092
  }
61316
- function balanceDisplay(b2, categorical) {
61093
+ function balanceDisplay(b2, categorical, words) {
61317
61094
  const isProp = categorical.has(b2.base_column) && b2.treated_mean >= 0 && b2.treated_mean <= 1 && b2.control_mean >= 0 && b2.control_mean <= 1;
61318
- return isProp ? `${Math.round(b2.treated_mean * 100)}% vs ${Math.round(b2.control_mean * 100)}%` : `${b2.treated_mean.toFixed(1)} vs ${b2.control_mean.toFixed(1)}`;
61095
+ return isProp ? `${words.percent(b2.treated_mean)} vs ${words.percent(b2.control_mean)}` : `${words.value(b2.treated_mean, ONE_DECIMAL)} vs ${words.value(b2.control_mean, ONE_DECIMAL)}`;
61319
61096
  }
61320
- function deriveAnswer(config2, result, adj, meta3) {
61097
+ function deriveAnswer(config2, result, adj, meta3, words) {
61321
61098
  const ci = eastUiComponents.getSomeorUndefined(adj.ci);
61322
61099
  const nci = eastUiComponents.getSomeorUndefined(result.naive_ci);
61323
61100
  const categorical = new Set(eastUiComponents.getSomeorUndefined(config2.categorical) ?? []);
61324
- const balance = [...result.balance].sort((a2, b2) => Math.abs(b2.std_diff) - Math.abs(a2.std_diff)).map((b2) => ({
61101
+ const balance = [...result.balance].sort((a2, b2) => compareFloats(Math.abs(b2.std_diff), Math.abs(a2.std_diff))).map((b2) => ({
61325
61102
  // One-hot rows are `col=level` — label the BASE confounder, keep the level.
61326
61103
  col: b2.column,
61327
61104
  label: b2.column === b2.base_column ? labelOf(meta3, b2.base_column) : `${labelOf(meta3, b2.base_column)}${b2.column.startsWith(b2.base_column) ? b2.column.slice(b2.base_column.length) : ` (${b2.column})`}`,
61328
61105
  treated: b2.treated_mean,
61329
61106
  control: b2.control_mean,
61330
- display: balanceDisplay(b2, categorical),
61107
+ display: balanceDisplay(b2, categorical, words),
61331
61108
  frac: clamp01(Math.abs(b2.std_diff)),
61332
61109
  tone: band(Math.abs(b2.std_diff)).tone
61333
61110
  }));
@@ -61358,12 +61135,12 @@ function deriveAnswer(config2, result, adj, meta3) {
61358
61135
  balance
61359
61136
  };
61360
61137
  }
61361
- function deriveNarrative(result, a2, refute, higherBetter, subject) {
61138
+ function deriveNarrative(result, a2, refute, higherBetter, subject, words) {
61362
61139
  if (a2 === null) return null;
61363
61140
  const unit2 = a2.unit ? ` ${a2.unit}` : "";
61364
61141
  const dirUp = a2.effect > 0;
61365
61142
  const verb = higherBetter === void 0 ? dirUp ? "raises" : "lowers" : dirUp === higherBetter ? "improves" : "worsens";
61366
- const range = ` (likely between ${signed(a2.lo)} and ${signed(a2.hi)})`;
61143
+ const range = ` (likely between ${signed(a2.lo, words)} and ${signed(a2.hi, words)})`;
61367
61144
  const passed = (refute == null ? void 0 : refute.checks.filter((c2) => c2.passed).length) ?? 0;
61368
61145
  const total = (refute == null ? void 0 : refute.checks.length) ?? 0;
61369
61146
  const trustClause = total === 0 ? "" : passed === total ? ` It held up against all ${total} ways we tried to break it.` : ` It passed ${passed} of ${total} stress tests — see “Can we trust it?”.`;
@@ -61374,13 +61151,13 @@ function deriveNarrative(result, a2, refute, higherBetter, subject) {
61374
61151
  segments: [
61375
61152
  { text: "Yes — ", strong: true },
61376
61153
  { text: `${a2.treatment} genuinely ${verb} ${a2.outcome}: about ` },
61377
- { text: `${signed(a2.effect)}${unit2}`, strong: true },
61154
+ { text: `${signed(a2.effect, words)}${unit2}`, strong: true },
61378
61155
  { text: ` per ${subject.one}${range}.${trustClause}` }
61379
61156
  ]
61380
61157
  };
61381
61158
  case "modest": {
61382
61159
  const tags = new Set(result.verdict_reasons.map((v3) => v3.type));
61383
- const why = tags.has("not_material") ? ` — the change (${signed(a2.effect)}${unit2}) is smaller than what would matter here (±${fmt$1(result.materiality_threshold)}${unit2}).` : tags.has("ci_spans_zero") ? ` — the likely range (${signed(a2.lo)} to ${signed(a2.hi)}) includes zero.` : tags.has("thin_support") ? " — too few treated and untreated look-alikes overlap to be confident." : tags.has("low_robustness") ? " — a fairly weak hidden factor could overturn it." : a2.lo <= 0 && a2.hi >= 0 ? ` — the likely range (${signed(a2.lo)} to ${signed(a2.hi)}) includes zero.` : ".";
61160
+ const why = tags.has("not_material") ? ` — the change (${signed(a2.effect, words)}${unit2}) is smaller than what would matter here (±${fmt$1(result.materiality_threshold, words)}${unit2}).` : tags.has("ci_spans_zero") ? ` — the likely range (${signed(a2.lo, words)} to ${signed(a2.hi, words)}) includes zero.` : tags.has("thin_support") ? " — too few treated and untreated look-alikes overlap to be confident." : tags.has("low_robustness") ? " — a fairly weak hidden factor could overturn it." : a2.lo <= 0 && a2.hi >= 0 ? ` — the likely range (${signed(a2.lo, words)} to ${signed(a2.hi, words)}) includes zero.` : ".";
61384
61161
  return {
61385
61162
  tone: "warn",
61386
61163
  segments: [
@@ -61395,14 +61172,14 @@ function deriveNarrative(result, a2, refute, higherBetter, subject) {
61395
61172
  tone: "warn",
61396
61173
  segments: [
61397
61174
  { text: "Don’t act on this yet — ", strong: true },
61398
- { text: `we got a number (${signed(a2.effect)}${unit2}), but a stress test failed: something we didn’t adjust for may still be driving it.` }
61175
+ { text: `we got a number (${signed(a2.effect, words)}${unit2}), but a stress test failed: something we didn’t adjust for may still be driving it.` }
61399
61176
  ]
61400
61177
  };
61401
61178
  default:
61402
61179
  return null;
61403
61180
  }
61404
61181
  }
61405
- function deriveRefusal(config2, result, meta3, subject) {
61182
+ function deriveRefusal(config2, result, meta3, subject, words) {
61406
61183
  const nT = Number(result.n_treated), nC = Number(result.n_control), nTot = Number(result.n_total);
61407
61184
  const treatment = labelOf(meta3, config2.treatment);
61408
61185
  if (result.verdict.type === "not_estimable") {
@@ -61412,22 +61189,22 @@ function deriveRefusal(config2, result, meta3, subject) {
61412
61189
  title: `Can’t estimate the effect of ${treatment}`,
61413
61190
  body: reason,
61414
61191
  evidence: [
61415
- { label: "treated", value: String(nT) },
61416
- { label: "untreated", value: String(nC) },
61417
- { label: subject.many, value: String(nTot) }
61192
+ { label: "treated", value: words.number(nT) },
61193
+ { label: "untreated", value: words.number(nC) },
61194
+ { label: subject.many, value: words.number(nTot) }
61418
61195
  ]
61419
61196
  };
61420
61197
  }
61421
61198
  if (result.verdict.type === "non_identifiable_positivity") {
61422
- const pct = Math.round(result.overlap.common_support_frac * 100);
61199
+ const pct = words.percent(result.overlap.common_support_frac);
61423
61200
  return {
61424
61201
  kind: "positivity",
61425
61202
  title: "No like-for-like comparison exists",
61426
- body: `The treated and untreated groups barely overlap on the confounders — only ${pct}% sit in a range where both occur — so there is no fair comparison to adjust toward.`,
61203
+ body: `The treated and untreated groups barely overlap on the confounders — only ${pct} sit in a range where both occur — so there is no fair comparison to adjust toward.`,
61427
61204
  evidence: [
61428
- { label: "common support", value: `${pct}%` },
61429
- { label: "treated", value: String(nT) },
61430
- { label: "untreated", value: String(nC) }
61205
+ { label: "common support", value: pct },
61206
+ { label: "treated", value: words.number(nT) },
61207
+ { label: "untreated", value: words.number(nC) }
61431
61208
  ]
61432
61209
  };
61433
61210
  }
@@ -61436,20 +61213,19 @@ function deriveRefusal(config2, result, meta3, subject) {
61436
61213
  title: `Can’t estimate the effect of ${treatment}`,
61437
61214
  body: "The engine could not produce a like-for-like estimate for this configuration.",
61438
61215
  evidence: [
61439
- { label: "treated", value: String(nT) },
61440
- { label: "untreated", value: String(nC) },
61441
- { label: subject.many, value: String(nTot) }
61216
+ { label: "treated", value: words.number(nT) },
61217
+ { label: "untreated", value: words.number(nC) },
61218
+ { label: subject.many, value: words.number(nTot) }
61442
61219
  ]
61443
61220
  };
61444
61221
  }
61445
- function deriveOverlap(o2) {
61446
- const pct = Math.round(o2.common_support_frac * 100);
61222
+ function deriveOverlap(o2, words) {
61447
61223
  return {
61448
61224
  treated: arr(o2.treated_propensity),
61449
61225
  control: arr(o2.control_propensity),
61450
61226
  commonSupportFrac: o2.common_support_frac,
61451
61227
  positivityOk: o2.positivity_ok,
61452
- supportLabel: `${pct}% common support`
61228
+ supportLabel: `${words.percent(o2.common_support_frac)} common support`
61453
61229
  };
61454
61230
  }
61455
61231
  function zeroCrossing(xs, ys) {
@@ -61462,7 +61238,7 @@ function zeroCrossing(xs, ys) {
61462
61238
  }
61463
61239
  return null;
61464
61240
  }
61465
- function deriveRefute(r2, adj, meta3) {
61241
+ function deriveRefute(r2, adj, meta3, words) {
61466
61242
  const checks = [];
61467
61243
  const est = (adj == null ? void 0 : adj.effect) ?? 0;
61468
61244
  const placeboEffect = eastUiComponents.getSomeorUndefined(r2.placebo_effect);
@@ -61475,7 +61251,7 @@ function deriveRefute(r2, adj, meta3) {
61475
61251
  desc: "Shuffle which rows were treated; a real effect should collapse to zero.",
61476
61252
  // Speak the outcome, not the statistic: on fake labels the effect
61477
61253
  // should VANISH — say whether it did.
61478
- value: placeboEffect !== void 0 ? passed ? `vanished (${signed(placeboEffect)})` : `didn’t vanish (${signed(placeboEffect)})` : passed ? "vanished" : "didn’t vanish",
61254
+ value: placeboEffect !== void 0 ? passed ? `vanished (${signed(placeboEffect, words)})` : `didn’t vanish (${signed(placeboEffect, words)})` : passed ? "vanished" : "didn’t vanish",
61479
61255
  passed,
61480
61256
  tip: east.some("Randomly re-label which rows were treated. A genuine effect should vanish."),
61481
61257
  help: "check_shuffle"
@@ -61489,7 +61265,7 @@ function deriveRefute(r2, adj, meta3) {
61489
61265
  name: "Drop-some test",
61490
61266
  short: "drop-some",
61491
61267
  desc: "Re-estimate on random subsamples; a trustworthy effect stays put.",
61492
- value: passed ? `stayed at ${signed(ds)} ± ${fmt$1(dstd)}` : `moved to ${signed(ds)} ± ${fmt$1(dstd)}`,
61268
+ value: passed ? `stayed at ${signed(ds, words)} ± ${fmt$1(dstd, words)}` : `moved to ${signed(ds, words)} ± ${fmt$1(dstd, words)}`,
61493
61269
  passed,
61494
61270
  tip: east.none,
61495
61271
  help: "check_dropsome"
@@ -61509,14 +61285,14 @@ function deriveRefute(r2, adj, meta3) {
61509
61285
  }
61510
61286
  const sens = eastUiComponents.getSomeorUndefined(r2.sensitivity);
61511
61287
  const evalue = eastUiComponents.getSomeorUndefined(r2.robustness_value);
61512
- const benchmarks = sens ? [...sens.benchmarks].sort((a2, b2) => b2.strength - a2.strength) : [];
61288
+ const benchmarks = sens ? [...sens.benchmarks].sort((a2, b2) => compareFloats(b2.strength, a2.strength)) : [];
61513
61289
  if (sens !== void 0 || evalue !== void 0) {
61514
61290
  const strengths = sens ? arr(sens.strengths) : [];
61515
61291
  const effects = sens ? arr(sens.effects) : [];
61516
61292
  const tip = sens ? zeroCrossing(strengths, effects) : null;
61517
61293
  const strongest = benchmarks[0];
61518
- const value = tip !== null ? strongest !== void 0 ? tip > strongest.strength ? `flips only beyond ${labelOf(meta3, strongest.column)}` : `a cause weaker than ${labelOf(meta3, strongest.column)} could flip it` : `would flip at ${fmt$1(tip)}` : evalue !== void 0 ? `holds (E-value ${fmt$1(evalue)})` : "holds throughout";
61519
- const scaleNote = strongest !== void 0 ? ` For scale, your strongest known factor (${labelOf(meta3, strongest.column)}) sits at ${fmt$1(strongest.strength)} on this axis.` : "";
61294
+ const value = tip !== null ? strongest !== void 0 ? tip > strongest.strength ? `flips only beyond ${labelOf(meta3, strongest.column)}` : `a cause weaker than ${labelOf(meta3, strongest.column)} could flip it` : `would flip at ${fmt$1(tip, words)}` : evalue !== void 0 ? `holds (E-value ${fmt$1(evalue, words)})` : "holds throughout";
61295
+ const scaleNote = strongest !== void 0 ? ` For scale, your strongest known factor (${labelOf(meta3, strongest.column)}) sits at ${fmt$1(strongest.strength, words)} on this axis.` : "";
61520
61296
  checks.push({
61521
61297
  name: "Hidden cause",
61522
61298
  short: "hidden cause",
@@ -61552,12 +61328,12 @@ function deriveRefute(r2, adj, meta3) {
61552
61328
  const at = atOf(b2.strength);
61553
61329
  return at === null ? [] : [{ at, label: `as strong as ${labelOf(meta3, b2.column)}`, tone: "muted", help: "sensitivity" }];
61554
61330
  });
61555
- sensVM = { lo: lo2, mid, hi, xTicks: ["none", "", "stronger"], yTicks: [fmt$1(yLo), fmt$1((yLo + yHi) / 2), fmt$1(yHi)], marks };
61331
+ sensVM = { lo: lo2, mid, hi, xTicks: ["none", "", "stronger"], yTicks: [fmt$1(yLo, words), fmt$1((yLo + yHi) / 2, words), fmt$1(yHi, words)], marks };
61556
61332
  }
61557
61333
  }
61558
61334
  return { checks, sens: sensVM };
61559
61335
  }
61560
- function deriveDose(dose, config2, meta3) {
61336
+ function deriveDose(dose, config2, meta3, words) {
61561
61337
  const grid = arr(dose.grid);
61562
61338
  const mid = arr(dose.effect);
61563
61339
  const lo2 = eastUiComponents.getSomeorUndefined(dose.lower) ? arr(eastUiComponents.getSomeorUndefined(dose.lower)) : mid.slice();
@@ -61575,17 +61351,17 @@ function deriveDose(dose, config2, meta3) {
61575
61351
  }
61576
61352
  }
61577
61353
  const xi = grid.length ? [0, Math.floor(grid.length / 2), grid.length - 1] : [];
61578
- const xTicks = xi.map((i) => fmt$1(grid[i]));
61354
+ const xTicks = xi.map((i) => fmt$1(grid[i], words));
61579
61355
  const yLo = Math.min(0, ...lo2), yHi = Math.max(...hi, 0);
61580
- const yTicks = [fmt$1(yLo), fmt$1((yLo + yHi) / 2), fmt$1(yHi)];
61356
+ const yTicks = [fmt$1(yLo, words), fmt$1((yLo + yHi) / 2, words), fmt$1(yHi, words)];
61581
61357
  const margSteps = marg.slice(1);
61582
61358
  let lastStep = margSteps.length - 1;
61583
61359
  while (lastStep > 0 && Math.abs(margSteps[lastStep]) < 0.12 * maxMarg) lastStep--;
61584
- const marginal = margSteps.slice(0, lastStep + 1).map((v3, i) => ({ label: `${fmt$1(grid[i + 1])}`, value: v3, frac: clamp01(Math.abs(v3) / maxMarg) }));
61360
+ const marginal = margSteps.slice(0, lastStep + 1).map((v3, i) => ({ label: fmt$1(grid[i + 1], words), value: v3, frac: clamp01(Math.abs(v3) / maxMarg) }));
61585
61361
  const stepFrom = here < sweet ? here : Math.max(0, sweet - 1);
61586
61362
  const gainToSweet = (mid[sweet] ?? 0) - (mid[stepFrom] ?? 0);
61587
61363
  const nextGain = sweet + 1 < mid.length ? mid[sweet + 1] - mid[sweet] : 0;
61588
- const tradeoff = `Going from ${fmt$1(grid[stepFrom] ?? 0)} to ${fmt$1(grid[sweet] ?? 0)} adds ${signed(gainToSweet)}; the next step adds only ${signed(nextGain)}.`;
61364
+ const tradeoff = `Going from ${fmt$1(grid[stepFrom] ?? 0, words)} to ${fmt$1(grid[sweet] ?? 0, words)} adds ${signed(gainToSweet, words)}; the next step adds only ${signed(nextGain, words)}.`;
61589
61365
  const marks = [];
61590
61366
  if (sizes.length) marks.push({ at: here, label: "you are here", tone: "muted", help: "dose_here" });
61591
61367
  marks.push({ at: sweet, label: "sweet spot", tone: "pos", help: "dose_sweet" });
@@ -61602,7 +61378,7 @@ function deriveDose(dose, config2, meta3) {
61602
61378
  marks,
61603
61379
  // Name the feature in the recommendation — a bare "≈ 5.5" doesn't say
61604
61380
  // 5.5 of WHAT.
61605
- recoLabel: `aim for ${featureLabel} ≈ ${fmt$1(grid[sweet] ?? 0)}${featureUnit ? " " + featureUnit : ""}`,
61381
+ recoLabel: `aim for ${featureLabel} ≈ ${fmt$1(grid[sweet] ?? 0, words)}${featureUnit ? " " + featureUnit : ""}`,
61606
61382
  recoEffect: mid[sweet] ?? 0,
61607
61383
  recoLo: lo2[sweet] ?? 0,
61608
61384
  recoHi: hi[sweet] ?? 0,
@@ -61611,11 +61387,11 @@ function deriveDose(dose, config2, meta3) {
61611
61387
  framing: `A different question from the headline: how ${outcomeLabel} responds as ${featureLabel} itself moves.`
61612
61388
  };
61613
61389
  }
61614
- function relTime(d2, now2) {
61390
+ function relTime(d2, now2, words) {
61615
61391
  const days = Math.floor((now2.getTime() - d2.getTime()) / 864e5);
61616
61392
  if (days <= 0) return "today";
61617
61393
  if (days === 1) return "yesterday";
61618
- if (days < 7) return d2.toLocaleDateString(void 0, { weekday: "short" });
61394
+ if (days < 7) return words.weekday(d2);
61619
61395
  return "last wk";
61620
61396
  }
61621
61397
  const VERDICT_WORD = {
@@ -61625,43 +61401,43 @@ const VERDICT_WORD = {
61625
61401
  non_identifiable_positivity: "no overlap",
61626
61402
  not_estimable: "n/a"
61627
61403
  };
61628
- function deriveJournalRow(row, now2, meta3) {
61404
+ function deriveJournalRow(row, now2, meta3, words) {
61629
61405
  const adj = eastUiComponents.getSomeorUndefined(row.adjusted);
61630
61406
  return {
61631
61407
  treatment: labelOf(meta3, row.config.treatment),
61632
61408
  outcome: labelOf(meta3, row.config.outcome),
61633
61409
  confounders: row.config.common_causes.map((c2) => labelOf(meta3, c2)).join(", "),
61634
- effect: adj !== void 0 ? signed(adj) : signed(row.naive),
61410
+ effect: adj !== void 0 ? signed(adj, words) : signed(row.naive, words),
61635
61411
  verdict: VERDICT_WORD[row.verdict.type],
61636
61412
  verdictTone: VERDICT_TONE[row.verdict.type],
61637
61413
  who: row.committed_by,
61638
- when: relTime(row.committed_at, now2),
61414
+ when: relTime(row.committed_at, now2, words),
61639
61415
  // The originating preset id (resolved to a label by the surface); `none` for a
61640
61416
  // free-form / pre-presets row.
61641
61417
  preset: row.preset
61642
61418
  };
61643
61419
  }
61644
- function deriveView(config2, ranConfig, cols, result, journal, meta3, dataLen, now2, subject = { one: "record", many: "records" }) {
61420
+ function deriveView(config2, ranConfig, cols, result, journal, meta3, dataLen, now2, subject = { one: "record", many: "records" }, words = eastUiComponents.formatters()) {
61645
61421
  var _a2;
61646
61422
  const adj = result ? eastUiComponents.getSomeorUndefined(result.adjusted) : void 0;
61647
61423
  const refutation = result ? eastUiComponents.getSomeorUndefined(result.refutation) : void 0;
61648
61424
  const doseR = result ? eastUiComponents.getSomeorUndefined(result.dose_response) : void 0;
61649
- const answer = result && adj ? deriveAnswer(ranConfig, result, adj, meta3) : null;
61650
- const refute = refutation ? deriveRefute(refutation, adj, meta3) : null;
61425
+ const answer = result && adj ? deriveAnswer(ranConfig, result, adj, meta3, words) : null;
61426
+ const refute = refutation ? deriveRefute(refutation, adj, meta3, words) : null;
61651
61427
  const higherBetter = eastUiComponents.getSomeorUndefined((_a2 = colMeta(meta3, ranConfig.outcome)) == null ? void 0 : _a2.higherIsBetter);
61652
61428
  return {
61653
61429
  // The set-up rail reflects the LIVE config (the editor); the result deck
61654
61430
  // reflects RANCONFIG — the config that produced `result` — so the result
61655
61431
  // strings never drift ahead of the numbers on a live picker edit.
61656
- spec: deriveSpec(config2, cols, result, meta3, dataLen, subject),
61432
+ spec: deriveSpec(config2, cols, result, meta3, dataLen, subject, words),
61657
61433
  verdict: result ? deriveVerdict(result.verdict) : null,
61658
- narrative: result ? deriveNarrative(result, answer, refute, higherBetter, subject) : null,
61434
+ narrative: result ? deriveNarrative(result, answer, refute, higherBetter, subject, words) : null,
61659
61435
  answer,
61660
- refusal: result && !adj ? deriveRefusal(ranConfig, result, meta3, subject) : null,
61661
- overlap: result ? deriveOverlap(result.overlap) : null,
61436
+ refusal: result && !adj ? deriveRefusal(ranConfig, result, meta3, subject, words) : null,
61437
+ overlap: result ? deriveOverlap(result.overlap, words) : null,
61662
61438
  refute,
61663
- dose: doseR && doseR.effect.length ? deriveDose(doseR, ranConfig, meta3) : null,
61664
- journal: journal ? journal.map((r2) => deriveJournalRow(r2, now2, meta3)) : null
61439
+ dose: doseR && doseR.effect.length ? deriveDose(doseR, ranConfig, meta3, words) : null,
61440
+ journal: journal ? journal.map((r2) => deriveJournalRow(r2, now2, meta3, words)) : null
61665
61441
  };
61666
61442
  }
61667
61443
  const DESIGN_HEADLINE = {
@@ -61680,7 +61456,7 @@ function deriveDesignOption(o2) {
61680
61456
  treatedShare: o2.treated_share
61681
61457
  };
61682
61458
  }
61683
- function deriveDesign(d2, result, ranConfig, meta3) {
61459
+ function deriveDesign(d2, result, ranConfig, meta3, words = eastUiComponents.formatters()) {
61684
61460
  const basis = d2.basis.type;
61685
61461
  const outcome = ranConfig.outcome;
61686
61462
  const unit2 = unitOf(meta3, outcome);
@@ -61712,9 +61488,9 @@ function deriveDesign(d2, result, ranConfig, meta3) {
61712
61488
  }
61713
61489
  return bi;
61714
61490
  };
61715
- const xTicks = len ? [String(ns[0]), String(ns[Math.floor((len - 1) / 2)]), String(ns[len - 1])] : [];
61491
+ const xTicks = len ? [words.number(ns[0]), words.number(ns[Math.floor((len - 1) / 2)]), words.number(ns[len - 1])] : [];
61716
61492
  const marks = [];
61717
- if (len) marks.push({ at: nearest(primary.nTotal), label: `target ${(d2.target_power * 100).toFixed(0)}%`, tone: "pos", help: "validate_power" });
61493
+ if (len) marks.push({ at: nearest(primary.nTotal), label: `target ${words.percent(d2.target_power)}`, tone: "pos", help: "validate_power" });
61718
61494
  const cp = eastUiComponents.getSomeorUndefined(d2.current_power);
61719
61495
  if (cp !== void 0 && len) {
61720
61496
  const curN = result ? Number(result.n_total) : 0;
@@ -61722,7 +61498,7 @@ function deriveDesign(d2, result, ranConfig, meta3) {
61722
61498
  const offScale = curN >= (ns[len - 1] ?? 0);
61723
61499
  marks.push({
61724
61500
  at: offScale ? len - 1 : nearest(curN),
61725
- label: offScale ? `you’re here · ${(cp * 100).toFixed(0)}% (off-scale)` : `you’re here ${(cp * 100).toFixed(0)}%`,
61501
+ label: offScale ? `you’re here · ${words.percent(cp)} (off-scale)` : `you’re here ${words.percent(cp)}`,
61726
61502
  tone: "muted",
61727
61503
  help: "validate_power"
61728
61504
  });
@@ -61736,13 +61512,204 @@ function deriveDesign(d2, result, ranConfig, meta3) {
61736
61512
  alternates: options2.slice(1),
61737
61513
  matchOn,
61738
61514
  curve: { mid: powers.slice(0, len).map((p2) => p2 * 100), xTicks, marks },
61739
- targetLabel: `${signed(d2.target_effect)}${unit2 ? ` ${unit2}` : ""}`,
61740
- targetPctLabel: `${(d2.target_power * 100).toFixed(0)}%`,
61515
+ targetLabel: `${signed(d2.target_effect, words)}${unit2 ? ` ${unit2}` : ""}`,
61516
+ targetPctLabel: words.percent(d2.target_power),
61741
61517
  holdback: basis === "create_control",
61742
61518
  showOverlap: basis === "restrict_to_overlap",
61743
61519
  faint
61744
61520
  };
61745
61521
  }
61522
+ function ChartLabel({ x: x2, y: y2, w: w2, align, size: size3, weight: weight8, color: color2, family, help, children: children2 }) {
61523
+ const span = /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: `${size3}px`, fontFamily: family, fontWeight: weight8, color: color2, lineHeight: 1, whiteSpace: "nowrap" }, children: children2 });
61524
+ return /* @__PURE__ */ jsxRuntime.jsx("foreignObject", { x: x2, y: y2, width: w2, height: size3 + 6, style: { overflow: "visible" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: align, fontSize: `${size3}px`, lineHeight: 1 }, children: help ? /* @__PURE__ */ jsxRuntime.jsx(Help, { id: help, children: span }) : span }) });
61525
+ }
61526
+ function svgText(size3, fill, family, weight8) {
61527
+ return { fontSize: `${size3}px`, fill, fontFamily: family, ...weight8 !== void 0 ? { fontWeight: weight8 } : {} };
61528
+ }
61529
+ function useMeasuredWidth() {
61530
+ const ref = React.useRef(null);
61531
+ const [w2, setW] = React.useState(0);
61532
+ React.useLayoutEffect(() => {
61533
+ const el = ref.current;
61534
+ if (!el) return;
61535
+ const update2 = () => setW(el.clientWidth);
61536
+ update2();
61537
+ const ro = new ResizeObserver(update2);
61538
+ ro.observe(el);
61539
+ return () => ro.disconnect();
61540
+ }, []);
61541
+ return [ref, w2];
61542
+ }
61543
+ function useChartTheme() {
61544
+ const system = react.useChakraContext();
61545
+ const tok = (k2, fallback) => system.token(k2, fallback);
61546
+ const tones = {
61547
+ neg: tok("colors.fg.danger", "#b85a4a"),
61548
+ pos: tok("colors.fg.success", "#2f7a5b"),
61549
+ warn: tok("colors.fg.warning", "#b8862d"),
61550
+ muted: tok("colors.fg.muted", "#6b8080"),
61551
+ brand: tok("colors.brand.solid", "#3a7780")
61552
+ };
61553
+ return {
61554
+ mono: tok("fonts.mono", '"JetBrains Mono", ui-monospace, monospace'),
61555
+ body: tok("fonts.body", "system-ui, -apple-system, sans-serif"),
61556
+ ink: tok("colors.fg", "#111b22"),
61557
+ muted: tones.muted,
61558
+ faint: tok("colors.fg.subtle", "#9bb0b0"),
61559
+ rule: tok("colors.border.subtle", "#e2e8e8"),
61560
+ ruleStrong: tok("colors.border.strong", "#cbd5d5"),
61561
+ surface: tok("colors.bg.surface", "#ffffff"),
61562
+ tone: (t4) => tones[t4] ?? tones.brand,
61563
+ labelSize: 10,
61564
+ titleSize: 11,
61565
+ lineWidth: 1.8,
61566
+ barWidth: 2.5,
61567
+ dotRadius: 2.6,
61568
+ scatterRadius: 3.4,
61569
+ areaOpacity: 0.16
61570
+ };
61571
+ }
61572
+ const niceCeil = (v3) => {
61573
+ if (v3 <= 1e-9) return 0;
61574
+ const mag = Math.pow(10, Math.floor(Math.log10(v3)));
61575
+ const n2 = v3 / mag;
61576
+ const step3 = n2 <= 1 ? 1 : n2 <= 1.5 ? 1.5 : n2 <= 2 ? 2 : n2 <= 3 ? 3 : n2 <= 4 ? 4 : n2 <= 5 ? 5 : n2 <= 6 ? 6 : n2 <= 8 ? 8 : 10;
61577
+ return step3 * mag;
61578
+ };
61579
+ function ForestPlot({ rows, min: min4, max: max5, unit: unit2, height: height2, rowHelp }) {
61580
+ const t4 = useChartTheme();
61581
+ const words = eastUiComponents.useFormatters();
61582
+ const [ref, w2] = useMeasuredWidth();
61583
+ const n2 = rows.length;
61584
+ const hPx = height2 ?? 26 + n2 * 38;
61585
+ const padL = 124, padR = 46, padT = 20, padB = 30;
61586
+ const innerW = Math.max(0, w2 - padL - padR);
61587
+ const innerH = hPx - padT - padB;
61588
+ const x2 = createLinearScale({ domain: [min4, max5], range: [0, innerW] });
61589
+ const rowH = innerH / Math.max(1, n2);
61590
+ const zeroX = Math.max(0, Math.min(innerW, x2(0)));
61591
+ const frac = (v3) => max5 > min4 ? (v3 - min4) / (max5 - min4) : 0.5;
61592
+ const anchorAt = (v3) => frac(v3) < 0.06 ? "start" : frac(v3) > 0.94 ? "end" : "middle";
61593
+ const zf = frac(0);
61594
+ const ticks2 = zf > 0.12 && zf < 0.88 ? [min4, 0, max5] : [min4, max5];
61595
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: padL, top: padT, children: [
61596
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: zeroX, y: -4 }, to: { x: zeroX, y: innerH }, stroke: t4.muted, strokeWidth: 1, strokeDasharray: "3 2" }),
61597
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: zeroX, y: -6, textAnchor: anchorAt(0), style: svgText(t4.labelSize, t4.muted, t4.mono), children: "no effect" }),
61598
+ rows.map((r2, i) => {
61599
+ const cy = rowH * i + rowH / 2;
61600
+ const col = t4.tone(r2.tone);
61601
+ return /* @__PURE__ */ jsxRuntime.jsxs(Group, { top: cy, children: [
61602
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: x2(r2.lo), y: 0 }, to: { x: x2(r2.hi), y: 0 }, stroke: col, strokeWidth: t4.barWidth, strokeOpacity: 0.9, strokeLinecap: "round" }),
61603
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: x2(r2.lo), y: -4 }, to: { x: x2(r2.lo), y: 4 }, stroke: col, strokeWidth: 1.5 }),
61604
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: x2(r2.hi), y: -4 }, to: { x: x2(r2.hi), y: 4 }, stroke: col, strokeWidth: 1.5 }),
61605
+ /* @__PURE__ */ jsxRuntime.jsx(Circle, { cx: x2(r2.est), cy: 0, r: t4.scatterRadius, fill: col, stroke: t4.surface, strokeWidth: 1.8 }),
61606
+ /* @__PURE__ */ jsxRuntime.jsx(ChartLabel, { x: -padL + 2, y: -13, w: padL - 6, align: "left", size: t4.labelSize, weight: 600, color: t4.ink, family: t4.body, ...(rowHelp == null ? void 0 : rowHelp[i]) ? { help: rowHelp[i] } : {}, children: r2.label }),
61607
+ r2.note && /* @__PURE__ */ jsxRuntime.jsx("text", { x: -padL + 2, y: 9, style: svgText(9, t4.faint, t4.body), children: r2.note }),
61608
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: innerW + padR - 2, y: 4, textAnchor: "end", style: svgText(t4.titleSize, col, t4.mono, 700), children: signed(r2.est, words) })
61609
+ ] }, i);
61610
+ }),
61611
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: innerH }, to: { x: innerW, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61612
+ ticks2.map((tk, i) => /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: Math.max(0, Math.min(innerW, x2(tk))), children: [
61613
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: innerH }, to: { x: 0, y: innerH + 4 }, stroke: t4.ruleStrong, strokeWidth: 1 }),
61614
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: 0, y: innerH + 14, textAnchor: anchorAt(tk), style: svgText(t4.labelSize, t4.muted, t4.mono), children: signed(tk, words) })
61615
+ ] }, `t${i}`)),
61616
+ unit2 && /* @__PURE__ */ jsxRuntime.jsx("text", { x: innerW / 2, y: innerH + 26, textAnchor: "middle", style: svgText(t4.labelSize, t4.muted, t4.mono), children: unit2 })
61617
+ ] }) }) });
61618
+ }
61619
+ function AreaRange({ lo: lo2, mid, hi, xTicks = [], xTickWords = false, yTicks = [], zero: zero2, tone: toneName, marks = [], height: height2, yFormat = "signed" }) {
61620
+ const t4 = useChartTheme();
61621
+ const words = eastUiComponents.useFormatters();
61622
+ const [ref, w2] = useMeasuredWidth();
61623
+ const hPx = height2 ?? 100;
61624
+ const col = t4.tone(toneName ?? "brand");
61625
+ const padL = yTicks.length ? 52 : 6;
61626
+ const padR = 12;
61627
+ const padT = marks.length ? 22 : 8;
61628
+ const padB = xTicks.length ? 22 : 12;
61629
+ const innerW = Math.max(0, w2 - padL - padR);
61630
+ const innerH = hPx - padT - padB;
61631
+ const xScale = createLinearScale({ domain: [0, Math.max(1, mid.length - 1)], range: [0, innerW] });
61632
+ const fin = (x2, fallback) => typeof x2 === "number" && Number.isFinite(x2) ? x2 : fallback;
61633
+ const data4 = mid.map((m2, i) => {
61634
+ const mm = fin(m2, 0);
61635
+ return { i, lo: fin(lo2[i], mm), hi: fin(hi[i], mm), mid: mm };
61636
+ });
61637
+ const dataMin = Math.min(...data4.map((d2) => d2.lo), zero2 ?? Infinity);
61638
+ const dataMax = Math.max(...data4.map((d2) => d2.hi), zero2 ?? -Infinity);
61639
+ const yHiN = niceCeil(Math.max(dataMax, 0));
61640
+ const yLoN = dataMin < -0.08 * yHiN ? -niceCeil(-dataMin) : 0;
61641
+ const yScale = createLinearScale({ domain: [yLoN, yHiN], range: [innerH, 0] });
61642
+ const yfmt = (v3) => yFormat === "percent" ? words.percent(v3 / 100) : signed(v3, words);
61643
+ const yLabels = [yfmt(yHiN), yfmt((yHiN + yLoN) / 2), yfmt(yLoN)];
61644
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: padL, top: padT, children: [
61645
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: 0 }, to: { x: 0, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61646
+ yTicks.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
61647
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: -8, y: 10, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[0] }),
61648
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: -8, y: innerH / 2 + 3, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[1] }),
61649
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: -8, y: innerH - 1, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[2] })
61650
+ ] }),
61651
+ zero2 != null && /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: yScale(zero2) }, to: { x: innerW, y: yScale(zero2) }, stroke: t4.muted, strokeWidth: 1, strokeDasharray: "3 2" }),
61652
+ /* @__PURE__ */ jsxRuntime.jsx(Area, { data: data4, x: (d2) => xScale(d2.i), y0: (d2) => yScale(d2.lo), y1: (d2) => yScale(d2.hi), curve: monotoneX, fill: col, fillOpacity: t4.areaOpacity, stroke: "transparent" }),
61653
+ /* @__PURE__ */ jsxRuntime.jsx(LinePath, { data: data4, x: (d2) => xScale(d2.i), y: (d2) => yScale(d2.mid), curve: monotoneX, stroke: col, strokeWidth: t4.lineWidth }),
61654
+ marks.map((m2, i) => {
61655
+ const mc = t4.tone(m2.tone);
61656
+ const dotY = yScale(fin(mid[m2.at], 0));
61657
+ const labY = Math.max(9, dotY - 9);
61658
+ const atEnd = m2.at >= mid.length - 2;
61659
+ const atStart = m2.at <= 1;
61660
+ const align = atEnd ? "right" : atStart ? "left" : "center";
61661
+ const labW = m2.label.length * 6.5 + 8;
61662
+ const labX = atEnd ? -labW - 5 : atStart ? 5 : -labW / 2;
61663
+ return /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: xScale(m2.at), children: [
61664
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: -2 }, to: { x: 0, y: innerH }, stroke: mc, strokeWidth: 1, strokeDasharray: "2 3" }),
61665
+ /* @__PURE__ */ jsxRuntime.jsx(Circle, { cx: 0, cy: dotY, r: t4.dotRadius, fill: mc, stroke: t4.surface, strokeWidth: 1.5 }),
61666
+ /* @__PURE__ */ jsxRuntime.jsx(ChartLabel, { x: labX, y: labY - 11, w: labW, align, size: t4.labelSize, weight: 500, color: mc, family: t4.body, ...m2.help ? { help: m2.help } : {}, children: m2.label })
61667
+ ] }, `mk${i}`);
61668
+ }),
61669
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: innerH }, to: { x: innerW, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61670
+ xTicks.map((tk, i) => {
61671
+ const word = xTickWords;
61672
+ return /* @__PURE__ */ jsxRuntime.jsx("text", { x: innerW * i / Math.max(1, xTicks.length - 1), y: innerH + 14, textAnchor: i === 0 ? "start" : i === xTicks.length - 1 ? "end" : "middle", style: svgText(word ? 9 : t4.labelSize, word ? t4.faint : t4.muted, word ? t4.body : t4.mono), children: tk }, `x${i}`);
61673
+ })
61674
+ ] }) }) });
61675
+ }
61676
+ function OverlapHistogram({ treated, control, domain = [0, 1], supportLabel, positivityOk, height: height2 }) {
61677
+ const t4 = useChartTheme();
61678
+ const words = eastUiComponents.useFormatters();
61679
+ const [ref, w2] = useMeasuredWidth();
61680
+ const hPx = height2 ?? 150;
61681
+ const padL = 8, padR = 8, padT = 16, padB = 26;
61682
+ const innerW = Math.max(0, w2 - padL - padR);
61683
+ const innerH = hPx - padT - padB;
61684
+ const centerY = innerH / 2;
61685
+ const halfH = centerY - 4;
61686
+ const bins = Math.max(treated.length, control.length);
61687
+ const x2 = createLinearScale({ domain, range: [0, innerW] });
61688
+ const span = domain[1] - domain[0];
61689
+ const binW = bins > 0 ? innerW / bins : innerW;
61690
+ const barW = Math.max(1, binW * 0.78);
61691
+ const maxVal = Math.max(1e-9, ...treated, ...control);
61692
+ const tCol = t4.tone("pos");
61693
+ const cCol = t4.tone("muted");
61694
+ const ticks2 = [domain[0], (domain[0] + domain[1]) / 2, domain[1]];
61695
+ const cx2 = (i) => x2(domain[0] + (i + 0.5) / bins * span);
61696
+ return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxRuntime.jsxs(Group, { left: padL, top: padT, children: [
61697
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: 0, y: -4, style: svgText(9, t4.faint, t4.body), children: "treated ↑" }),
61698
+ supportLabel && /* @__PURE__ */ jsxRuntime.jsx("text", { x: innerW, y: -4, textAnchor: "end", style: svgText(t4.labelSize, positivityOk ? t4.tone("pos") : t4.tone("warn"), t4.mono, 600), children: supportLabel }),
61699
+ Array.from({ length: bins }, (_2, i) => {
61700
+ const ht = Number(treated[i] ?? 0) / maxVal * halfH;
61701
+ const hc = Number(control[i] ?? 0) / maxVal * halfH;
61702
+ const left = cx2(i) - barW / 2;
61703
+ return /* @__PURE__ */ jsxRuntime.jsxs(Group, { children: [
61704
+ ht > 0 && /* @__PURE__ */ jsxRuntime.jsx("rect", { x: left, y: centerY - ht, width: barW, height: ht, fill: tCol, fillOpacity: 0.85, rx: 0.5 }),
61705
+ hc > 0 && /* @__PURE__ */ jsxRuntime.jsx("rect", { x: left, y: centerY, width: barW, height: hc, fill: cCol, fillOpacity: 0.6, rx: 0.5 })
61706
+ ] }, i);
61707
+ }),
61708
+ /* @__PURE__ */ jsxRuntime.jsx(Line, { from: { x: 0, y: centerY }, to: { x: innerW, y: centerY }, stroke: t4.ruleStrong, strokeWidth: 1 }),
61709
+ /* @__PURE__ */ jsxRuntime.jsx("text", { x: 0, y: innerH + 4, style: svgText(9, t4.faint, t4.body), children: "untreated ↓" }),
61710
+ ticks2.map((tk, i) => /* @__PURE__ */ jsxRuntime.jsx("text", { x: x2(tk), y: innerH + 16, textAnchor: i === 0 ? "start" : i === ticks2.length - 1 ? "end" : "middle", style: svgText(t4.labelSize, t4.muted, t4.mono), children: fmt$1(tk, words) }, `x${i}`))
61711
+ ] }) }) });
61712
+ }
61746
61713
  const SUBJECT_DEFAULT = { one: "record", many: "records" };
61747
61714
  const AUTORUN_MAX_ROWS = 5e4;
61748
61715
  const TONE_TOKEN = {
@@ -61770,7 +61737,7 @@ function kindOfTypeValue(t4) {
61770
61737
  }
61771
61738
  }
61772
61739
  function useColumns(workspace, source) {
61773
- const types = source ? getBindingTypes(workspace, source) : void 0;
61740
+ const types = getBindingTypes(workspace, source);
61774
61741
  return React.useMemo(() => {
61775
61742
  const st = types == null ? void 0 : types.sourceType;
61776
61743
  if (!st || st.type !== "Array") return { columns: [], rowArrayType: null };
@@ -61782,35 +61749,9 @@ function useColumns(workspace, source) {
61782
61749
  };
61783
61750
  }, [types == null ? void 0 : types.sourceType]);
61784
61751
  }
61785
- function rowMatchesAll(row, preds) {
61786
- return preds.every((p2) => {
61787
- const { fieldId, op } = p2.value;
61788
- const v3 = row[fieldId];
61789
- const ov = op.value;
61790
- switch (op.type) {
61791
- case "eq":
61792
- case "is":
61793
- return v3 === ov;
61794
- case "neq":
61795
- return v3 !== ov;
61796
- case "lt":
61797
- return num(v3) != null && num(ov) != null ? num(v3) < num(ov) : true;
61798
- case "lte":
61799
- return num(v3) != null && num(ov) != null ? num(v3) <= num(ov) : true;
61800
- case "gt":
61801
- return num(v3) != null && num(ov) != null ? num(v3) > num(ov) : true;
61802
- case "gte":
61803
- return num(v3) != null && num(ov) != null ? num(v3) >= num(ov) : true;
61804
- case "in":
61805
- return east.isEastSet(ov) ? ov.has(v3) : true;
61806
- case "notIn":
61807
- return east.isEastSet(ov) ? !ov.has(v3) : true;
61808
- default:
61809
- return true;
61810
- }
61811
- });
61752
+ function inPopulation(row, population) {
61753
+ return population.every((p2) => eastUi.slicePredicateMatches(p2, row));
61812
61754
  }
61813
- const num = (x2) => typeof x2 === "number" ? x2 : typeof x2 === "bigint" ? Number(x2) : null;
61814
61755
  function Cap({ children: children2, help }) {
61815
61756
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
61816
61757
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "caption.eyebrow", fontSize: "9px", mb: "2.5", children: help ? /* @__PURE__ */ jsxRuntime.jsx(Help, { id: help, children: children2 }) : children2 }),
@@ -61923,7 +61864,7 @@ function LoadingSkeleton() {
61923
61864
  ] })
61924
61865
  ] });
61925
61866
  }
61926
- const experimentValueEqual = east.equalFor(internal$1.Experiment.Component.schema);
61867
+ const experimentValueEqual = east.equivalentFor(internal$1.Experiment.Component.schema);
61927
61868
  const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }) {
61928
61869
  var _a2, _b2, _c2;
61929
61870
  const v3 = value;
@@ -61933,6 +61874,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
61933
61874
  const bs = react.useSlotRecipe({ key: "barStrip" })({});
61934
61875
  const statusR = react.useSlotRecipe({ key: "status" });
61935
61876
  const es = react.useSlotRecipe({ key: "eyebrowRow" })({});
61877
+ const words = eastUiComponents.useFormatters();
61936
61878
  const workspace = getReactiveDatasetCache().getConfig().workspace ?? "";
61937
61879
  const data4 = useBindingValue(v3.data);
61938
61880
  const journalBind = useBindingValue(v3.journal.type === "some" ? v3.journal.value : null);
@@ -61980,7 +61922,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
61980
61922
  const population = localPop;
61981
61923
  const filteredRows = React.useMemo(() => {
61982
61924
  if (!data4.value) return null;
61983
- return population.length ? data4.value.filter((r2) => rowMatchesAll(r2, population)) : data4.value;
61925
+ return population.length ? data4.value.filter((r2) => inPopulation(r2, population)) : data4.value;
61984
61926
  }, [data4.value, population]);
61985
61927
  const fields = React.useMemo(
61986
61928
  () => columns.filter((c2) => c2.kind !== "other").map((c2) => {
@@ -62082,8 +62024,8 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62082
62024
  }, [ranConfig, config2, meta3, subject]);
62083
62025
  const view = React.useMemo(() => {
62084
62026
  if (!config2) return null;
62085
- return deriveView(config2, ranConfig ?? config2, columns, shownResult, journalBind.value, meta3, nRows, now2, subject);
62086
- }, [config2, ranConfig, columns, shownResult, journalBind.value, meta3, nRows, now2, subject]);
62027
+ return deriveView(config2, ranConfig ?? config2, columns, shownResult, journalBind.value, meta3, nRows, now2, subject, words);
62028
+ }, [config2, ranConfig, columns, shownResult, journalBind.value, meta3, nRows, now2, subject, words]);
62087
62029
  const designConfigValue = React.useMemo(() => ({
62088
62030
  alpha: east.none,
62089
62031
  target_power: east.none,
@@ -62096,15 +62038,15 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62096
62038
  var _a3;
62097
62039
  if (tab !== "validate" || !hasDesign || design.pending || precomputedDesign !== null) return;
62098
62040
  if (!filteredRows || !config2 || !shownResult) return;
62099
- if (((_a3 = designSnapRef.current) == null ? void 0 : _a3.result) === shownResult) return;
62041
+ if (Object.is((_a3 = designSnapRef.current) == null ? void 0 : _a3.result, shownResult)) return;
62100
62042
  designSnapRef.current = { result: shownResult, config: ranConfig ?? config2 };
62101
62043
  design.call(filteredRows, ranConfig ?? config2, shownResult, designConfigValue);
62102
62044
  }, [tab, hasDesign, precomputedDesign, filteredRows, config2, ranConfig, shownResult, design, designConfigValue]);
62103
62045
  const vmDesign = React.useMemo(() => {
62104
- if (precomputedDesign !== null && shownResult !== null && config2) return deriveDesign(precomputedDesign, shownResult, ranConfig ?? config2, meta3);
62105
- return design.result && designSnapRef.current ? deriveDesign(design.result, designSnapRef.current.result, designSnapRef.current.config, meta3) : null;
62106
- }, [precomputedDesign, shownResult, config2, ranConfig, design.result, meta3]);
62107
- const designFresh = precomputedDesign !== null && shownResult !== null || design.result !== null && ((_b2 = designSnapRef.current) == null ? void 0 : _b2.result) === shownResult && !design.pending;
62046
+ if (precomputedDesign !== null && shownResult !== null && config2) return deriveDesign(precomputedDesign, shownResult, ranConfig ?? config2, meta3, words);
62047
+ return design.result && designSnapRef.current ? deriveDesign(design.result, designSnapRef.current.result, designSnapRef.current.config, meta3, words) : null;
62048
+ }, [precomputedDesign, shownResult, config2, ranConfig, design.result, meta3, words]);
62049
+ const designFresh = precomputedDesign !== null && shownResult !== null || design.result !== null && Object.is((_b2 = designSnapRef.current) == null ? void 0 : _b2.result, shownResult) && !design.pending;
62108
62050
  if (!config2 || !view) {
62109
62051
  const failed2 = experiment.status === "failed";
62110
62052
  const noConfigs = !configsBind.error && configs.length === 0;
@@ -62172,7 +62114,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62172
62114
  readonly && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: badge({ variant: "plain", size: "sm" }), textTransform: "none", letterSpacing: "normal", children: "View only" }),
62173
62115
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: dataStatus.root, children: [
62174
62116
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: dataStatus.indicator }),
62175
- /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: dataStatus.label, children: stale ? `${nRows} rows` : vs.dataLabel })
62117
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: dataStatus.label, children: stale ? `${words.number(nRows)} rows` : vs.dataLabel })
62176
62118
  ] }),
62177
62119
  /* @__PURE__ */ jsxRuntime.jsx(GuidanceToggle, { on: guidance, onToggle: () => setGuidance((g2) => !g2) }),
62178
62120
  canRun && /* @__PURE__ */ jsxRuntime.jsx(ActionButton, { button, variant: "solid", label: "Run", onClick: onRun, disabled: runDisabled, pulse: stale }),
@@ -62205,7 +62147,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62205
62147
  "add another"
62206
62148
  ] }) })
62207
62149
  ] }) }),
62208
- /* @__PURE__ */ jsxRuntime.jsx(Step, { n: 4, title: `Which ${subject.many}?`, help: "step_population", children: /* @__PURE__ */ jsxRuntime.jsx(FilterRail, { fields, population, onChange: editPopulation, chip, button, readonly, subjectMany: subject.many }) }),
62150
+ /* @__PURE__ */ jsxRuntime.jsx(Step, { n: 4, title: `Which ${subject.many}?`, help: "step_population", children: /* @__PURE__ */ jsxRuntime.jsx(FilterRail, { fields, population, onChange: editPopulation, chip, button, readonly, subjectMany: subject.many, words }) }),
62209
62151
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "details", borderTopWidth: "1px", borderColor: "border.subtle", children: [
62210
62152
  /* @__PURE__ */ jsxRuntime.jsxs(
62211
62153
  react.Box,
@@ -62323,10 +62265,11 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62323
62265
  subjectMany: subject.many,
62324
62266
  higherBetter,
62325
62267
  badge,
62326
- barList
62268
+ barList,
62269
+ words
62327
62270
  }
62328
62271
  ),
62329
- activeTab === "answer" && !a2 && ref && /* @__PURE__ */ jsxRuntime.jsx(RefusalZone, { refusal: ref, overlap: ov, naiveValue: (shownResult == null ? void 0 : shownResult.naive) ?? 0, outcome: vs.outcomeLabel }),
62272
+ activeTab === "answer" && !a2 && ref && /* @__PURE__ */ jsxRuntime.jsx(RefusalZone, { refusal: ref, overlap: ov, naiveValue: (shownResult == null ? void 0 : shownResult.naive) ?? 0, outcome: vs.outcomeLabel, words }),
62330
62273
  activeTab === "trust" && vr && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { p: "4.5", children: [
62331
62274
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "body.sm", color: "fg.muted", mb: "3.5", children: /* @__PURE__ */ jsxRuntime.jsx(Help, { id: "trust_intro", children: "Before trusting the answer we tried to break it — colour shows pass / caution." }) }),
62332
62275
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { layerStyle: "frame.flat", children: vr.checks.map((c2, i) => {
@@ -62354,6 +62297,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62354
62297
  zero: 0,
62355
62298
  tone: "brand",
62356
62299
  xTicks: vr.sens.xTicks,
62300
+ xTickWords: true,
62357
62301
  yTicks: vr.sens.yTicks,
62358
62302
  marks: vr.sens.marks,
62359
62303
  height: vr.sens.marks.length ? 148 : 132
@@ -62399,13 +62343,13 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62399
62343
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", flexDirection: "column", gap: "0.5", children: [
62400
62344
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "caption.eyebrow", children: vd.recoLabel }),
62401
62345
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", alignItems: "baseline", gap: "2", children: [
62402
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "mono-kpi", fontFamily: "heading", color: "brand.solid", children: signed(vd.recoEffect) }),
62346
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "mono-kpi", fontFamily: "heading", color: "brand.solid", children: signed(vd.recoEffect, words) }),
62403
62347
  /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { textStyle: "mono.sm", color: "fg.muted", children: [
62404
62348
  vd.outcome,
62405
62349
  " · ",
62406
- signed(vd.recoLo),
62350
+ signed(vd.recoLo, words),
62407
62351
  " … ",
62408
- signed(vd.recoHi)
62352
+ signed(vd.recoHi, words)
62409
62353
  ] })
62410
62354
  ] })
62411
62355
  ] }),
@@ -62417,7 +62361,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62417
62361
  vd.outcome,
62418
62362
  " per step"
62419
62363
  ] }),
62420
- /* @__PURE__ */ jsxRuntime.jsx(react.Box, { py: "0.5", maxH: "200px", overflowY: "auto", children: barList(vd.marginal.map((m2, i) => ({ label: m2.label, frac: m2.frac, tone: i < 2 ? "brand" : "muted", value: signed(m2.value) }))) })
62364
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { py: "0.5", maxH: "200px", overflowY: "auto", children: barList(vd.marginal.map((m2, i) => ({ label: m2.label, frac: m2.frac, tone: i < 2 ? "brand" : "muted", value: signed(m2.value, words) }))) })
62421
62365
  ] })
62422
62366
  ] })
62423
62367
  ] }),
@@ -62435,7 +62379,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62435
62379
  " tab for why)."
62436
62380
  ] })
62437
62381
  ] }),
62438
- activeTab === "validate" && (design.status === "failed" && design.error ? /* @__PURE__ */ jsxRuntime.jsx(react.Box, { px: "4.5", pt: "4.5", children: /* @__PURE__ */ jsxRuntime.jsx(RunError, { error: design.error }) }) : designFresh && vmDesign ? /* @__PURE__ */ jsxRuntime.jsx(ValidatePanel, { vm: vmDesign, barList }) : !hasDesign && precomputedDesign === null ? /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { p: "4.5", children: [
62382
+ activeTab === "validate" && (design.status === "failed" && design.error ? /* @__PURE__ */ jsxRuntime.jsx(react.Box, { px: "4.5", pt: "4.5", children: /* @__PURE__ */ jsxRuntime.jsx(RunError, { error: design.error }) }) : designFresh && vmDesign ? /* @__PURE__ */ jsxRuntime.jsx(ValidatePanel, { vm: vmDesign, barList, words }) : !hasDesign && precomputedDesign === null ? /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { p: "4.5", children: [
62439
62383
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "inline-flex", alignItems: "center", gap: "2", mb: "2", color: "fg.muted", children: [
62440
62384
  /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faTriangleExclamation, style: { fontSize: "13px" } }),
62441
62385
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "body.sm", fontWeight: "semibold", color: "fg.default", children: "No trial recipe for this question" })
@@ -62452,7 +62396,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62452
62396
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: es.root, bg: "bg.canvas", borderTopWidth: "1px", borderColor: "border.subtle", children: [
62453
62397
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: es.lbl, children: /* @__PURE__ */ jsxRuntime.jsx(Help, { id: "journal", children: "Committed experiments" }) }),
62454
62398
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: es.meta, children: /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { as: "span", children: [
62455
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: journal.length }),
62399
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: words.number(journal.length) }),
62456
62400
  " on record",
62457
62401
  journal.length > 50 ? " · showing newest 50" : ""
62458
62402
  ] }) })
@@ -62494,7 +62438,7 @@ const EastChakraExperiment = React.memo(function EastChakraExperiment2({ value }
62494
62438
  ] })
62495
62439
  ] }) });
62496
62440
  }, (prev2, next2) => experimentValueEqual(prev2.value, next2.value) && prev2.storageKey === next2.storageKey);
62497
- function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMany, higherBetter, badge, barList }) {
62441
+ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMany, higherBetter, badge, barList, words }) {
62498
62442
  const dirUp = a2.effect > 0;
62499
62443
  const statusWord = higherBetter === void 0 ? dirUp ? "Higher" : "Lower" : dirUp === higherBetter ? "Better" : "Worse";
62500
62444
  const lowerWord = a2.naive < 0 ? "lower" : "higher";
@@ -62509,7 +62453,7 @@ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMa
62509
62453
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "mono.sm", color: "fg.muted", children: a2.outcome }),
62510
62454
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", alignItems: "baseline", gap: "2.5", children: [
62511
62455
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "mono-kpi", fontFamily: "heading", fontSize: "32px", color: kpiColor, children: /* @__PURE__ */ jsxRuntime.jsxs(Help, { id: "answer_effect", children: [
62512
- signed(a2.effect),
62456
+ signed(a2.effect, words),
62513
62457
  a2.unit ? /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { as: "span", fontSize: "16px", color: "fg.muted", children: [
62514
62458
  " ",
62515
62459
  a2.unit
@@ -62517,9 +62461,9 @@ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMa
62517
62461
  ] }) }),
62518
62462
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "mono.sm", color: "fg.muted", children: /* @__PURE__ */ jsxRuntime.jsxs(Help, { id: "answer_ci", children: [
62519
62463
  "likely between ",
62520
- signed(a2.lo),
62464
+ signed(a2.lo, words),
62521
62465
  " and ",
62522
- signed(a2.hi)
62466
+ signed(a2.hi, words)
62523
62467
  ] }) })
62524
62468
  ] })
62525
62469
  ] }),
@@ -62583,7 +62527,7 @@ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMa
62583
62527
  " on ",
62584
62528
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontWeight: "semibold", children: a2.outcome }),
62585
62529
  " (",
62586
- signed(a2.naive),
62530
+ signed(a2.naive, words),
62587
62531
  ") — but they also differ most on ",
62588
62532
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontWeight: "semibold", children: top.label }),
62589
62533
  " (",
@@ -62642,13 +62586,13 @@ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMa
62642
62586
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { px: "3.5", pb: "3.5", py: "0.5", maxH: "208px", overflowY: "auto", children: barList(a2.balance.map((b2) => ({ label: b2.label, frac: b2.frac, tone: b2.tone, value: b2.display }))) })
62643
62587
  ] }),
62644
62588
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { mt: "3.5", children: /* @__PURE__ */ jsxRuntime.jsx(Help, { id: "counts", display: "inline-flex", gap: "4", children: [[a2.nTotal, subjectMany], [a2.nCompared, "compared like-for-like"], [a2.nDropped, "had no fair match"]].map(([n2, label], i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { textStyle: "mono.sm", color: "fg.muted", children: [
62645
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: Number(n2) }),
62589
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: words.number(n2) }),
62646
62590
  " ",
62647
62591
  label
62648
62592
  ] }, i)) }) })
62649
62593
  ] });
62650
62594
  }
62651
- function RefusalZone({ refusal, overlap, naiveValue, outcome }) {
62595
+ function RefusalZone({ refusal, overlap, naiveValue, outcome, words }) {
62652
62596
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { p: "4.5", children: [
62653
62597
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "inline-flex", alignItems: "center", gap: "2", mb: "2", color: "fg.warning", children: [
62654
62598
  /* @__PURE__ */ jsxRuntime.jsx(FontAwesomeIcon, { icon: faTriangleExclamation, style: { fontSize: "14px" } }),
@@ -62671,11 +62615,11 @@ function RefusalZone({ refusal, overlap, naiveValue, outcome }) {
62671
62615
  "Raw average difference in ",
62672
62616
  outcome,
62673
62617
  " (context only, not an answer): ",
62674
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", color: "fg.muted", children: signed(naiveValue) })
62618
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", color: "fg.muted", children: signed(naiveValue, words) })
62675
62619
  ] })
62676
62620
  ] });
62677
62621
  }
62678
- function ValidatePanel({ vm, barList }) {
62622
+ function ValidatePanel({ vm, barList, words }) {
62679
62623
  const stat = react.useSlotRecipe({ key: "stat" })({ size: "lg" });
62680
62624
  const meter = react.useSlotRecipe({ key: "segmentedMeter" })({});
62681
62625
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { p: "4.5", children: [
@@ -62683,7 +62627,7 @@ function ValidatePanel({ vm, barList }) {
62683
62627
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", alignItems: "flex-end", gap: "5", flexWrap: "wrap", children: [
62684
62628
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: stat.root, children: [
62685
62629
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { css: stat.label, children: /* @__PURE__ */ jsxRuntime.jsx(Help, { id: "validate_size", children: vm.holdback ? "to hold back from" : "to run" }) }),
62686
- vm.faint ? /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "body.sm", fontWeight: "semibold", color: "fg.warning", maxW: "220px", children: "Effect too faint to size — set a materiality threshold to size a trial." }) : /* @__PURE__ */ jsxRuntime.jsx(react.Text, { css: stat.valueText, color: "brand.solid", children: vm.primary.nTotal.toLocaleString() })
62630
+ vm.faint ? /* @__PURE__ */ jsxRuntime.jsx(react.Text, { textStyle: "body.sm", fontWeight: "semibold", color: "fg.warning", maxW: "220px", children: "Effect too faint to size — set a materiality threshold to size a trial." }) : /* @__PURE__ */ jsxRuntime.jsx(react.Text, { css: stat.valueText, color: "brand.solid", children: words.number(vm.primary.nTotal) })
62687
62631
  ] }),
62688
62632
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: meter.root, flex: "1", minW: "220px", children: [
62689
62633
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { css: meter.label, children: /* @__PURE__ */ jsxRuntime.jsx(Help, { id: "validate_split", children: vm.holdback ? "Hold-back split" : "Split" }) }),
@@ -62695,7 +62639,7 @@ function ValidatePanel({ vm, barList }) {
62695
62639
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: meter.keyItem, children: [
62696
62640
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: meter.keyDot, bg: "brand.solid" }),
62697
62641
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
62698
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", css: meter.valueText, children: vm.primary.nTreated.toLocaleString() }),
62642
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", css: meter.valueText, children: words.number(vm.primary.nTreated) }),
62699
62643
  " ",
62700
62644
  vm.holdback ? "treated" : "get it"
62701
62645
  ] })
@@ -62703,7 +62647,7 @@ function ValidatePanel({ vm, barList }) {
62703
62647
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: meter.keyItem, children: [
62704
62648
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: meter.keyDot, bg: "bg.emphasized" }),
62705
62649
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
62706
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", css: meter.valueText, children: vm.primary.nControl.toLocaleString() }),
62650
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", css: meter.valueText, children: words.number(vm.primary.nControl) }),
62707
62651
  " ",
62708
62652
  vm.holdback ? "held back" : "left alone"
62709
62653
  ] })
@@ -62736,16 +62680,16 @@ function ValidatePanel({ vm, barList }) {
62736
62680
  vm.alternates.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: "flex", flexDirection: "column", gap: "1.5", mt: "3", pt: "3", borderTopWidth: "1px", borderColor: "border.subtle", children: vm.alternates.map((o2, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { textStyle: "caption", color: "fg.muted", children: [
62737
62681
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontWeight: "semibold", color: "fg.default", children: o2.label }),
62738
62682
  " · ",
62739
- o2.nTotal.toLocaleString(),
62683
+ words.number(o2.nTotal),
62740
62684
  " total (",
62741
- o2.nTreated.toLocaleString(),
62685
+ words.number(o2.nTreated),
62742
62686
  " / ",
62743
- o2.nControl.toLocaleString(),
62687
+ words.number(o2.nControl),
62744
62688
  ")"
62745
62689
  ] }, i)) })
62746
62690
  ] });
62747
62691
  }
62748
- function FilterRail({ fields, population, onChange: onChange2, chip, button, readonly, subjectMany }) {
62692
+ function FilterRail({ fields, population, onChange: onChange2, chip, button, readonly, subjectMany, words }) {
62749
62693
  const [open, setOpen] = React.useState(null);
62750
62694
  const replaceAt = (i, p2) => onChange2(population.map((f2, j2) => j2 === i ? p2 : f2));
62751
62695
  const removeAt = (i) => onChange2(population.filter((_2, j2) => j2 !== i));
@@ -62754,7 +62698,7 @@ function FilterRail({ fields, population, onChange: onChange2, chip, button, rea
62754
62698
  return /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: population.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: chip({ tone: "plain", numeric: true, shape: "rounded" }), children: [
62755
62699
  "all ",
62756
62700
  subjectMany
62757
- ] }) : population.map((pred, i) => /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: chip({ tone: "brand", numeric: true, shape: "rounded" }), flexShrink: 0, children: /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", whiteSpace: "nowrap", children: eastUiComponents.formatPredicate(pred) }) }, i)) });
62701
+ ] }) : population.map((pred, i) => /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: chip({ tone: "brand", numeric: true, shape: "rounded" }), flexShrink: 0, children: /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", whiteSpace: "nowrap", children: eastUiComponents.formatPredicate(pred, words) }) }, i)) });
62758
62702
  }
62759
62703
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: [
62760
62704
  population.map((pred, i) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -62768,7 +62712,7 @@ function FilterRail({ fields, population, onChange: onChange2, chip, button, rea
62768
62712
  ] }),
62769
62713
  footActions: done,
62770
62714
  trigger: /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: chip({ tone: "brand", numeric: true, shape: "rounded" }), cursor: "pointer", flexShrink: 0, children: [
62771
- /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", whiteSpace: "nowrap", children: eastUiComponents.formatPredicate(pred) }),
62715
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", whiteSpace: "nowrap", children: eastUiComponents.formatPredicate(pred, words) }),
62772
62716
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "button", display: "inline-flex", alignItems: "center", cursor: "pointer", color: "brand.fg", flexShrink: "0", fontSize: "10px", onClick: (e3) => {
62773
62717
  e3.stopPropagation();
62774
62718
  removeAt(i);
@@ -62894,20 +62838,8 @@ function viewFor(binding) {
62894
62838
  const patch = binding.patch.type === "some" ? binding.patch.value : void 0;
62895
62839
  return defaultBindRuntime.buildBindHandle(types.sourceType, source, patch, binding.mode.type);
62896
62840
  }
62897
- function stableStringify(v3) {
62898
- return JSON.stringify(v3, (_k, x2) => {
62899
- if (typeof x2 === "bigint") return `${x2}n`;
62900
- if (x2 instanceof Date) return x2.toISOString();
62901
- if (east.isEastSet(x2)) return [...x2].sort();
62902
- if (east.isEastDict(x2)) return [...x2.entries()].sort((a2, b2) => String(a2[0]).localeCompare(String(b2[0])));
62903
- return x2;
62904
- });
62905
- }
62906
- function hashString2(s2) {
62907
- let h2 = 5381;
62908
- for (let i = 0; i < s2.length; i++) h2 = (h2 << 5) + h2 + s2.charCodeAt(i) | 0;
62909
- return (h2 >>> 0).toString(36);
62910
- }
62841
+ const printDescriptors = east.printFor(east.StructType({ decisions: east.ArrayType(internal$1.DiffBindingType), judgements: internal$1.DiffBindingType }));
62842
+ const printTypeValue = east.printFor(east.EastTypeValueType);
62911
62843
  function readSelectionAt(selectionKey) {
62912
62844
  platform.StateRuntime.trackKey(selectionKey);
62913
62845
  const bytes = platform.StateRuntime.getStore().read(selectionKey);
@@ -62949,16 +62881,6 @@ function removeFromOwningView(decisions, caseId) {
62949
62881
  }
62950
62882
  }
62951
62883
  const decisionHandleCache = /* @__PURE__ */ new Map();
62952
- function typeToken(tv) {
62953
- const seen = /* @__PURE__ */ new WeakSet();
62954
- return JSON.stringify(tv, (_k, v3) => {
62955
- if (typeof v3 === "object" && v3 !== null) {
62956
- if (seen.has(v3)) return "<cyc>";
62957
- seen.add(v3);
62958
- }
62959
- return typeof v3 === "bigint" ? `${v3}n` : v3;
62960
- });
62961
- }
62962
62884
  function compileDecisionMethods(constraintType, decisions, judgements, selectionKey) {
62963
62885
  const platform$1 = platform.getRegisteredPlatformImplementations();
62964
62886
  const c2 = east.fromEastTypeValue(constraintType);
@@ -63026,7 +62948,7 @@ function buildDecisionHandle(decisions, judgements, constraintType) {
63026
62948
  const at = (j2) => j2.resolvedAt.type === "some" ? j2.resolvedAt.value.getTime() : 0;
63027
62949
  return entries.sort((a2, b2) => at(b2) - at(a2));
63028
62950
  };
63029
- const cacheKey = `${hashString2(stableStringify({ decisions, judgements }))}|${typeToken(cType)}`;
62951
+ const cacheKey = `${printDescriptors({ decisions, judgements })}|${printTypeValue(east.canonicalTypeValue(cType))}`;
63030
62952
  let methods = decisionHandleCache.get(cacheKey);
63031
62953
  if (methods === void 0) {
63032
62954
  methods = compileDecisionMethods(cType, decisions, judgements, selectionKey);
@@ -63216,91 +63138,71 @@ const OP_WORDS = {
63216
63138
  notIn: "not in",
63217
63139
  is: "is"
63218
63140
  };
63219
- function formatScalar(v3) {
63220
- if (v3 instanceof Date) {
63221
- return `${v3.toLocaleString("en", { month: "short" })} ${v3.getDate()}`;
63222
- }
63223
- if (east.isEastSet(v3)) {
63224
- return `{${[...v3].map(formatScalar).join(", ")}}`;
63141
+ const PRINTERS = /* @__PURE__ */ new WeakMap();
63142
+ function printerOf(contract) {
63143
+ let printer = PRINTERS.get(contract);
63144
+ if (printer === void 0) {
63145
+ const context = /* @__PURE__ */ new Map();
63146
+ east.printFor(contract.type, context);
63147
+ printer = (type) => east.printFor(type, context);
63148
+ PRINTERS.set(contract, printer);
63225
63149
  }
63226
- if (v3 !== null && typeof v3 === "object" && !v3.type) {
63227
- return Object.entries(v3).map(([k2, x2]) => `${k2} ${formatScalar(x2)}`).join(" · ");
63228
- }
63229
- return String(v3);
63150
+ return printer;
63230
63151
  }
63231
- function formatConstraint(constraint, payloadType, levers) {
63232
- var _a2, _b2;
63233
- const c2 = constraint;
63234
- const lever = ((_a2 = levers == null ? void 0 : levers.find((l2) => l2.case === c2.type)) == null ? void 0 : _a2.label) ?? c2.type;
63235
- if ((payloadType == null ? void 0 : payloadType.type) === "Variant") {
63236
- const op = c2.value;
63237
- const word = OP_WORDS[op.type] ?? op.type;
63238
- const opType = (_b2 = payloadType.cases) == null ? void 0 : _b2[op.type];
63239
- if ((opType == null ? void 0 : opType.type) === "Struct" && op.value !== null && typeof op.value === "object") {
63240
- const r2 = op.value;
63241
- if ("min" in r2 && "max" in r2) {
63242
- return { lever, op: word, value: `${formatScalar(r2.min)} – ${formatScalar(r2.max)}` };
63243
- }
63152
+ function formatValue(value, type, words, print) {
63153
+ switch (type.type) {
63154
+ case "DateTime":
63155
+ return words.monthDay(value);
63156
+ case "Float":
63157
+ return words.float(value);
63158
+ case "String":
63159
+ return value;
63160
+ case "Set": {
63161
+ const member = type.value;
63162
+ return `{${[...value].map((m2) => formatValue(m2, member, words, print)).join(", ")}}`;
63244
63163
  }
63245
- return { lever, op: word, value: formatScalar(op.value) };
63246
- }
63247
- return { lever, op: "·", value: formatScalar(c2.value) };
63248
- }
63249
- const PRIMITIVES = /* @__PURE__ */ new Set(["String", "Integer", "Float", "DateTime", "Boolean"]);
63250
- function normalizeTypeValue(tv) {
63251
- var _a2;
63252
- const n2 = tv;
63253
- if (n2.cases !== void 0 || n2.fields !== void 0) {
63254
- const out = { type: n2.type };
63255
- if (n2.cases) out.cases = Object.fromEntries(Object.entries(n2.cases).map(([k2, v3]) => [k2, normalizeTypeValue(v3)]));
63256
- if (n2.fields) out.fields = Object.fromEntries(Object.entries(n2.fields).map(([k2, v3]) => [k2, normalizeTypeValue(v3)]));
63257
- if (n2.key) out.key = normalizeTypeValue(n2.key);
63258
- if (n2.value !== void 0 && (n2.type === "Array" || n2.type === "Dict")) out.value = normalizeTypeValue(n2.value);
63259
- return out;
63260
- }
63261
- switch (n2.type) {
63262
63164
  case "Struct":
63263
- return { type: "Struct", fields: Object.fromEntries(n2.value.map((f2) => [f2.name, normalizeTypeValue(f2.type)])) };
63264
- case "Variant":
63265
- return { type: "Variant", cases: Object.fromEntries(n2.value.map((f2) => [f2.name, normalizeTypeValue(f2.type)])) };
63266
- case "Array":
63267
- return { type: "Array", value: normalizeTypeValue(n2.value) };
63268
- case "Dict": {
63269
- const d2 = n2.value;
63270
- return { type: "Dict", key: normalizeTypeValue(d2.key), value: normalizeTypeValue(d2.value) };
63271
- }
63272
- case "Recursive": {
63273
- const w2 = n2.value;
63274
- if ((w2 == null ? void 0 : w2.type) === "wrapper" && ((_a2 = w2.value) == null ? void 0 : _a2.inner)) return normalizeTypeValue(w2.value.inner);
63275
- return { type: n2.type };
63276
- }
63165
+ return type.value.map((f2) => `${f2.name} ${formatValue(value[f2.name], f2.type, words, print)}`).join(" · ");
63277
63166
  default:
63278
- return { type: n2.type };
63167
+ return print(type)(value);
63279
63168
  }
63280
63169
  }
63281
- function emptyFor(node2) {
63282
- switch (node2.type) {
63283
- case "Integer":
63284
- return 0n;
63285
- case "Float":
63286
- return 0;
63287
- case "DateTime":
63288
- return /* @__PURE__ */ new Date();
63289
- case "Boolean":
63290
- return false;
63291
- case "String":
63292
- return "";
63293
- case "Struct":
63294
- return Object.fromEntries(Object.entries(node2.fields ?? {}).map(([k2, f2]) => [k2, emptyFor(f2)]));
63295
- default:
63296
- return null;
63170
+ function formatConstraint(constraint, contract, levers, words = eastUiComponents.formatters()) {
63171
+ var _a2;
63172
+ const lever = ((_a2 = levers == null ? void 0 : levers.find((l2) => l2.case === constraint.type)) == null ? void 0 : _a2.label) ?? constraint.type;
63173
+ const payload = contract == null ? void 0 : contract.payloads.get(constraint.type);
63174
+ if (contract === void 0 || payload === void 0) return { lever, op: "·", value: "" };
63175
+ const print = printerOf(contract);
63176
+ if (payload.type === "Variant") {
63177
+ const op = constraint.value;
63178
+ const word = OP_WORDS[op.type] ?? op.type;
63179
+ const opType = payload.value.find((c2) => c2.name === op.type).type;
63180
+ if (opType.type === "Struct") {
63181
+ const fields = opType.value;
63182
+ const min4 = fields.find((f2) => f2.name === "min");
63183
+ const max5 = fields.find((f2) => f2.name === "max");
63184
+ if (min4 !== void 0 && max5 !== void 0) {
63185
+ const range = op.value;
63186
+ return { lever, op: word, value: `${formatValue(range.min, min4.type, words, print)} – ${formatValue(range.max, max5.type, words, print)}` };
63187
+ }
63188
+ }
63189
+ return { lever, op: word, value: formatValue(op.value, opType, words, print) };
63297
63190
  }
63191
+ return { lever, op: "·", value: formatValue(constraint.value, payload, words, print) };
63298
63192
  }
63299
- function leverPayloadEditable(node2) {
63300
- if (!node2) return false;
63301
- if (PRIMITIVES.has(node2.type)) return true;
63302
- if (node2.type === "Struct") return Object.values(node2.fields ?? {}).every((f2) => PRIMITIVES.has(f2.type));
63303
- if (node2.type === "Variant") return Object.values(node2.cases ?? {}).every((c2) => PRIMITIVES.has(c2.type) || c2.type === "Struct" && Object.values(c2.fields ?? {}).every((f2) => PRIMITIVES.has(f2.type)));
63193
+ const PRIMITIVES = /* @__PURE__ */ new Set(["String", "Integer", "Float", "DateTime", "Boolean"]);
63194
+ const NULL_TYPE = east.toEastTypeValue(east.NullType);
63195
+ function emptyFor(type) {
63196
+ if (type.type === "DateTime") return /* @__PURE__ */ new Date();
63197
+ if (type.type === "Struct") return Object.fromEntries(type.value.map((f2) => [f2.name, emptyFor(f2.type)]));
63198
+ return east.defaultValue(type);
63199
+ }
63200
+ function leverPayloadEditable(payload) {
63201
+ if (payload === void 0) return false;
63202
+ const primitive = (t4) => PRIMITIVES.has(t4.type);
63203
+ const structOfPrimitives = (t4) => t4.type === "Struct" && t4.value.every((f2) => primitive(f2.type));
63204
+ if (primitive(payload) || structOfPrimitives(payload)) return true;
63205
+ if (payload.type === "Variant") return payload.value.every((c2) => primitive(c2.type) || structOfPrimitives(c2.type));
63304
63206
  return false;
63305
63207
  }
63306
63208
  const inputStyle = east.some({ size: east.some(east.variant("sm", null)) });
@@ -63308,17 +63210,17 @@ function LeverEditor({ leverCase, payload, onInject }) {
63308
63210
  var _a2;
63309
63211
  const button = react.useRecipe({ key: "button" });
63310
63212
  const isOpVariant = payload.type === "Variant";
63311
- const ops = React.useMemo(() => isOpVariant ? Object.keys(payload.cases ?? {}) : [], [isOpVariant, payload]);
63213
+ const ops = React.useMemo(() => payload.type === "Variant" ? payload.value.map((c2) => c2.name) : [], [payload]);
63312
63214
  const [opTag, setOpTag] = React.useState(ops[0] ?? "");
63313
- const active = isOpVariant ? ((_a2 = payload.cases) == null ? void 0 : _a2[opTag]) ?? { type: "Null" } : payload;
63215
+ const active = payload.type === "Variant" ? ((_a2 = payload.value.find((c2) => c2.name === opTag)) == null ? void 0 : _a2.type) ?? NULL_TYPE : payload;
63314
63216
  const valRef = React.useRef(emptyFor(active));
63315
63217
  const keyRef = React.useRef(`${leverCase}:${opTag}`);
63316
63218
  if (keyRef.current !== `${leverCase}:${opTag}`) {
63317
63219
  keyRef.current = `${leverCase}:${opTag}`;
63318
63220
  valRef.current = emptyFor(active);
63319
63221
  }
63320
- const primitiveInput = (node2, key, get3, set3) => {
63321
- switch (node2.type) {
63222
+ const primitiveInput = (type, key, get3, set3) => {
63223
+ switch (type.type) {
63322
63224
  case "Integer":
63323
63225
  return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraIntegerInput, { value: { value: get3(), onChange: east.some(set3), style: inputStyle } }, key);
63324
63226
  case "Float":
@@ -63331,7 +63233,7 @@ function LeverEditor({ leverCase, payload, onInject }) {
63331
63233
  {
63332
63234
  ariaLabel: key,
63333
63235
  value: {
63334
- value: east.some(String(get3())),
63236
+ value: east.some(get3() === true ? "true" : "false"),
63335
63237
  items: [{ value: "true", label: "true", disabled: east.none }, { value: "false", label: "false", disabled: east.none }],
63336
63238
  placeholder: east.none,
63337
63239
  multiple: east.none,
@@ -63344,17 +63246,19 @@ function LeverEditor({ leverCase, payload, onInject }) {
63344
63246
  },
63345
63247
  key
63346
63248
  );
63249
+ case "String":
63250
+ return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraStringInput, { value: { value: get3(), onChange: east.some(set3), style: inputStyle } }, key);
63347
63251
  default:
63348
- return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraStringInput, { value: { value: String(get3() ?? ""), onChange: east.some(set3), style: inputStyle } }, key);
63252
+ return null;
63349
63253
  }
63350
63254
  };
63351
63255
  const valueControls = React.useMemo(() => {
63352
63256
  const k2 = keyRef.current;
63353
63257
  if (active.type === "Struct") {
63354
- return Object.entries(active.fields ?? {}).map(([field, node2]) => /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", alignItems: "center", gap: "6px", minW: 0, children: [
63258
+ return active.value.map(({ name: field, type }) => /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", alignItems: "center", gap: "6px", minW: 0, children: [
63355
63259
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", textStyle: "caption.eyebrow", color: "fg.subtle", flexShrink: 0, children: field }),
63356
63260
  primitiveInput(
63357
- node2,
63261
+ type,
63358
63262
  `${k2}.${field}.in`,
63359
63263
  () => valRef.current[field],
63360
63264
  (v3) => {
@@ -63410,11 +63314,12 @@ function LeverEditor({ leverCase, payload, onInject }) {
63410
63314
  }
63411
63315
  );
63412
63316
  }
63413
- function fmt(d2, n2, showSign = false) {
63414
- return eastUiComponents.formatTick(n2, eastUiComponents.getSomeorUndefined(d2.format), showSign);
63317
+ function fmt(words, d2, n2, showSign = false) {
63318
+ return words.value(n2, eastUiComponents.getSomeorUndefined(d2.format), showSign);
63415
63319
  }
63416
63320
  const caption = { textStyle: "caption.eyebrow", color: "fg.muted" };
63417
63321
  const EvidenceFacet = React.memo(function EvidenceFacet2({ decision, children: children2 }) {
63322
+ const words = eastUiComponents.useFormatters();
63418
63323
  const stakes = eastUiComponents.getSomeorUndefined(decision.stakes);
63419
63324
  const downside = eastUiComponents.getSomeorUndefined(decision.downside);
63420
63325
  const confidence = eastUiComponents.getSomeorUndefined(decision.confidence);
@@ -63430,15 +63335,12 @@ const EvidenceFacet = React.memo(function EvidenceFacet2({ decision, children: c
63430
63335
  ] }),
63431
63336
  downside !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
63432
63337
  "if wrong ",
63433
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", color: "fg.danger", children: fmt(decision, downside, true) }),
63338
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", color: "fg.danger", children: fmt(words, decision, downside, true) }),
63434
63339
  " · "
63435
63340
  ] }),
63436
63341
  confidence !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
63437
63342
  "confidence ",
63438
- /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: [
63439
- Math.round(confidence * 100),
63440
- "%"
63441
- ] })
63343
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: words.percent(confidence) })
63442
63344
  ] })
63443
63345
  ] })
63444
63346
  ] }),
@@ -63454,8 +63356,9 @@ const EvidenceFacet = React.memo(function EvidenceFacet2({ decision, children: c
63454
63356
  children2
63455
63357
  ] });
63456
63358
  });
63359
+ const compareValues$1 = east.compareFor(east.FloatType);
63457
63360
  function rankOptions(d2) {
63458
- const alternatives = [...d2.alternatives].sort((a2, b2) => b2.value - a2.value).map((a2) => ({
63361
+ const alternatives = [...d2.alternatives].sort((a2, b2) => compareValues$1(b2.value, a2.value)).map((a2) => ({
63459
63362
  label: a2.label,
63460
63363
  value: a2.value,
63461
63364
  downside: eastUiComponents.getSomeorUndefined(a2.downside),
@@ -63475,14 +63378,15 @@ function rankOptions(d2) {
63475
63378
  ...alternatives
63476
63379
  ].map((o2, i) => ({ ...o2, rank: i + 1 }));
63477
63380
  }
63478
- function metaLine(o2) {
63381
+ function metaLine(o2, words) {
63479
63382
  const parts = [];
63480
63383
  if (o2.recommended) parts.push("recommended");
63481
- if (o2.confidence !== void 0) parts.push(`${Math.round(o2.confidence * 100)}% conf`);
63384
+ if (o2.confidence !== void 0) parts.push(`${words.percent(o2.confidence)} conf`);
63482
63385
  if (!o2.recommended && o2.note !== void 0) parts.push(o2.note);
63483
63386
  return parts.join(" · ");
63484
63387
  }
63485
63388
  const OptionsFacet = React.memo(function OptionsFacet2({ decision, narrow }) {
63389
+ const words = eastUiComponents.useFormatters();
63486
63390
  const options2 = rankOptions(decision);
63487
63391
  const maxUp = Math.max(...options2.map((o2) => Math.max(o2.value, 0)), 1e-9);
63488
63392
  const maxDown = Math.max(...options2.map((o2) => Math.abs(o2.downside ?? 0)), 1e-9);
@@ -63498,7 +63402,7 @@ const OptionsFacet = React.memo(function OptionsFacet2({ decision, narrow }) {
63498
63402
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", flexDirection: "column", gap: "10px", children: [
63499
63403
  /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { ...caption, color: "fg", children: [
63500
63404
  "Options · ",
63501
- options2.length,
63405
+ words.number(options2.length),
63502
63406
  " evaluated"
63503
63407
  ] }),
63504
63408
  options2.map((o2) => /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", flexDirection: "column", gap: "4px", pl: "8px", ...o2.recommended ? { boxShadow: "inset 2px 0 0 var(--chakra-colors-accent-brand)" } : {}, children: [
@@ -63507,8 +63411,8 @@ const OptionsFacet = React.memo(function OptionsFacet2({ decision, narrow }) {
63507
63411
  " ",
63508
63412
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontWeight: o2.recommended ? "semibold" : "normal", children: o2.label })
63509
63413
  ] }),
63510
- meter(upLabel, o2.value / maxUp, fmt(decision, o2.value, signed2), signed2 ? "success" : "neutral"),
63511
- meter("If wrong", (o2.downside ?? 0) / maxDown, o2.downside !== void 0 ? fmt(decision, o2.downside, true) : "—", "danger")
63414
+ meter(upLabel, o2.value / maxUp, fmt(words, decision, o2.value, signed2), signed2 ? "success" : "neutral"),
63415
+ meter("If wrong", (o2.downside ?? 0) / maxDown, o2.downside !== void 0 ? fmt(words, decision, o2.downside, true) : "—", "danger")
63512
63416
  ] }, o2.rank))
63513
63417
  ] });
63514
63418
  }
@@ -63516,7 +63420,7 @@ const OptionsFacet = React.memo(function OptionsFacet2({ decision, narrow }) {
63516
63420
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "grid", gridTemplateColumns: "minmax(180px, 1.1fr) 1fr 1fr", alignItems: "baseline", gap: "8px", children: [
63517
63421
  /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { ...caption, color: "fg", children: [
63518
63422
  "Options · ",
63519
- options2.length,
63423
+ words.number(options2.length),
63520
63424
  " evaluated"
63521
63425
  ] }),
63522
63426
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { ...caption, textAlign: "center", children: "If wrong" }),
@@ -63538,15 +63442,15 @@ const OptionsFacet = React.memo(function OptionsFacet2({ decision, narrow }) {
63538
63442
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { minW: 0, pl: o2.recommended ? "6px" : "0", display: "flex", alignItems: "baseline", gap: "6px", children: [
63539
63443
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", fontSize: "11px", color: "fg.subtle", flexShrink: 0, children: o2.rank }),
63540
63444
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontSize: "12.5px", fontWeight: o2.recommended ? "semibold" : "normal", flexShrink: 0, children: o2.label }),
63541
- metaLine(o2) !== "" && /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", fontSize: "10.5px", color: "fg.muted", minW: 0, truncate: true, children: metaLine(o2) })
63445
+ metaLine(o2, words) !== "" && /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", fontSize: "10.5px", color: "fg.muted", minW: 0, truncate: true, children: metaLine(o2, words) })
63542
63446
  ] }),
63543
63447
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: "flex", justifyContent: "flex-end", alignItems: "center", gap: "6px", height: "16px", children: o2.downside !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
63544
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "10.5px", fontFamily: "mono", color: "fg.danger", flexShrink: 0, children: fmt(decision, o2.downside, true) }),
63448
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "10.5px", fontFamily: "mono", color: "fg.danger", flexShrink: 0, children: fmt(words, decision, o2.downside, true) }),
63545
63449
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { height: "12px", width: `${Math.round(downFrac * 100)}%`, bg: "fg.danger", opacity: 0.55 })
63546
63450
  ] }) }),
63547
63451
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: "flex", alignItems: "center", gap: "6px", height: "16px", borderLeftWidth: "1px", borderColor: "border.strong", children: o2.value > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
63548
63452
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { height: "12px", width: `${Math.round(upFrac * 100)}%`, bg: signed2 ? "fg.success" : "fg.subtle", opacity: 0.6 }),
63549
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "10.5px", fontFamily: "mono", color: signed2 ? "fg.success" : "fg.muted", flexShrink: 0, children: fmt(decision, o2.value, signed2) })
63453
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "10.5px", fontFamily: "mono", color: signed2 ? "fg.success" : "fg.muted", flexShrink: 0, children: fmt(words, decision, o2.value, signed2) })
63550
63454
  ] }) })
63551
63455
  ]
63552
63456
  },
@@ -63560,8 +63464,9 @@ const ANSWERS = [
63560
63464
  { literal: "no", label: "No" },
63561
63465
  { literal: "unknown", label: "Don't know" }
63562
63466
  ];
63563
- const JudgementFacet = React.memo(function JudgementFacet2({ decision, handle, leverPayloads }) {
63467
+ const JudgementFacet = React.memo(function JudgementFacet2({ decision, handle, contract }) {
63564
63468
  var _a2;
63469
+ const words = eastUiComponents.useFormatters();
63565
63470
  const button = react.useRecipe({ key: "button" });
63566
63471
  const input = react.useRecipe({ key: "input" });
63567
63472
  const judgement = handle.judgementFor(decision.id);
@@ -63574,11 +63479,12 @@ const JudgementFacet = React.memo(function JudgementFacet2({ decision, handle, l
63574
63479
  if (knowledge !== stagedKnowledge) handle.addKnowledge(decision.id, knowledge);
63575
63480
  }, [knowledge, stagedKnowledge, handle, decision.id]);
63576
63481
  const levers = React.useMemo(
63577
- () => decision.levers.filter((l2) => leverPayloadEditable(leverPayloads[l2.case])),
63578
- [decision.levers, leverPayloads]
63482
+ () => decision.levers.filter((l2) => leverPayloadEditable(contract == null ? void 0 : contract.payloads.get(l2.case))),
63483
+ [decision.levers, contract]
63579
63484
  );
63580
63485
  const [leverCase, setLeverCase] = React.useState(((_a2 = levers[0]) == null ? void 0 : _a2.case) ?? "");
63581
63486
  const activeLever = levers.find((l2) => l2.case === leverCase) ?? levers[0];
63487
+ const activePayload = activeLever === void 0 ? void 0 : contract == null ? void 0 : contract.payloads.get(activeLever.case);
63582
63488
  const gate = handle.commitStateFor(decision.id);
63583
63489
  const gateHint = (gate == null ? void 0 : gate.type) === "gated" ? gate.value === 1n ? "Answer the judgement question to enable apply" : `Answer the ${gate.value} judgement questions to enable apply` : (gate == null ? void 0 : gate.type) === "blocked" ? "Commit blocked — an answer contradicts the recommendation" : (gate == null ? void 0 : gate.type) === "handoff" ? "Awaiting handoff — an answer was don't know" : null;
63584
63490
  const onInject = React.useCallback((constraint) => {
@@ -63624,8 +63530,7 @@ const JudgementFacet = React.memo(function JudgementFacet2({ decision, handle, l
63624
63530
  (levers.length > 0 || judgement.constraints.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", flexDirection: "column", gap: "6px", children: [
63625
63531
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { ...caption, children: "Inject constraint · next run folds it in" }),
63626
63532
  judgement.constraints.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: "flex", gap: "12px", flexWrap: "wrap", children: judgement.constraints.map((c2, i) => {
63627
- const tag = c2.type;
63628
- const f2 = formatConstraint(c2, leverPayloads[tag], decision.levers);
63533
+ const f2 = formatConstraint(c2, contract, decision.levers, words);
63629
63534
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { as: "span", fontFamily: "mono", fontSize: "11px", children: [
63630
63535
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "accent.brand", fontWeight: "semibold", children: f2.lever }),
63631
63536
  " ",
@@ -63634,7 +63539,7 @@ const JudgementFacet = React.memo(function JudgementFacet2({ decision, handle, l
63634
63539
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontWeight: "semibold", children: f2.value })
63635
63540
  ] }, i);
63636
63541
  }) }),
63637
- activeLever !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap", children: [
63542
+ activeLever !== void 0 && activePayload !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap", children: [
63638
63543
  levers.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(react.Box, { flexShrink: 0, css: { "& [data-scope=select][data-part=root]": { width: "auto", minWidth: "160px" } }, children: /* @__PURE__ */ jsxRuntime.jsx(
63639
63544
  eastUiComponents.EastChakraSelect,
63640
63545
  {
@@ -63656,7 +63561,7 @@ const JudgementFacet = React.memo(function JudgementFacet2({ decision, handle, l
63656
63561
  LeverEditor,
63657
63562
  {
63658
63563
  leverCase: activeLever.case,
63659
- payload: leverPayloads[activeLever.case],
63564
+ payload: activePayload,
63660
63565
  onInject
63661
63566
  },
63662
63567
  activeLever.case
@@ -63679,11 +63584,54 @@ const JudgementFacet = React.memo(function JudgementFacet2({ decision, handle, l
63679
63584
  ] })
63680
63585
  ] });
63681
63586
  });
63587
+ function body(type) {
63588
+ return type.type === "Recursive" && type.value.type === "wrapper" ? type.value.value.inner : type;
63589
+ }
63590
+ function constraintContractOf(judgementsType) {
63591
+ const dict = body(judgementsType);
63592
+ if (dict.type !== "Dict") return void 0;
63593
+ const record = body(dict.value.value);
63594
+ if (record.type !== "Struct") return void 0;
63595
+ const field = record.value.find((f2) => f2.name === "constraints");
63596
+ if (field === void 0) return void 0;
63597
+ const constraints = body(field.type);
63598
+ if (constraints.type !== "Array") return void 0;
63599
+ const contract = constraints.value;
63600
+ const cases = body(contract);
63601
+ if (cases.type !== "Variant") return void 0;
63602
+ return {
63603
+ type: contract,
63604
+ payloads: new Map(cases.value.map((c2) => [c2.name, c2.type]))
63605
+ };
63606
+ }
63607
+ function useConstraintContract(ref) {
63608
+ const workspace = getReactiveDatasetCache().getConfig().workspace ?? "";
63609
+ return React.useMemo(() => {
63610
+ if (ref === null) return void 0;
63611
+ const judgements = getBindingTypes(workspace, ref.judgements.source);
63612
+ return judgements === void 0 ? void 0 : constraintContractOf(judgements.sourceType);
63613
+ }, [ref, workspace]);
63614
+ }
63682
63615
  const URGENCY_RANK = {
63683
63616
  overdue: 0,
63684
63617
  due: 1,
63685
63618
  routine: 2
63686
63619
  };
63620
+ const compareInstants = east.compareFor(east.DateTimeType);
63621
+ const compareValues = east.compareFor(east.FloatType);
63622
+ function compareByUrgency(a2, b2) {
63623
+ const rank = URGENCY_RANK[a2.urgency.type] - URGENCY_RANK[b2.urgency.type];
63624
+ if (rank !== 0) return rank;
63625
+ const da = a2.deadline.type === "some" ? a2.deadline.value : void 0;
63626
+ const db = b2.deadline.type === "some" ? b2.deadline.value : void 0;
63627
+ if (da !== void 0 && db !== void 0) {
63628
+ const byDeadline = compareInstants(da, db);
63629
+ if (byDeadline !== 0) return byDeadline;
63630
+ } else if (da !== db) {
63631
+ return da === void 0 ? 1 : -1;
63632
+ }
63633
+ return compareValues(b2.value, a2.value);
63634
+ }
63687
63635
  const URGENCY_GROUP_LABEL = {
63688
63636
  overdue: "Overdue",
63689
63637
  due: "Due today",
@@ -63730,10 +63678,10 @@ const URGENCY_TONE = {
63730
63678
  };
63731
63679
  const EXIT_MS = 560;
63732
63680
  const NARROW_PX = 560;
63733
- function decisionValue(d2, n2, showSign = false) {
63734
- return eastUiComponents.formatTick(n2, eastUiComponents.getSomeorUndefined(d2.format), showSign);
63681
+ function decisionValue(words, d2, n2, showSign = false) {
63682
+ return words.value(n2, eastUiComponents.getSomeorUndefined(d2.format), showSign);
63735
63683
  }
63736
- function deadlineSuffix(d2) {
63684
+ function deadlineSuffix(d2, words) {
63737
63685
  const deadline = eastUiComponents.getSomeorUndefined(d2.deadline);
63738
63686
  if (deadline === void 0) return "";
63739
63687
  if (d2.urgency.type === "overdue") {
@@ -63742,34 +63690,16 @@ function deadlineSuffix(d2) {
63742
63690
  if (hours < 48) return ` ${hours}h`;
63743
63691
  return ` ${Math.round(hours / 24)}d`;
63744
63692
  }
63745
- if (d2.urgency.type === "due") {
63746
- const h2 = deadline.getHours();
63747
- const m2 = deadline.getMinutes();
63748
- const meridiem = h2 >= 12 ? "pm" : "am";
63749
- const clock2 = h2 % 12 === 0 ? 12 : h2 % 12;
63750
- return m2 === 0 ? ` ${clock2}${meridiem}` : ` ${clock2}:${String(m2).padStart(2, "0")}${meridiem}`;
63751
- }
63693
+ if (d2.urgency.type === "due") return ` ${words.time(deadline)}`;
63752
63694
  return "";
63753
63695
  }
63754
- function useLeverPayloads(ref) {
63755
- const cache3 = getReactiveDatasetCache();
63756
- const workspace = cache3.getConfig().workspace ?? "";
63757
- return React.useMemo(() => {
63758
- var _a2, _b2, _c2;
63759
- if (!ref) return {};
63760
- const judgements = getBindingTypes(workspace, ref.judgements.source);
63761
- if (!(judgements == null ? void 0 : judgements.sourceType)) return {};
63762
- const root2 = normalizeTypeValue(judgements.sourceType);
63763
- const constraint = (_c2 = (_b2 = (_a2 = root2.value) == null ? void 0 : _a2.fields) == null ? void 0 : _b2["constraints"]) == null ? void 0 : _c2.value;
63764
- return (constraint == null ? void 0 : constraint.type) === "Variant" ? constraint.cases ?? {} : {};
63765
- }, [ref, workspace]);
63766
- }
63767
- const Row = React.memo(function Row2({ decision, handle, selected: selected2, narrow, leverPayloads, modify, evidence, defaultFacet, facetInclude, apply: apply2, reject: reject2, leaving, storageKey }) {
63696
+ const Row = React.memo(function Row2({ decision, handle, selected: selected2, narrow, contract, modify, evidence, defaultFacet, facetInclude, apply: apply2, reject: reject2, leaving, storageKey }) {
63768
63697
  var _a2, _b2;
63769
63698
  const dq = react.useSlotRecipe({ key: "decisionQueue" });
63770
63699
  const status = react.useSlotRecipe({ key: "status" });
63771
63700
  const tabs = react.useSlotRecipe({ key: "facetTabs" });
63772
63701
  const button = react.useRecipe({ key: "button" });
63702
+ const words = eastUiComponents.useFormatters();
63773
63703
  const rs = dq({});
63774
63704
  const ts = tabs({});
63775
63705
  const st = status({ status: URGENCY_TONE[decision.urgency.type], size: "md" });
@@ -63795,10 +63725,15 @@ const Row = React.memo(function Row2({ decision, handle, selected: selected2, na
63795
63725
  const handleReject = React.useCallback(() => {
63796
63726
  reject2(decision);
63797
63727
  }, [reject2, decision]);
63728
+ const stageUpdate = handle.update;
63729
+ const updateDecision = React.useCallback((next2) => {
63730
+ stageUpdate(next2);
63731
+ return null;
63732
+ }, [stageUpdate]);
63798
63733
  const probe = React.useMemo(() => {
63799
63734
  if (!selected2 || facet !== "modify" || !modify) return null;
63800
- return modify(decision, handle.update);
63801
- }, [selected2, facet, modify, decision, handle.update]);
63735
+ return modify(decision, updateDecision);
63736
+ }, [selected2, facet, modify, decision, updateDecision]);
63802
63737
  const canvas = React.useMemo(() => {
63803
63738
  if (!selected2 || facet !== "evidence" || !evidence) return null;
63804
63739
  return evidence(decision);
@@ -63847,11 +63782,11 @@ const Row = React.memo(function Row2({ decision, handle, selected: selected2, na
63847
63782
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: st.indicator }),
63848
63783
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: st.label, children: [
63849
63784
  decision.urgency.type,
63850
- deadlineSuffix(decision)
63785
+ deadlineSuffix(decision, words)
63851
63786
  ] })
63852
63787
  ] });
63853
63788
  const valueSigned = ((_b2 = eastUiComponents.getSomeorUndefined(decision.valueAxis)) == null ? void 0 : _b2.signed) ?? true;
63854
- const valueText = /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontFamily: "mono", fontWeight: "semibold", textAlign: "right", ...valueSigned && decision.value >= 0 && selected2 ? { color: "fg.success" } : {}, children: decisionValue(decision, decision.value, valueSigned && selected2) });
63789
+ const valueText = /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontFamily: "mono", fontWeight: "semibold", textAlign: "right", ...valueSigned && decision.value >= 0 && selected2 ? { color: "fg.success" } : {}, children: decisionValue(words, decision, decision.value, valueSigned && selected2) });
63855
63790
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: rs.rowShell, ...leaving ? { "data-leaving": leaving } : {}, children: [
63856
63791
  narrow ? /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { px: "14px", py: "10px", children: [
63857
63792
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { display: "flex", justifyContent: "space-between", alignItems: "baseline", children: [
@@ -63875,7 +63810,7 @@ const Row = React.memo(function Row2({ decision, handle, selected: selected2, na
63875
63810
  selected2 && /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { px: narrow ? "14px" : "18px", py: "12px", borderTopWidth: "1px", borderColor: "border.subtle", bg: "bg.canvas", children: [
63876
63811
  facet === "evidence" && /* @__PURE__ */ jsxRuntime.jsx(EvidenceFacet, { decision, children: canvas != null && /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraComponent, { value: canvas, storageKey: `${storageKey}-evidence-${decision.id}` }) }),
63877
63812
  facet === "options" && /* @__PURE__ */ jsxRuntime.jsx(OptionsFacet, { decision, narrow }),
63878
- facet === "judgement" && /* @__PURE__ */ jsxRuntime.jsx(JudgementFacet, { decision, handle, leverPayloads }),
63813
+ facet === "judgement" && /* @__PURE__ */ jsxRuntime.jsx(JudgementFacet, { decision, handle, contract }),
63879
63814
  facet === "modify" && probe != null && /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.EastChakraComponent, { value: probe, storageKey: `${storageKey}-modify-${decision.id}` })
63880
63815
  ] })
63881
63816
  ] });
@@ -63884,6 +63819,7 @@ const RoutineGroup = React.memo(function RoutineGroup2({ routine, acceptAll, lea
63884
63819
  const dq = react.useSlotRecipe({ key: "decisionQueue" });
63885
63820
  const status = react.useSlotRecipe({ key: "status" });
63886
63821
  const button = react.useRecipe({ key: "button" });
63822
+ const words = eastUiComponents.useFormatters();
63887
63823
  const rs = dq({});
63888
63824
  const st = status({ status: "neutral", size: "md" });
63889
63825
  const total = React.useMemo(() => routine.reduce((acc, d2) => acc + d2.value, 0), [routine]);
@@ -63905,15 +63841,15 @@ const RoutineGroup = React.memo(function RoutineGroup2({ routine, acceptAll, lea
63905
63841
  d2.kind
63906
63842
  ] })
63907
63843
  ] }),
63908
- /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: rs.routineValue, children: decisionValue(d2, d2.value) })
63844
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: rs.routineValue, children: decisionValue(words, d2, d2.value) })
63909
63845
  ] }) }, d2.id)),
63910
63846
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: rs.summary, ...narrow ? { marginLeft: "0", flexWrap: "wrap" } : {}, children: [
63911
63847
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: rs.summaryCap, children: [
63912
- routine.length,
63848
+ words.number(routine.length),
63913
63849
  " routine"
63914
63850
  ] }),
63915
63851
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.subtle", children: "·" }),
63916
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: eastUiComponents.formatTick(total, format2) }),
63852
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: words.value(total, format2) }),
63917
63853
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.muted", children: "total" }),
63918
63854
  acceptAll && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "button", css: button({ variant: "solid", size: "xs" }), ml: "auto", onClick: handleAcceptAll, children: "Accept all" })
63919
63855
  ] })
@@ -63922,6 +63858,7 @@ const RoutineGroup = React.memo(function RoutineGroup2({ routine, acceptAll, lea
63922
63858
  const GroupHead = React.memo(function GroupHead2({ group: group2, collapsible, collapsed, onToggle, acceptAll }) {
63923
63859
  const dq = react.useSlotRecipe({ key: "decisionQueue" });
63924
63860
  const button = react.useRecipe({ key: "button" });
63861
+ const words = eastUiComponents.useFormatters();
63925
63862
  const rs = dq({});
63926
63863
  const format2 = group2.decisions[0] ? eastUiComponents.getSomeorUndefined(group2.decisions[0].format) : void 0;
63927
63864
  const handleToggle = React.useCallback(() => {
@@ -63936,11 +63873,11 @@ const GroupHead = React.memo(function GroupHead2({ group: group2, collapsible, c
63936
63873
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: rs.groupLabel, children: [
63937
63874
  group2.label,
63938
63875
  " · ",
63939
- group2.decisions.length
63876
+ words.number(group2.decisions.length)
63940
63877
  ] }),
63941
63878
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", css: rs.groupSummary, children: [
63942
- eastUiComponents.formatTick(group2.total, format2),
63943
- group2.pastSla > 0 ? ` · ${group2.pastSla} past SLA` : ""
63879
+ words.value(group2.total, format2),
63880
+ group2.pastSla > 0 ? ` · ${words.number(group2.pastSla)} past SLA` : ""
63944
63881
  ] }),
63945
63882
  acceptAll && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "button", css: button({ variant: "solid", size: "xs" }), onClick: handleAcceptAll, children: "Accept all" })
63946
63883
  ] });
@@ -63952,10 +63889,11 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
63952
63889
  const dq = react.useSlotRecipe({ key: "decisionQueue" });
63953
63890
  const qs = dq({});
63954
63891
  const chip = react.useRecipe({ key: "chip" });
63892
+ const words = eastUiComponents.useFormatters();
63955
63893
  const handleRef = value.handle;
63956
63894
  const handle = useDecisionHandle(handleRef);
63957
63895
  const decisions = handle.decisions;
63958
- const leverPayloads = useLeverPayloads(handleRef);
63896
+ const contract = useConstraintContract(handleRef);
63959
63897
  const railAffordances = eastUiComponents.getSomeorUndefined(value.affordances);
63960
63898
  const sliceHandle = eastUiComponents.getSomeorUndefined(value.slice) ?? null;
63961
63899
  eastUiComponents.useSliceReactivity(sliceHandle == null ? void 0 : sliceHandle.key);
@@ -63995,14 +63933,8 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
63995
63933
  const heading = eastUiComponents.getSomeorUndefined(value.heading) ?? "Decisions waiting";
63996
63934
  const onApply = React.useMemo(() => eastUiComponents.getSomeorUndefined(value.onApply), [value.onApply]);
63997
63935
  const onReject = React.useMemo(() => eastUiComponents.getSomeorUndefined(value.onReject), [value.onReject]);
63998
- const modify = React.useMemo(
63999
- () => eastUiComponents.getSomeorUndefined(value.modify),
64000
- [value.modify]
64001
- );
64002
- const evidence = React.useMemo(
64003
- () => eastUiComponents.getSomeorUndefined(value.evidence),
64004
- [value.evidence]
64005
- );
63936
+ const modify = React.useMemo(() => eastUiComponents.getSomeorUndefined(value.modify), [value.modify]);
63937
+ const evidence = React.useMemo(() => eastUiComponents.getSomeorUndefined(value.evidence), [value.evidence]);
64006
63938
  const defaultFacet = ((_a2 = eastUiComponents.getSomeorUndefined(value.defaultFacet)) == null ? void 0 : _a2.type) ?? "evidence";
64007
63939
  const facetInclude = React.useMemo(() => {
64008
63940
  const facets = eastUiComponents.getSomeorUndefined(value.facets);
@@ -64051,15 +63983,7 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
64051
63983
  for (const { decision } of exiting.values()) {
64052
63984
  if (!merged2.some((d2) => d2.id === decision.id)) merged2.push(decision);
64053
63985
  }
64054
- merged2.sort((a2, b2) => {
64055
- var _a3, _b2;
64056
- const r2 = URGENCY_RANK[a2.urgency.type] - URGENCY_RANK[b2.urgency.type];
64057
- if (r2 !== 0) return r2;
64058
- const da = ((_a3 = eastUiComponents.getSomeorUndefined(a2.deadline)) == null ? void 0 : _a3.getTime()) ?? Infinity;
64059
- const db = ((_b2 = eastUiComponents.getSomeorUndefined(b2.deadline)) == null ? void 0 : _b2.getTime()) ?? Infinity;
64060
- if (da !== db) return da - db;
64061
- return b2.value - a2.value;
64062
- });
63986
+ merged2.sort(compareByUrgency);
64063
63987
  return {
64064
63988
  merged: merged2,
64065
63989
  active: merged2.filter((d2) => d2.urgency.type !== "routine"),
@@ -64098,7 +64022,7 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
64098
64022
  handle,
64099
64023
  selected: selectedId === d2.id,
64100
64024
  narrow,
64101
- leverPayloads,
64025
+ contract,
64102
64026
  modify,
64103
64027
  evidence,
64104
64028
  defaultFacet,
@@ -64125,13 +64049,13 @@ const EastChakraDecisionQueue = React.memo(function EastChakraDecisionQueue2({ v
64125
64049
  ) }),
64126
64050
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: es.meta, gap: "10px", children: [
64127
64051
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", children: [
64128
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg", fontWeight: "semibold", children: visible }),
64052
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg", fontWeight: "semibold", children: words.number(visible) }),
64129
64053
  narrow ? "" : " decisions"
64130
64054
  ] }),
64131
64055
  pastSla > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
64132
64056
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { as: "span", css: es.sep, children: "·" }),
64133
64057
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { as: "span", children: [
64134
- /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.danger", fontWeight: "semibold", children: pastSla }),
64058
+ /* @__PURE__ */ jsxRuntime.jsx(react.Text, { as: "span", color: "fg.danger", fontWeight: "semibold", children: words.number(pastSla) }),
64135
64059
  narrow ? " SLA" : " past SLA"
64136
64060
  ] })
64137
64061
  ] })
@@ -64193,34 +64117,24 @@ function verdictPresentation(verdict) {
64193
64117
  return { tone: "warning", verb: "handed off", detail: verdict.value !== "" ? verdict.value : null };
64194
64118
  }
64195
64119
  }
64196
- function formatResolvedAt(j2) {
64120
+ function formatResolvedAt(j2, words) {
64197
64121
  if (j2.resolvedAt.type !== "some") return null;
64198
64122
  const d2 = j2.resolvedAt.value;
64199
- const month = d2.toLocaleString("en", { month: "short" });
64200
- const time2 = `${String(d2.getHours()).padStart(2, "0")}:${String(d2.getMinutes()).padStart(2, "0")}`;
64201
- return `${month} ${d2.getDate()} · ${time2}`;
64123
+ return `${words.monthDay(d2)} · ${words.time(d2)}`;
64202
64124
  }
64203
64125
  const EastChakraDecisionJournal = React.memo(function EastChakraDecisionJournal2({ value }) {
64204
64126
  const eyebrow = react.useSlotRecipe({ key: "eyebrowRow" });
64205
64127
  const status = react.useSlotRecipe({ key: "status" });
64206
64128
  const es = eyebrow({});
64129
+ const words = eastUiComponents.useFormatters();
64207
64130
  const handle = useDecisionHandle(value.handle);
64208
64131
  const heading = eastUiComponents.getSomeorUndefined(value.heading) ?? "Decision journal";
64209
- const cache3 = getReactiveDatasetCache();
64210
- const workspace = cache3.getConfig().workspace ?? "";
64211
- const leverPayloads = React.useMemo(() => {
64212
- var _a2, _b2, _c2;
64213
- const judgements = getBindingTypes(workspace, value.handle.judgements.source);
64214
- if (!(judgements == null ? void 0 : judgements.sourceType)) return {};
64215
- const root2 = normalizeTypeValue(judgements.sourceType);
64216
- const constraint = (_c2 = (_b2 = (_a2 = root2.value) == null ? void 0 : _a2.fields) == null ? void 0 : _b2["constraints"]) == null ? void 0 : _c2.value;
64217
- return (constraint == null ? void 0 : constraint.type) === "Variant" ? constraint.cases ?? {} : {};
64218
- }, [workspace, value.handle]);
64132
+ const contract = useConstraintContract(value.handle);
64219
64133
  const entries = React.useMemo(() => handle.journal ?? [], [handle.journal]);
64220
64134
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { borderWidth: "1px", borderColor: "border.strong", borderRadius: "6px", background: "bg.canvas", overflow: "hidden", children: [
64221
64135
  /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { css: es.root, children: [
64222
64136
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: es.lbl, children: heading }),
64223
- /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: es.meta, children: entries.length === 1 ? "1 entry" : `${entries.length} entries` })
64137
+ /* @__PURE__ */ jsxRuntime.jsx(react.Box, { css: es.meta, children: entries.length === 1 ? "1 entry" : `${words.number(entries.length)} entries` })
64224
64138
  ] }),
64225
64139
  /* @__PURE__ */ jsxRuntime.jsx(
64226
64140
  react.Box,
@@ -64232,7 +64146,7 @@ const EastChakraDecisionJournal = React.memo(function EastChakraDecisionJournal2
64232
64146
  if (!verdict) return null;
64233
64147
  const { tone, verb, detail } = verdictPresentation(verdict);
64234
64148
  const st = status({ status: tone, size: "md" });
64235
- const when = formatResolvedAt(j2);
64149
+ const when = formatResolvedAt(j2, words);
64236
64150
  const knowledge = j2.knowledge.type === "some" && j2.knowledge.value !== "" ? j2.knowledge.value : null;
64237
64151
  return /* @__PURE__ */ jsxRuntime.jsxs(
64238
64152
  react.Box,
@@ -64271,8 +64185,7 @@ const EastChakraDecisionJournal = React.memo(function EastChakraDecisionJournal2
64271
64185
  }
64272
64186
  ),
64273
64187
  j2.constraints.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Box, { display: "flex", gap: "12px", flexWrap: "wrap", children: j2.constraints.map((c2, k2) => {
64274
- const tag = c2.type;
64275
- const f2 = formatConstraint(c2, leverPayloads[tag]);
64188
+ const f2 = formatConstraint(c2, contract, void 0, words);
64276
64189
  return /* @__PURE__ */ jsxRuntime.jsx(eastUiComponents.ClauseChip, { field: f2.lever, op: f2.op, value: f2.value }, k2);
64277
64190
  }) })
64278
64191
  ]
@@ -64811,6 +64724,10 @@ function pagingDebug(...args) {
64811
64724
  console.info("[e3-paging]", ...args);
64812
64725
  }
64813
64726
  const PAGE_SIZE = 500;
64727
+ function servedPageSize(requested, page) {
64728
+ const trimmed = page.count < requested && page.offset + page.count < page.totalElements;
64729
+ return trimmed ? Math.max(1, page.count) : requested;
64730
+ }
64814
64731
  const MAX_RETAINED_PAGES = 8;
64815
64732
  function pageRows(type, decoded, offset) {
64816
64733
  if (type.type === "Array") {
@@ -64850,6 +64767,7 @@ const PagedDatasetPreview = React.memo(function PagedDatasetPreview2({
64850
64767
  onDownload,
64851
64768
  onNotIndexed
64852
64769
  }) {
64770
+ const words = eastUiComponents.useFormatters();
64853
64771
  const queryClient = reactQuery.useQueryClient();
64854
64772
  const [pages, setPages] = React.useState(/* @__PURE__ */ new Map());
64855
64773
  const [totals, setTotals] = React.useState(null);
@@ -64858,6 +64776,8 @@ const PagedDatasetPreview = React.memo(function PagedDatasetPreview2({
64858
64776
  const [jumpRow, setJumpRow] = React.useState(void 0);
64859
64777
  const inflightRef = React.useRef(/* @__PURE__ */ new Set());
64860
64778
  const shownRef = React.useRef({ path: path2, hash: hash2 });
64779
+ const [pageSize, setPageSize] = React.useState(PAGE_SIZE);
64780
+ const pageSizeRef = React.useRef(PAGE_SIZE);
64861
64781
  React.useEffect(() => {
64862
64782
  pagingDebug(`reset (path=${path2}, hash=${hash2.slice(0, 8)})`);
64863
64783
  shownRef.current = { path: path2, hash: hash2 };
@@ -64866,36 +64786,45 @@ const PagedDatasetPreview = React.memo(function PagedDatasetPreview2({
64866
64786
  setError(null);
64867
64787
  setJumpRow(void 0);
64868
64788
  inflightRef.current = /* @__PURE__ */ new Set();
64789
+ pageSizeRef.current = PAGE_SIZE;
64790
+ setPageSize(PAGE_SIZE);
64869
64791
  }, [path2, hash2]);
64870
64792
  const loadPage = React.useCallback((pageIdx) => {
64871
64793
  const inflight = inflightRef.current;
64872
64794
  if (inflight.has(pageIdx)) return;
64873
64795
  inflight.add(pageIdx);
64874
64796
  const current = () => shownRef.current.path === path2 && shownRef.current.hash === hash2;
64797
+ const size3 = pageSizeRef.current;
64875
64798
  setLoadingCount((n2) => n2 + 1);
64876
- pagingDebug(`fetch p${pageIdx} (offset=${pageIdx * PAGE_SIZE}, limit=${PAGE_SIZE}, hash=${hash2.slice(0, 8)})`);
64799
+ pagingDebug(`fetch p${pageIdx} (offset=${pageIdx * size3}, limit=${size3}, hash=${hash2.slice(0, 8)})`);
64877
64800
  const pathParts2 = path2.split(".").filter(Boolean).map((v3) => east.variant("field", v3));
64878
64801
  const reqOpts = requestOptions ?? { token: null };
64879
64802
  queryClient.fetchQuery({
64880
- queryKey: ["datasetPage", apiUrl, repo, workspace, path2, hash2, `p${pageIdx}`],
64803
+ queryKey: ["datasetPage", apiUrl, repo, workspace, path2, hash2, `p${pageIdx}@${size3}`],
64881
64804
  // Hash-pinned: the URL is a pure function of the bytes, so any
64882
64805
  // HTTP cache between here and the server can hold it immutably.
64883
- queryFn: () => e3ApiClient.datasetGetPage(apiUrl, repo, workspace, pathParts2, { offset: pageIdx * PAGE_SIZE, limit: PAGE_SIZE, hash: hash2 }, reqOpts),
64806
+ queryFn: () => e3ApiClient.datasetGetPage(apiUrl, repo, workspace, pathParts2, { offset: pageIdx * size3, limit: size3, hash: hash2 }, reqOpts),
64884
64807
  staleTime: Infinity
64885
64808
  // pages of one content hash are immutable
64886
64809
  }).then((page) => {
64887
64810
  if (!current()) return;
64811
+ if (size3 !== pageSizeRef.current) return;
64888
64812
  const decoded = east.decodeBeast2For(type)(page.data);
64889
64813
  const rows = pageRows(type, decoded, page.offset);
64890
64814
  pagingDebug(
64891
64815
  `p${pageIdx} ok: count=${page.count} rows=${rows.length} offset=${page.offset} total=${page.totalElements} segs=${page.segmentCount}`,
64892
64816
  rows.length > 0 ? `first=${JSON.stringify(rows[0].label ?? "(derived)")}` : "(empty)"
64893
64817
  );
64894
- if (page.count < PAGE_SIZE && page.offset + page.count < page.totalElements) {
64895
- pagingDebug(`p${pageIdx} SHORT page: server clamped ${PAGE_SIZE} → ${page.count}`);
64896
- }
64897
64818
  setTotals({ elements: page.totalElements, bytes: page.totalBytes });
64898
- setPages((prev2) => new Map(prev2).set(pageIdx, rows));
64819
+ const served = servedPageSize(size3, page);
64820
+ if (served === size3) {
64821
+ setPages((prev2) => new Map(prev2).set(pageIdx, rows));
64822
+ return;
64823
+ }
64824
+ pagingDebug(`p${pageIdx} SHORT page: served ${page.count} of ${size3} — addressing pages by ${served}`);
64825
+ pageSizeRef.current = served;
64826
+ setPageSize(served);
64827
+ setPages(pageIdx === 0 ? /* @__PURE__ */ new Map([[0, rows]]) : /* @__PURE__ */ new Map());
64899
64828
  }).catch((err) => {
64900
64829
  pagingDebug(`p${pageIdx} FAILED:`, err);
64901
64830
  if (!current()) return;
@@ -64916,8 +64845,8 @@ const PagedDatasetPreview = React.memo(function PagedDatasetPreview2({
64916
64845
  if (totals === null && error3 === null) loadPage(0);
64917
64846
  }, [totals, error3, loadPage]);
64918
64847
  const onNeedRows = React.useCallback((startRow, endRow) => {
64919
- const first2 = Math.max(0, Math.floor(startRow / PAGE_SIZE));
64920
- const last2 = Math.max(first2, Math.ceil(endRow / PAGE_SIZE) - 1);
64848
+ const first2 = Math.max(0, Math.floor(startRow / pageSize));
64849
+ const last2 = Math.max(first2, Math.ceil(endRow / pageSize) - 1);
64921
64850
  const missing = [];
64922
64851
  for (let p2 = first2; p2 <= last2; p2++) {
64923
64852
  if (!pages.has(p2)) missing.push(p2);
@@ -64925,7 +64854,7 @@ const PagedDatasetPreview = React.memo(function PagedDatasetPreview2({
64925
64854
  pagingDebug(`need rows [${startRow}, ${endRow}) → pages ${first2}..${last2}, missing=[${missing.join(",")}], inflight=[${[...inflightRef.current].join(",")}]`);
64926
64855
  setPages((prev2) => internal$2.pruneRetainedPages(prev2, first2, last2, MAX_RETAINED_PAGES));
64927
64856
  for (const p2 of missing) loadPage(p2);
64928
- }, [pages, loadPage]);
64857
+ }, [pages, loadPage, pageSize]);
64929
64858
  const keyType = React.useMemo(() => type.type === "Dict" ? type.value.key : type.type === "Set" ? type.value : null, [type]);
64930
64859
  const pathParts = React.useMemo(() => path2.split(".").filter(Boolean).map((v3) => east.variant("field", v3)), [path2]);
64931
64860
  const onFindKey = React.useCallback(async (query) => {
@@ -64962,11 +64891,11 @@ const PagedDatasetPreview = React.memo(function PagedDatasetPreview2({
64962
64891
  }), [type]);
64963
64892
  const paging = React.useMemo(() => totals === null ? null : {
64964
64893
  totalRows: totals.elements,
64965
- pageSize: PAGE_SIZE,
64894
+ pageSize,
64966
64895
  pages,
64967
64896
  onNeedRows,
64968
64897
  scrollToRow: jumpRow
64969
- }, [totals, pages, onNeedRows, jumpRow]);
64898
+ }, [totals, pageSize, pages, onNeedRows, jumpRow]);
64970
64899
  if (error3 !== null) {
64971
64900
  if (error3 instanceof e3ApiClient.ApiError && error3.code === "dataset_too_large") {
64972
64901
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { height: "100%", direction: "column", align: "center", justify: "center", gap: 3, p: 6, children: [
@@ -64984,11 +64913,11 @@ const PagedDatasetPreview = React.memo(function PagedDatasetPreview2({
64984
64913
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { direction: "column", height: "100%", overflow: "hidden", children: [
64985
64914
  /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { px: 4, py: 2, gap: 2, align: "center", flexShrink: 0, borderBottom: "1px solid", borderColor: "border.subtle", children: [
64986
64915
  /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { fontSize: "xs", color: "fg.muted", whiteSpace: "nowrap", children: [
64987
- totals.elements.toLocaleString(),
64916
+ words.number(totals.elements),
64988
64917
  " ",
64989
64918
  itemNoun,
64990
64919
  " · ",
64991
- formatSize(totals.bytes > 0 ? totals.bytes : sizeBytes)
64920
+ formatSize(totals.bytes > 0 ? totals.bytes : sizeBytes, words)
64992
64921
  ] }),
64993
64922
  loadingCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "xs", color: "fg.muted", children: "Loading…" }),
64994
64923
  keyType !== null && /* @__PURE__ */ jsxRuntime.jsx(
@@ -65010,10 +64939,12 @@ const PagedDatasetPreview = React.memo(function PagedDatasetPreview2({
65010
64939
  return prev2.apiUrl === next2.apiUrl && prev2.repo === next2.repo && prev2.workspace === next2.workspace && prev2.path === next2.path && prev2.hash === next2.hash && prev2.sizeBytes === next2.sizeBytes && ((_a2 = prev2.requestOptions) == null ? void 0 : _a2.token) === ((_b2 = next2.requestOptions) == null ? void 0 : _b2.token);
65011
64940
  });
65012
64941
  const DEFAULT_SIZE_LIMIT = 200 * 1024;
65013
- function formatSize(bytes) {
65014
- if (bytes < 1024) return `${bytes} B`;
65015
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
65016
- return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
64942
+ const KB_FORMAT = east.variant("number", { minimumFractionDigits: east.some(1n), maximumFractionDigits: east.some(1n), signDisplay: east.none });
64943
+ const MB_FORMAT = east.variant("number", { minimumFractionDigits: east.some(2n), maximumFractionDigits: east.some(2n), signDisplay: east.none });
64944
+ function formatSize(bytes, words = eastUiComponents.formatters()) {
64945
+ if (bytes < 1024) return `${words.number(bytes)} B`;
64946
+ if (bytes < 1024 * 1024) return `${words.value(bytes / 1024, KB_FORMAT)} KB`;
64947
+ return `${words.value(bytes / 1024 / 1024, MB_FORMAT)} MB`;
65017
64948
  }
65018
64949
  function DownloadButton({ onClick, label }) {
65019
64950
  const [downloading, setDownloading] = React.useState(false);
@@ -65041,6 +64972,7 @@ const DatasetPreview = React.memo(function DatasetPreview2({
65041
64972
  editable = false
65042
64973
  }) {
65043
64974
  var _a2;
64975
+ const words = eastUiComponents.useFormatters();
65044
64976
  const statusQuery = useDatasetStatus(apiUrl, repo, workspace, path2, {
65045
64977
  ...requestOptions != null && { requestOptions },
65046
64978
  ...pollInterval !== void 0 && { pollInterval }
@@ -65165,9 +65097,9 @@ const DatasetPreview = React.memo(function DatasetPreview2({
65165
65097
  /* @__PURE__ */ jsxRuntime.jsx(react.Text, { fontSize: "lg", color: "fg.warning", fontWeight: "bold", children: "Value too large to display" }),
65166
65098
  /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { color: "fg.muted", fontSize: "sm", children: [
65167
65099
  "The data is ",
65168
- formatSize(sizeBytes),
65100
+ formatSize(sizeBytes, words),
65169
65101
  ", which exceeds the ",
65170
- formatSize(sizeLimit),
65102
+ formatSize(sizeLimit, words),
65171
65103
  " display limit."
65172
65104
  ] }),
65173
65105
  /* @__PURE__ */ jsxRuntime.jsx(DownloadButton, { onClick: download, label: "Download value" })
@@ -65179,7 +65111,7 @@ const DatasetPreview = React.memo(function DatasetPreview2({
65179
65111
  }
65180
65112
  if (valueQuery.isLoading || !valueQuery.data) return /* @__PURE__ */ jsxRuntime.jsx(StatusDisplay, { variant: "loading", title: "Loading..." });
65181
65113
  const count = type === void 0 || decoded === void 0 ? null : type.type === "Array" ? decoded.length : type.type === "Set" || type.type === "Dict" ? decoded.size : null;
65182
- const countText = count === null ? "" : `${count.toLocaleString()} ${(type == null ? void 0 : type.type) === "Dict" ? "entries" : "items"} · `;
65114
+ const countText = count === null ? "" : `${words.number(count)} ${(type == null ? void 0 : type.type) === "Dict" ? "entries" : "items"} · `;
65183
65115
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { direction: "column", height: "100%", overflow: "hidden", children: [
65184
65116
  /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { px: 4, py: 2, gap: 2, align: "center", flexShrink: 0, borderBottom: "1px solid", borderColor: "border.subtle", children: [
65185
65117
  keyType !== null && inlineKeys !== null && /* @__PURE__ */ jsxRuntime.jsx(
@@ -65195,7 +65127,7 @@ const DatasetPreview = React.memo(function DatasetPreview2({
65195
65127
  /* @__PURE__ */ jsxRuntime.jsxs(react.Flex, { flex: 1, justify: "flex-end", align: "center", gap: 2, children: [
65196
65128
  /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { fontSize: "xs", color: "fg.muted", children: [
65197
65129
  countText,
65198
- formatSize(sizeBytes)
65130
+ formatSize(sizeBytes, words)
65199
65131
  ] }),
65200
65132
  /* @__PURE__ */ jsxRuntime.jsx(DownloadButton, { onClick: download })
65201
65133
  ] })
@@ -65865,31 +65797,11 @@ const TaskPreview = React.memo(function TaskPreview2({
65865
65797
  return prev2.task === next2.task && prev2.apiUrl === next2.apiUrl && prev2.repo === next2.repo && prev2.workspace === next2.workspace && prev2.bare === next2.bare && ((_a2 = prev2.requestOptions) == null ? void 0 : _a2.token) === ((_b2 = next2.requestOptions) == null ? void 0 : _b2.token);
65866
65798
  });
65867
65799
  function formatPrimitive(type, value) {
65868
- switch (type.type) {
65869
- case "Null":
65870
- return "null";
65871
- case "Boolean":
65872
- return value ? "true" : "false";
65873
- case "Integer":
65874
- return String(value);
65875
- case "Float": {
65876
- const num2 = value;
65877
- if (Number.isNaN(num2)) return "NaN";
65878
- if (!Number.isFinite(num2)) return num2 > 0 ? "Infinity" : "-Infinity";
65879
- return String(num2);
65880
- }
65881
- case "String":
65882
- return `"${value}"`;
65883
- case "DateTime":
65884
- return value.toISOString();
65885
- case "Blob":
65886
- return `Blob[${value.length} bytes]`;
65887
- default:
65888
- return String(value);
65889
- }
65800
+ if (type.type === "Blob") return `Blob[${value.length} bytes]`;
65801
+ return east.printFor(type)(value);
65890
65802
  }
65891
65803
  function isPrimitive(type) {
65892
- return ["Null", "Boolean", "Integer", "Float", "String", "DateTime", "Blob", "Never"].includes(type.type);
65804
+ return ["Null", "Boolean", "Integer", "Float", "String", "DateTime", "Blob"].includes(type.type);
65893
65805
  }
65894
65806
  function getTypeLabel(type, value) {
65895
65807
  switch (type.type) {
@@ -66011,8 +65923,8 @@ function ValueNode({
66011
65923
  }
66012
65924
  if (type.type === "Variant") {
66013
65925
  const cases = type.value;
66014
- const variant = value;
66015
- const activeCase = cases.find((c2) => c2.name === variant.type);
65926
+ const chosen = value;
65927
+ const activeCase = cases.find((c2) => c2.name === chosen.type);
66016
65928
  if (!activeCase) {
66017
65929
  return /* @__PURE__ */ jsxRuntime.jsxs(react.Box, { py: 0.5, display: "flex", alignItems: "center", gap: 2, children: [
66018
65930
  label && /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { as: "span", color: "accent.purple", fontWeight: "medium", children: [
@@ -66021,7 +65933,7 @@ function ValueNode({
66021
65933
  ] }),
66022
65934
  /* @__PURE__ */ jsxRuntime.jsxs(react.Text, { as: "span", color: "fg.danger", children: [
66023
65935
  "Unknown variant: ",
66024
- variant.type
65936
+ chosen.type
66025
65937
  ] })
66026
65938
  ] });
66027
65939
  }
@@ -66033,7 +65945,7 @@ function ValueNode({
66033
65945
  ] }),
66034
65946
  /* @__PURE__ */ jsxRuntime.jsxs(react.Badge, { size: "xs", colorPalette: "brand", variant: "subtle", children: [
66035
65947
  ".",
66036
- variant.type
65948
+ chosen.type
66037
65949
  ] })
66038
65950
  ] });
66039
65951
  }
@@ -66045,14 +65957,14 @@ function ValueNode({
66045
65957
  ] }),
66046
65958
  /* @__PURE__ */ jsxRuntime.jsxs(react.Badge, { size: "xs", colorPalette: "brand", variant: "subtle", children: [
66047
65959
  ".",
66048
- variant.type
65960
+ chosen.type
66049
65961
  ] })
66050
65962
  ] }),
66051
65963
  /* @__PURE__ */ jsxRuntime.jsx(react.Box, { pl: 4, children: /* @__PURE__ */ jsxRuntime.jsx(
66052
65964
  ValueNode,
66053
65965
  {
66054
65966
  type: activeCase.type,
66055
- value: variant.value,
65967
+ value: chosen.value,
66056
65968
  depth: depth + 1
66057
65969
  }
66058
65970
  ) })