@elaraai/e3-ui-components 1.0.80 → 1.0.82

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.js CHANGED
@@ -18,18 +18,18 @@ var __privateWrapper = (obj, member, setter, getter) => ({
18
18
  }
19
19
  });
20
20
  var _focused, _cleanup, _setup, _a, _provider, _providerCalled, _b, _online, _cleanup2, _setup2, _c, _gcTimeout, _d, _initialState, _revertState, _cache, _client, _retryer, _defaultOptions, _abortSignalConsumed, _Query_instances, isInitialPausedFetch_fn, dispatch_fn, _e, _client2, _observers, _mutationCache, _retryer2, _Mutation_instances, dispatch_fn2, _f, _mutations, _scopes, _mutationId, _g, _queries, _h, _queryCache, _mutationCache2, _defaultOptions2, _queryDefaults, _mutationDefaults, _mountCount, _unsubscribeFocus, _unsubscribeOnline, _i, _j;
21
- import { variant, SortedMap, compareFor, EastError, fromEastTypeValue, East, none as none$1, some, OptionType, BooleanType, NullType, ConflictError, equalFor, toEastTypeValue, PatchType, diffFor, applyFor, encodeBeast2For, decodeBeast2For, BlobType, StringType, IntegerType, StructType, walkPatch, pathToString, pathDisplay, printFor, isVariant, prunePatchFor, detectConflictsFor, mergeWithResolutionsFor, validatePatchFor, isEastSet, isEastDict, ArrayType, parseFor } from "@elaraai/east";
22
- import { EastTypeType } from "@elaraai/east/internal";
21
+ import { variant, SortedMap, compareFor, EastError, fromEastTypeValue, East, none as none$1, some, OptionType, BooleanType, NullType, ConflictError, equalFor, toEastTypeValue, PatchType, diffFor, applyFor, encodeBeast2For, decodeBeast2For, BlobType, StringType, IntegerType, isTypeValueEqual, StructType, walkPatch, pathToString, pathDisplay, parseFor, printFor, FloatType, equivalentFor, prunePatchFor, detectConflictsFor, mergeWithResolutionsFor, validatePatchFor, canonicalTypeValue, ArrayType, EastTypeValueType, defaultValue, DateTimeType } from "@elaraai/east";
22
+ import { EastTypeType, formatDateTime, parseDateTimeFormatted, tokenizeDateTimeFormat } from "@elaraai/east/internal";
23
23
  import { DataBindModeType, DataBindPrimitives, bindPlatformFn, DataPagedPrimitives, bindPagedPlatformFn, bindPagedPinnedPlatformFn, FuncBindPrimitives, FuncErrorType, FuncStatusType, funcBindPlatformFn, RecordBindPrimitives, recordBindPlatformFn, Diff, Ontology, FuncBindHandleType, Experiment, decisionBindPlatformFn, DecisionBindPrimitives, DecisionConstraintType, DiffBindingType, CommitStateType, VerdictType, AnswerType, judgementInputType, DecisionType, DecisionQueue, DecisionJournal } from "@elaraai/e3-ui/internal";
24
24
  import { registerReactiveTracker, registerPlatformImplementation, StateRuntime, getRegisteredPlatformImplementations, boundSliceConfig } from "@elaraai/east-ui-components/platform";
25
- import { TreePathType, DatasetStatusType } from "@elaraai/e3-types";
25
+ import { TreePathType, DatasetStatusType, pathToString as pathToString$1 } from "@elaraai/e3-types";
26
26
  import { workspaceStatus, datasetListAt, datasetList, dataflowExecuteLaunch, datasetSet, datasetGet, ApiError, DatasetHashMismatchError, datasetGetStatus, datasetFindKey, datasetGetPage, workspaceFunctionCall, workspaceFunctionList, workspaceRecordHistory, workspaceRecordMutate, workspaceRecordDescribe, repoCreate, repoGc, repoGcStart, repoGcStatus, repoList, repoRemove, repoStatus, packageExport, packageGet, packageImport, packageList, packageRemove, workspaceCreate, workspaceDeploy, workspaceExport, workspaceGet, workspaceList, workspaceRemove, datasetListRecursive, datasetListRecursivePaths, datasetListWithStatus, taskExecutionList, taskGet, taskList, dataflowCancel, dataflowExecute, dataflowExecutePoll, dataflowGraph, taskLogs } from "@elaraai/e3-api-client";
27
- import { SeekQueryType, SeekRangeType, ValueTree } from "@elaraai/east-ui";
27
+ import { SeekQueryType, SeekRangeType, slicePredicateMatches, ValueTree } from "@elaraai/east-ui";
28
28
  import { jsx as jsx$1, Fragment, jsxs } from "react/jsx-runtime";
29
29
  import * as React from "react";
30
30
  import React__default, { useId, useMemo, useContext, createContext, useRef, useState, useEffect, useCallback, useSyncExternalStore, memo, forwardRef, useLayoutEffect, Fragment as Fragment$1, Component } from "react";
31
31
  import { Box, Flex, Text, HStack, Input, useSlotRecipe, useRecipe, VStack, useToken, Drawer, Portal, Field, NativeSelect, Textarea, chakra, Tooltip, SegmentGroup, Menu, HoverCard, useChakraContext, Spinner, Code, Clipboard, IconButton, Button, Tabs, Badge, useTabs } from "@chakra-ui/react";
32
- import { implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, useContainerBelow, usePersistedState, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, NavImpl, SliceImpl, SliceApplyImpl, OverlayImpl, ClipboardImpl, DownloadImpl, ShareImpl, LoadingIcon, DatasetKeySearch, EastChakraValueTree, keyRangePredicates, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
32
+ import { formatters, useFormatters, useDataStable, implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, useSliceReactivity, useContainerBelow, usePersistedState, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, NavImpl, SliceImpl, SliceApplyImpl, OverlayImpl, ClipboardImpl, DownloadImpl, ShareImpl, LoadingIcon, DatasetKeySearch, EastChakraValueTree, keyRangePredicates, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
33
33
  import { DatasetKeySearch as DatasetKeySearch2 } from "@elaraai/east-ui-components";
34
34
  import { createPortal } from "react-dom";
35
35
  import { sliceMatches, pruneRetainedPages } from "@elaraai/east-ui/internal";
@@ -2981,7 +2981,7 @@ function clearStagedStoreSingleton() {
2981
2981
  }
2982
2982
  const UNCHANGED_VARIANT = variant("unchanged", null);
2983
2983
  const blobEqual = equalFor(BlobType);
2984
- const eastTypeEqual$2 = equalFor(EastTypeType);
2984
+ const eastTypeEqual$1 = equalFor(EastTypeType);
2985
2985
  const helpersCache = new SortedMap(
2986
2986
  void 0,
2987
2987
  compareFor(EastTypeType)
@@ -3190,11 +3190,11 @@ class BindRuntime {
3190
3190
  const key = datasetCacheKey(workspace, sourcePath);
3191
3191
  const existing = this.bindingRegistry.get(key);
3192
3192
  if (existing) {
3193
- if (existing.mode === info.mode && existing.hasPatchDataset === info.hasPatchDataset && existing.sourceType === info.sourceType) {
3193
+ if (existing.mode === info.mode && existing.hasPatchDataset === info.hasPatchDataset && Object.is(existing.sourceType, info.sourceType)) {
3194
3194
  return;
3195
3195
  }
3196
3196
  const shapeChanged = existing.mode !== info.mode || existing.hasPatchDataset !== info.hasPatchDataset;
3197
- const typeChanged = !eastTypeEqual$2(existing.sourceType, info.sourceType);
3197
+ const typeChanged = !eastTypeEqual$1(existing.sourceType, info.sourceType);
3198
3198
  if (!shapeChanged && !typeChanged) {
3199
3199
  this.bindingRegistry.set(key, info);
3200
3200
  return;
@@ -3384,7 +3384,7 @@ class BindRuntime {
3384
3384
  };
3385
3385
  const bindingDescriptor = {
3386
3386
  source: sourcePath,
3387
- patch: patchPath ? variant("some", patchPath) : variant("none", null),
3387
+ patch: patchPath ? some(patchPath) : none$1,
3388
3388
  mode: variant(mode, null)
3389
3389
  };
3390
3390
  const writeStaged = (value) => {
@@ -4477,13 +4477,12 @@ function createDefaultFunctionApi(apiUrl, repo, getToken) {
4477
4477
  async call(workspace, fn3, req) {
4478
4478
  return workspaceFunctionCall(apiUrl, repo, workspace, fn3, {
4479
4479
  args: req.args,
4480
- runner: variant("none", null),
4481
- limits: variant("none", null)
4480
+ runner: none$1,
4481
+ limits: none$1
4482
4482
  }, opts());
4483
4483
  }
4484
4484
  };
4485
4485
  }
4486
- const eastTypeEqual$1 = equalFor(EastTypeType);
4487
4486
  function signatureOfFuncHandleType(handleType) {
4488
4487
  var _a2, _b2;
4489
4488
  if (handleType.type !== "Struct") {
@@ -4500,11 +4499,11 @@ function signatureOfFuncHandleType(handleType) {
4500
4499
  if (readOut.type !== "Variant") {
4501
4500
  throw new Error("Func.bind: read() must return Option(Output)");
4502
4501
  }
4503
- const some3 = readOut.value.find((a2) => a2.name === "some");
4504
- if (!some3) {
4502
+ const some22 = readOut.value.find((a2) => a2.name === "some");
4503
+ if (!some22) {
4505
4504
  throw new Error("Func.bind: read() must return Option(Output)");
4506
4505
  }
4507
- return { inputs, output: some3.type };
4506
+ return { inputs, output: some22.type };
4508
4507
  }
4509
4508
  function errorOfExecuteResult(result) {
4510
4509
  const outcome = result.outcome;
@@ -4627,8 +4626,8 @@ class FuncRuntime extends TrackedChannelStore {
4627
4626
  stderr: ""
4628
4627
  };
4629
4628
  }
4630
- const inputsMatch = deployed.inputTypes.length === sig.inputs.length && deployed.inputTypes.every((t4, i) => eastTypeEqual$1(t4, sig.inputs[i]));
4631
- const outputMatches = eastTypeEqual$1(deployed.outputType, sig.output);
4629
+ const inputsMatch = deployed.inputTypes.length === sig.inputs.length && deployed.inputTypes.every((t4, i) => isTypeValueEqual(t4, sig.inputs[i]));
4630
+ const outputMatches = isTypeValueEqual(deployed.outputType, sig.output);
4632
4631
  if (!inputsMatch || !outputMatches) {
4633
4632
  const message = `signature mismatch for "${name}": bound (${sig.inputs.length} inputs) disagrees with the deployed package`;
4634
4633
  return {
@@ -4731,7 +4730,7 @@ class FuncRuntime extends TrackedChannelStore {
4731
4730
  FuncBindPrimitives.read.implement((_outputType) => (nameArg) => {
4732
4731
  const { key, entry } = channel(nameArg);
4733
4732
  runtime.track(key);
4734
- return entry.result !== void 0 ? variant("some", entry.result) : variant("none", null);
4733
+ return entry.result !== void 0 ? some(entry.result) : none$1;
4735
4734
  }),
4736
4735
  FuncBindPrimitives.status.implement((nameArg) => {
4737
4736
  const { key, entry } = channel(nameArg);
@@ -4741,7 +4740,7 @@ class FuncRuntime extends TrackedChannelStore {
4741
4740
  FuncBindPrimitives.error.implement((nameArg) => {
4742
4741
  const { key, entry } = channel(nameArg);
4743
4742
  runtime.track(key);
4744
- return entry.status === "failed" && entry.error !== void 0 ? variant("some", entry.error) : variant("none", null);
4743
+ return entry.status === "failed" && entry.error !== void 0 ? some(entry.error) : none$1;
4745
4744
  }),
4746
4745
  FuncBindPrimitives.pending.implement((nameArg) => {
4747
4746
  const { key, entry } = channel(nameArg);
@@ -9241,12 +9240,11 @@ function collectLeaves(node2, into = []) {
9241
9240
  else for (const c2 of node2.children) collectLeaves(c2, into);
9242
9241
  return into;
9243
9242
  }
9243
+ const readString = parseFor(StringType);
9244
9244
  function leafDisplayLabel(seg) {
9245
- if (seg.kind === "key" && typeof seg.key === "string" && seg.key.length >= 2 && seg.key.startsWith('"') && seg.key.endsWith('"')) {
9246
- try {
9247
- return JSON.parse(seg.key);
9248
- } catch {
9249
- }
9245
+ if (seg.kind === "key") {
9246
+ const read = readString(seg.key);
9247
+ if (read.success) return read.value;
9250
9248
  }
9251
9249
  return pathDisplay(seg);
9252
9250
  }
@@ -9298,57 +9296,28 @@ function walkPatchToTree(typeValue, patch, rootLabel) {
9298
9296
  return root2;
9299
9297
  }
9300
9298
  const MAX_INLINE_CHARS = 48;
9301
- function formatLeafValue(typeValue, value) {
9302
- if (value === null || value === void 0) return "null";
9303
- if (!typeValue) return "<value>";
9304
- switch (typeValue.type) {
9305
- case "Null":
9306
- return "null";
9307
- case "Boolean":
9308
- return value ? "true" : "false";
9309
- case "Integer":
9310
- return typeof value === "bigint" ? value.toString() : String(value);
9311
- case "Float":
9312
- return formatFloat(value);
9313
- case "String":
9314
- return value === "" ? '""' : String(value);
9315
- case "DateTime":
9316
- return value instanceof Date ? value.toISOString() : String(value);
9317
- case "Blob":
9318
- return value instanceof Uint8Array ? `${value.length} bytes` : truncate(printFor(typeValue)(value));
9319
- case "Variant":
9320
- if (isVariant(value)) {
9321
- const cases = typeValue.value;
9322
- const sub = cases.find((c2) => c2.name === value.type);
9323
- if (value.value === null || value.value === void 0 || !sub) return value.type;
9324
- return `${value.type}(${truncate(printFor(sub.type)(value.value))})`;
9325
- }
9326
- return "<value>";
9327
- default:
9328
- return truncate(printFor(typeValue)(value));
9329
- }
9330
- }
9331
- function formatFloat(v3) {
9332
- if (typeof v3 !== "number") return String(v3);
9333
- if (Number.isInteger(v3)) return v3.toFixed(1);
9334
- return Math.abs(v3) >= 1e3 ? v3.toLocaleString("en-US", { maximumFractionDigits: 2 }) : String(Number(v3.toFixed(4)));
9299
+ function formatLeafValue(leafType, value, words = formatters()) {
9300
+ if (leafType.type === "Float") return words.float(value);
9301
+ const text = printFor(leafType)(value);
9302
+ return leafType.type === "String" ? text : truncate(text);
9335
9303
  }
9336
9304
  function truncate(s2) {
9337
9305
  return s2.length > MAX_INLINE_CHARS ? s2.slice(0, MAX_INLINE_CHARS - 1) + "…" : s2;
9338
9306
  }
9339
- function formatBindingLabel(segments) {
9340
- if (segments.length === 0) return "(root)";
9341
- const last2 = segments[segments.length - 1];
9342
- if (last2 && typeof last2 === "object" && "type" in last2) {
9343
- if (last2.type === "field") return String(last2.value);
9344
- if (last2.type === "index") return `[${String(last2.value)}]`;
9345
- if (last2.type === "key") return String(last2.value);
9307
+ function formatBindingLabel(path2) {
9308
+ const last2 = path2[path2.length - 1];
9309
+ if (last2 === void 0) return "(root)";
9310
+ switch (last2.type) {
9311
+ case "field":
9312
+ return last2.value;
9346
9313
  }
9347
- return String(last2);
9348
9314
  }
9349
- function isPrimitiveLeafType(t4) {
9350
- if (!t4) return false;
9351
- switch (t4.type) {
9315
+ const DATETIME_LOCAL = tokenizeDateTimeFormat("YYYY-MM-DDTHH:mm");
9316
+ const readBoolean = parseFor(BooleanType);
9317
+ const readInteger = parseFor(IntegerType);
9318
+ const readFloat = parseFor(FloatType);
9319
+ function isPrimitiveLeafType(leafType) {
9320
+ switch (leafType.type) {
9352
9321
  case "Boolean":
9353
9322
  case "Integer":
9354
9323
  case "Float":
@@ -9360,49 +9329,46 @@ function isPrimitiveLeafType(t4) {
9360
9329
  }
9361
9330
  }
9362
9331
  function formatManualDraft(leafType, value) {
9363
- if (!leafType || value === void 0 || value === null) return "";
9332
+ if (value === void 0) return "";
9364
9333
  switch (leafType.type) {
9365
9334
  case "Boolean":
9366
- return value ? "true" : "false";
9367
9335
  case "Integer":
9368
- return typeof value === "bigint" ? value.toString() : String(value);
9369
9336
  case "Float":
9370
- return typeof value === "number" ? String(value) : String(value);
9337
+ return printFor(leafType)(value);
9371
9338
  case "String":
9372
- return String(value);
9373
- case "DateTime": {
9374
- if (!(value instanceof Date)) return String(value);
9375
- return value.toISOString().slice(0, 16);
9376
- }
9339
+ return value;
9340
+ case "DateTime":
9341
+ return formatDateTime(value, DATETIME_LOCAL);
9377
9342
  default:
9378
9343
  return "";
9379
9344
  }
9380
9345
  }
9381
9346
  function parseManualDraft(leafType, draft) {
9382
- try {
9383
- switch (leafType.type) {
9384
- case "Integer":
9385
- return { ok: true, value: BigInt(draft) };
9386
- case "Float": {
9387
- const n2 = Number(draft);
9388
- if (Number.isNaN(n2)) return { ok: false };
9389
- return { ok: true, value: n2 };
9390
- }
9391
- case "String":
9392
- return { ok: true, value: draft };
9393
- case "DateTime": {
9394
- const d2 = new Date(draft);
9395
- if (Number.isNaN(d2.getTime())) return { ok: false };
9396
- return { ok: true, value: d2 };
9397
- }
9398
- default:
9399
- return { ok: false };
9347
+ switch (leafType.type) {
9348
+ case "Boolean": {
9349
+ const read = readBoolean(draft);
9350
+ return read.success ? { ok: true, value: read.value } : { ok: false };
9400
9351
  }
9401
- } catch {
9402
- return { ok: false };
9352
+ case "Integer": {
9353
+ const read = readInteger(draft);
9354
+ return read.success ? { ok: true, value: read.value } : { ok: false };
9355
+ }
9356
+ case "Float": {
9357
+ const read = readFloat(draft);
9358
+ return read.success ? { ok: true, value: read.value } : { ok: false };
9359
+ }
9360
+ case "String":
9361
+ return { ok: true, value: draft };
9362
+ case "DateTime": {
9363
+ const read = parseDateTimeFormatted(draft, DATETIME_LOCAL);
9364
+ return read.success ? { ok: true, value: read.value } : { ok: false };
9365
+ }
9366
+ default:
9367
+ return { ok: false };
9403
9368
  }
9404
9369
  }
9405
- const diffValueEqual = equalFor(Diff.Component.schema);
9370
+ const diffValueEqual = equivalentFor(Diff.Component.schema);
9371
+ const diffValueDataEqual = equalFor(Diff.Component.schema);
9406
9372
  function getOpt$1(opt) {
9407
9373
  return opt.type === "some" ? opt.value : void 0;
9408
9374
  }
@@ -9628,6 +9594,7 @@ function ActionBtn({
9628
9594
  );
9629
9595
  }
9630
9596
  const DiffRow = memo(function DiffRow2({ row, depth, bindingPathStr, showActions, onDiscard, annotation, metrics }) {
9597
+ const words = useFormatters();
9631
9598
  const handleDiscard = useCallback(() => onDiscard(bindingPathStr, row.path), [onDiscard, bindingPathStr, row.path]);
9632
9599
  return /* @__PURE__ */ jsxs(
9633
9600
  Box,
@@ -9660,7 +9627,7 @@ const DiffRow = memo(function DiffRow2({ row, depth, bindingPathStr, showActions
9660
9627
  row.stale && /* @__PURE__ */ jsxs(Text, { fontSize: "11px", color: "fg.warning", fontWeight: 500, children: [
9661
9628
  /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation }),
9662
9629
  " ",
9663
- row.stale.actual === void 0 ? "stale — source no longer has this entry" : `stale — source actually has ${formatLeafValue(row.leafType, row.stale.actual)}`
9630
+ row.stale.actual === void 0 ? "stale — source no longer has this entry" : `stale — source actually has ${formatLeafValue(row.leafType, row.stale.actual, words)}`
9664
9631
  ] }),
9665
9632
  annotation && /* @__PURE__ */ jsx$1(Text, { fontSize: "11px", color: `${annotation.tone}.700`, fontWeight: 500, children: annotation.text })
9666
9633
  ] }),
@@ -9669,13 +9636,13 @@ const DiffRow = memo(function DiffRow2({ row, depth, bindingPathStr, showActions
9669
9636
  row.before !== void 0 && /* @__PURE__ */ jsxs(Chip$1, { fontSize: metrics.chipFontSize, children: [
9670
9637
  /* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.danger", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faMinus }) }),
9671
9638
  " ",
9672
- formatLeafValue(row.leafType, row.before)
9639
+ formatLeafValue(row.leafType, row.before, words)
9673
9640
  ] }),
9674
9641
  row.before !== void 0 && row.after !== void 0 && /* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.subtle", fontSize: "11px", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faArrowRight }) }),
9675
9642
  row.after !== void 0 && /* @__PURE__ */ jsxs(Chip$1, { fontSize: metrics.chipFontSize, children: [
9676
9643
  /* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.success", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faPlus }) }),
9677
9644
  " ",
9678
- formatLeafValue(row.leafType, row.after)
9645
+ formatLeafValue(row.leafType, row.after, words)
9679
9646
  ] })
9680
9647
  ] }),
9681
9648
  showActions && /* @__PURE__ */ jsx$1(ActionBtn, { icon: faXmark, title: "Discard this change", onClick: handleDiscard, size: metrics.actionBtnSize })
@@ -9684,9 +9651,11 @@ const DiffRow = memo(function DiffRow2({ row, depth, bindingPathStr, showActions
9684
9651
  }
9685
9652
  );
9686
9653
  });
9654
+ const REMOVED = "(removed)";
9687
9655
  const ConflictRow = memo(function ConflictRow2({ row, depth, bindingPathStr, serverValue, resolution, onResolve, metrics }) {
9688
- const yoursStr = formatLeafValue(row.leafType, row.after);
9689
- const theirsStr = formatLeafValue(row.leafType, serverValue);
9656
+ const words = useFormatters();
9657
+ const yoursStr = row.after === void 0 ? REMOVED : formatLeafValue(row.leafType, row.after, words);
9658
+ const theirsStr = serverValue === void 0 ? REMOVED : formatLeafValue(row.leafType, serverValue, words);
9690
9659
  const isYours = (resolution == null ? void 0 : resolution.type) === "keepA";
9691
9660
  const isTheirs = (resolution == null ? void 0 : resolution.type) === "keepB";
9692
9661
  const isManual = (resolution == null ? void 0 : resolution.type) === "manual";
@@ -9752,7 +9721,7 @@ const ConflictRow = memo(function ConflictRow2({ row, depth, bindingPathStr, ser
9752
9721
  {
9753
9722
  selected: isManual,
9754
9723
  leafType: row.leafType,
9755
- value: isManual ? resolution.value : row.after,
9724
+ value: (resolution == null ? void 0 : resolution.type) === "manual" ? resolution.value : row.after,
9756
9725
  onChange: handleManual
9757
9726
  }
9758
9727
  )
@@ -9869,9 +9838,8 @@ function ManualEditor({
9869
9838
  const fire = useCallback((parsed) => {
9870
9839
  queueMicrotask(() => onChange2(parsed));
9871
9840
  }, [onChange2]);
9872
- if (!leafType) return null;
9873
9841
  if (leafType.type === "Boolean") {
9874
- const checked = !!value;
9842
+ const checked = value === true;
9875
9843
  return /* @__PURE__ */ jsxs(
9876
9844
  Box,
9877
9845
  {
@@ -10053,9 +10021,10 @@ const EastChakraDiff = memo(function EastChakraDiff2({ value }) {
10053
10021
  const [conflicts, setConflicts] = useState(null);
10054
10022
  const [resolutions, setResolutions] = useState(/* @__PURE__ */ new Map());
10055
10023
  const [committing, setCommitting] = useState(false);
10024
+ const data4 = useDataStable(value, diffValueDataEqual);
10056
10025
  const irBindings = useMemo(
10057
- () => value.bindings ?? [],
10058
- [value.bindings]
10026
+ () => data4.bindings ?? [],
10027
+ [data4.bindings]
10059
10028
  );
10060
10029
  const interactive = !(getOpt$1(value.readonly) ?? false);
10061
10030
  const onCommittedFn = getOpt$1(value.onCommitted);
@@ -10089,7 +10058,7 @@ const EastChakraDiff = memo(function EastChakraDiff2({ value }) {
10089
10058
  useEffect(() => {
10090
10059
  setConflicts(null);
10091
10060
  setResolutions(/* @__PURE__ */ new Map());
10092
- }, [value, stagedVersion, datasetVersion]);
10061
+ }, [data4, stagedVersion, datasetVersion]);
10093
10062
  const visibleBindings = useMemo(
10094
10063
  () => bindings.filter((b2) => b2.leaves.length > 0),
10095
10064
  [bindings]
@@ -23468,13 +23437,13 @@ var hashIterableInts = function hashIterableInts2(iterator) {
23468
23437
  }
23469
23438
  return hash2;
23470
23439
  };
23471
- var hashInt = function hashInt2(num2) {
23440
+ var hashInt = function hashInt2(num) {
23472
23441
  var seed = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : DEFAULT_HASH_SEED;
23473
- return seed * K + num2 | 0;
23442
+ return seed * K + num | 0;
23474
23443
  };
23475
- var hashIntAlt = function hashIntAlt2(num2) {
23444
+ var hashIntAlt = function hashIntAlt2(num) {
23476
23445
  var seed = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : DEFAULT_HASH_SEED_ALT;
23477
- return (seed << 5) + seed + num2 | 0;
23446
+ return (seed << 5) + seed + num | 0;
23478
23447
  };
23479
23448
  var combineHashes = function combineHashes2(hash1, hash2) {
23480
23449
  return hash1 * 2097152 + hash2;
@@ -23504,7 +23473,7 @@ var hashIntsArray = function hashIntsArray2(ints, seed) {
23504
23473
  };
23505
23474
  return hashIterableInts(iterator, seed);
23506
23475
  };
23507
- var hashString$1 = function hashString(str, seed) {
23476
+ var hashString = function hashString2(str, seed) {
23508
23477
  var entry = {
23509
23478
  value: 0,
23510
23479
  done: false
@@ -23531,9 +23500,9 @@ var hashStringsArray = function hashStringsArray2(strs) {
23531
23500
  for (var i = 0; i < strs.length; i++) {
23532
23501
  var str = strs[i];
23533
23502
  if (i === 0) {
23534
- hash2 = hashString$1(str);
23503
+ hash2 = hashString(str);
23535
23504
  } else {
23536
- hash2 = hashString$1(str, hash2);
23505
+ hash2 = hashString(str, hash2);
23537
23506
  }
23538
23507
  }
23539
23508
  return hash2;
@@ -29099,9 +29068,9 @@ function requireGet() {
29099
29068
  if (hasRequiredGet) return get_1;
29100
29069
  hasRequiredGet = 1;
29101
29070
  var baseGet = require_baseGet();
29102
- function get3(object3, path2, defaultValue) {
29071
+ function get3(object3, path2, defaultValue2) {
29103
29072
  var result = object3 == null ? void 0 : baseGet(object3, path2);
29104
- return result === void 0 ? defaultValue : result;
29073
+ return result === void 0 ? defaultValue2 : result;
29105
29074
  }
29106
29075
  get_1 = get3;
29107
29076
  return get_1;
@@ -30671,7 +30640,7 @@ var cache = function cache2(fn3, name) {
30671
30640
  var _p = eles[0]._private;
30672
30641
  var tch = _p.traversalCache = _p.traversalCache || {};
30673
30642
  var ch = tch[name] = tch[name] || [];
30674
- var hash2 = hashString$1(key);
30643
+ var hash2 = hashString(key);
30675
30644
  var cacheHit = ch[hash2];
30676
30645
  if (cacheHit) {
30677
30646
  return cacheHit;
@@ -33277,13 +33246,13 @@ function styleCache(key, fn3, ele) {
33277
33246
  }
33278
33247
  }
33279
33248
  function cacheStyleFunction(key, fn3) {
33280
- key = hashString$1(key);
33249
+ key = hashString(key);
33281
33250
  return function cachedStyleFunction(ele) {
33282
33251
  return styleCache(key, fn3, ele);
33283
33252
  };
33284
33253
  }
33285
33254
  function cachePrototypeStyleFunction(key, fn3) {
33286
- key = hashString$1(key);
33255
+ key = hashString(key);
33287
33256
  var selfFn = function selfFn2(ele) {
33288
33257
  return fn3.call(ele);
33289
33258
  };
@@ -43554,7 +43523,7 @@ BRp$9.applyLabelDimensions = function(ele) {
43554
43523
  BRp$9.applyPrefixedLabelDimensions = function(ele, prefix2) {
43555
43524
  var _p = ele._private;
43556
43525
  var text = this.getLabelText(ele, prefix2);
43557
- var cacheKey = hashString$1(text, ele._private.labelDimsKey);
43526
+ var cacheKey = hashString(text, ele._private.labelDimsKey);
43558
43527
  if (getPrefixedProperty(_p.rscratch, "prefixedLabelDimsKey", prefix2) === cacheKey) {
43559
43528
  return;
43560
43529
  }
@@ -47950,7 +47919,7 @@ CRp$9.drawArrowShape = function(edge, context, fill, edgeWidth, shape, shapeWidt
47950
47919
  var shapeImpl = r2.arrowShapes[shape];
47951
47920
  if (usePaths) {
47952
47921
  var cache3 = r2.arrowPathCache = r2.arrowPathCache || [];
47953
- var key = hashString$1(shape);
47922
+ var key = hashString(shape);
47954
47923
  var cachedPath = cache3[key];
47955
47924
  if (cachedPath != null) {
47956
47925
  path2 = context = cachedPath;
@@ -54963,25 +54932,25 @@ function requireLayoutBase() {
54963
54932
  }
54964
54933
  }
54965
54934
  };
54966
- Layout2.transform = function(sliderValue, defaultValue, minDiv, maxMul) {
54935
+ Layout2.transform = function(sliderValue, defaultValue2, minDiv, maxMul) {
54967
54936
  if (minDiv != void 0 && maxMul != void 0) {
54968
- var value = defaultValue;
54937
+ var value = defaultValue2;
54969
54938
  if (sliderValue <= 50) {
54970
- var minValue = defaultValue / minDiv;
54971
- value -= (defaultValue - minValue) / 50 * (50 - sliderValue);
54939
+ var minValue = defaultValue2 / minDiv;
54940
+ value -= (defaultValue2 - minValue) / 50 * (50 - sliderValue);
54972
54941
  } else {
54973
- var maxValue = defaultValue * maxMul;
54974
- value += (maxValue - defaultValue) / 50 * (sliderValue - 50);
54942
+ var maxValue = defaultValue2 * maxMul;
54943
+ value += (maxValue - defaultValue2) / 50 * (sliderValue - 50);
54975
54944
  }
54976
54945
  return value;
54977
54946
  } else {
54978
54947
  var a2, b2;
54979
54948
  if (sliderValue <= 50) {
54980
- a2 = 9 * defaultValue / 500;
54981
- b2 = defaultValue / 10;
54949
+ a2 = 9 * defaultValue2 / 500;
54950
+ b2 = defaultValue2 / 10;
54982
54951
  } else {
54983
- a2 = 9 * defaultValue / 50;
54984
- b2 = -8 * defaultValue;
54952
+ a2 = 9 * defaultValue2 / 50;
54953
+ b2 = -8 * defaultValue2;
54985
54954
  }
54986
54955
  return a2 * sliderValue + b2;
54987
54956
  }
@@ -58332,7 +58301,7 @@ function useBindingValue(binding) {
58332
58301
  try {
58333
58302
  return { value: handle.read(), pending: handle.pending(), error: void 0 };
58334
58303
  } catch (e3) {
58335
- console.error(`[Experiment] failed to read binding "${String(sourcePath)}":`, e3);
58304
+ console.error(`[Experiment] failed to read binding "${pathToString$1(sourcePath)}":`, e3);
58336
58305
  return { value: null, pending: false, error: e3 };
58337
58306
  }
58338
58307
  }, [handle, version2]);
@@ -58348,20 +58317,25 @@ function useBindingValue(binding) {
58348
58317
  }, [handle]);
58349
58318
  return { value, mode, pending, error: error3, mutate, commit, discard };
58350
58319
  }
58320
+ function sameType(a2, b2) {
58321
+ return isTypeValueEqual(toEastTypeValue(a2), toEastTypeValue(b2));
58322
+ }
58323
+ function sameSignature(a2, b2) {
58324
+ const ai = a2.inputs;
58325
+ const bi = b2.inputs;
58326
+ return sameType(a2.output, b2.output) && (ai === null || bi === null ? ai === bi : ai.length === bi.length && ai.every((t4, i) => sameType(t4, bi[i])));
58327
+ }
58351
58328
  const IDLE = { call: () => {
58352
58329
  }, result: null, status: "idle", pending: false, error: null };
58353
58330
  function useFuncCall(name, inputs, output2) {
58354
58331
  const workspace = getReactiveDatasetCache().getConfig().workspace ?? "";
58355
58332
  const ready4 = !!name && !!inputs && workspace !== "";
58356
- const sigKey = useMemo(
58357
- () => ready4 ? JSON.stringify([inputs.map((t4) => toEastTypeValue(t4)), toEastTypeValue(output2)]) : "",
58358
- [ready4, inputs, output2]
58359
- );
58333
+ const signature = useDataStable({ inputs, output: output2 }, sameSignature);
58360
58334
  const handle = useMemo(() => {
58361
- if (!ready4) return null;
58362
- const handleType = toEastTypeValue(FuncBindHandleType(inputs, output2));
58335
+ if (!ready4 || signature.inputs === null) return null;
58336
+ const handleType = toEastTypeValue(FuncBindHandleType(signature.inputs, signature.output));
58363
58337
  return defaultFuncRuntime.buildHandle(handleType, name);
58364
- }, [ready4, name, workspace, sigKey]);
58338
+ }, [ready4, name, workspace, signature]);
58365
58339
  const channelKey = ready4 ? funcChannelKey(workspace, name) : "";
58366
58340
  const version2 = useSyncExternalStore(
58367
58341
  useCallback(
@@ -58372,7 +58346,6 @@ function useFuncCall(name, inputs, output2) {
58372
58346
  useCallback(() => channelKey ? defaultFuncRuntime.getKeyVersion(channelKey) : 0, [channelKey])
58373
58347
  );
58374
58348
  return useMemo(() => {
58375
- var _a2;
58376
58349
  if (!handle) return IDLE;
58377
58350
  let result = null;
58378
58351
  let status = "idle";
@@ -58384,10 +58357,7 @@ function useFuncCall(name, inputs, output2) {
58384
58357
  status = handle.status().type;
58385
58358
  pending = handle.pending();
58386
58359
  const err = handle.error();
58387
- if (err.type === "some") {
58388
- const v3 = err.value;
58389
- error3 = { kind: ((_a2 = v3.kind) == null ? void 0 : _a2.type) ?? "failed", message: v3.message ?? "", stdout: v3.stdout ?? "", stderr: v3.stderr ?? "" };
58390
- }
58360
+ if (err.type === "some") error3 = err.value;
58391
58361
  } catch {
58392
58362
  }
58393
58363
  return { call: (...args) => {
@@ -61005,207 +60975,14 @@ function GuidanceToggle({ on: on3, onToggle }) {
61005
60975
  }
61006
60976
  ) });
61007
60977
  }
61008
- function ChartLabel({ x: x2, y: y2, w: w2, align, size: size3, weight: weight8, color: color2, family, help, children: children2 }) {
61009
- const span = /* @__PURE__ */ jsx$1("span", { style: { fontSize: `${size3}px`, fontFamily: family, fontWeight: weight8, color: color2, lineHeight: 1, whiteSpace: "nowrap" }, children: children2 });
61010
- return /* @__PURE__ */ jsx$1("foreignObject", { x: x2, y: y2, width: w2, height: size3 + 6, style: { overflow: "visible" }, children: /* @__PURE__ */ jsx$1("div", { style: { textAlign: align, fontSize: `${size3}px`, lineHeight: 1 }, children: help ? /* @__PURE__ */ jsx$1(Help, { id: help, children: span }) : span }) });
61011
- }
61012
- function svgText(size3, fill, family, weight8) {
61013
- return { fontSize: `${size3}px`, fill, fontFamily: family, ...weight8 !== void 0 ? { fontWeight: weight8 } : {} };
61014
- }
61015
- function useMeasuredWidth() {
61016
- const ref = useRef(null);
61017
- const [w2, setW] = useState(0);
61018
- useLayoutEffect(() => {
61019
- const el = ref.current;
61020
- if (!el) return;
61021
- const update2 = () => setW(el.clientWidth);
61022
- update2();
61023
- const ro = new ResizeObserver(update2);
61024
- ro.observe(el);
61025
- return () => ro.disconnect();
61026
- }, []);
61027
- return [ref, w2];
61028
- }
61029
- function useChartTheme() {
61030
- const system = useChakraContext();
61031
- const tok = (k2, fallback) => system.token(k2, fallback);
61032
- const tones = {
61033
- neg: tok("colors.fg.danger", "#b85a4a"),
61034
- pos: tok("colors.fg.success", "#2f7a5b"),
61035
- warn: tok("colors.fg.warning", "#b8862d"),
61036
- muted: tok("colors.fg.muted", "#6b8080"),
61037
- brand: tok("colors.brand.solid", "#3a7780")
61038
- };
61039
- return {
61040
- mono: tok("fonts.mono", '"JetBrains Mono", ui-monospace, monospace'),
61041
- body: tok("fonts.body", "system-ui, -apple-system, sans-serif"),
61042
- ink: tok("colors.fg", "#111b22"),
61043
- muted: tones.muted,
61044
- faint: tok("colors.fg.subtle", "#9bb0b0"),
61045
- rule: tok("colors.border.subtle", "#e2e8e8"),
61046
- ruleStrong: tok("colors.border.strong", "#cbd5d5"),
61047
- surface: tok("colors.bg.surface", "#ffffff"),
61048
- tone: (t4) => tones[t4] ?? tones.brand,
61049
- labelSize: 10,
61050
- titleSize: 11,
61051
- lineWidth: 1.8,
61052
- barWidth: 2.5,
61053
- dotRadius: 2.6,
61054
- scatterRadius: 3.4,
61055
- areaOpacity: 0.16
61056
- };
61057
- }
61058
- const fmt$2 = (n2) => Number.isInteger(n2) ? String(n2) : n2.toFixed(1);
61059
- const signed$1 = (n2) => (n2 > 0 ? "+" : "") + fmt$2(n2);
61060
- const niceCeil = (v3) => {
61061
- if (v3 <= 1e-9) return 0;
61062
- const mag = Math.pow(10, Math.floor(Math.log10(v3)));
61063
- const n2 = v3 / mag;
61064
- 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;
61065
- return step3 * mag;
61066
- };
61067
- function ForestPlot({ rows, min: min4, max: max5, unit: unit2, height: height2, rowHelp }) {
61068
- const t4 = useChartTheme();
61069
- const [ref, w2] = useMeasuredWidth();
61070
- const n2 = rows.length;
61071
- const hPx = height2 ?? 26 + n2 * 38;
61072
- const padL = 124, padR = 46, padT = 20, padB = 30;
61073
- const innerW = Math.max(0, w2 - padL - padR);
61074
- const innerH = hPx - padT - padB;
61075
- const x2 = createLinearScale({ domain: [min4, max5], range: [0, innerW] });
61076
- const rowH = innerH / Math.max(1, n2);
61077
- const zeroX = Math.max(0, Math.min(innerW, x2(0)));
61078
- const frac = (v3) => max5 > min4 ? (v3 - min4) / (max5 - min4) : 0.5;
61079
- const anchorAt = (v3) => frac(v3) < 0.06 ? "start" : frac(v3) > 0.94 ? "end" : "middle";
61080
- const zf = frac(0);
61081
- const ticks2 = zf > 0.12 && zf < 0.88 ? [min4, 0, max5] : [min4, max5];
61082
- return /* @__PURE__ */ jsx$1(Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsx$1("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxs(Group, { left: padL, top: padT, children: [
61083
- /* @__PURE__ */ jsx$1(Line, { from: { x: zeroX, y: -4 }, to: { x: zeroX, y: innerH }, stroke: t4.muted, strokeWidth: 1, strokeDasharray: "3 2" }),
61084
- /* @__PURE__ */ jsx$1("text", { x: zeroX, y: -6, textAnchor: anchorAt(0), style: svgText(t4.labelSize, t4.muted, t4.mono), children: "no effect" }),
61085
- rows.map((r2, i) => {
61086
- const cy = rowH * i + rowH / 2;
61087
- const col = t4.tone(r2.tone);
61088
- return /* @__PURE__ */ jsxs(Group, { top: cy, children: [
61089
- /* @__PURE__ */ jsx$1(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" }),
61090
- /* @__PURE__ */ jsx$1(Line, { from: { x: x2(r2.lo), y: -4 }, to: { x: x2(r2.lo), y: 4 }, stroke: col, strokeWidth: 1.5 }),
61091
- /* @__PURE__ */ jsx$1(Line, { from: { x: x2(r2.hi), y: -4 }, to: { x: x2(r2.hi), y: 4 }, stroke: col, strokeWidth: 1.5 }),
61092
- /* @__PURE__ */ jsx$1(Circle, { cx: x2(r2.est), cy: 0, r: t4.scatterRadius, fill: col, stroke: t4.surface, strokeWidth: 1.8 }),
61093
- /* @__PURE__ */ jsx$1(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 }),
61094
- r2.note && /* @__PURE__ */ jsx$1("text", { x: -padL + 2, y: 9, style: svgText(9, t4.faint, t4.body), children: r2.note }),
61095
- /* @__PURE__ */ jsx$1("text", { x: innerW + padR - 2, y: 4, textAnchor: "end", style: svgText(t4.titleSize, col, t4.mono, 700), children: signed$1(r2.est) })
61096
- ] }, i);
61097
- }),
61098
- /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: innerH }, to: { x: innerW, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61099
- ticks2.map((tk, i) => /* @__PURE__ */ jsxs(Group, { left: Math.max(0, Math.min(innerW, x2(tk))), children: [
61100
- /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: innerH }, to: { x: 0, y: innerH + 4 }, stroke: t4.ruleStrong, strokeWidth: 1 }),
61101
- /* @__PURE__ */ jsx$1("text", { x: 0, y: innerH + 14, textAnchor: anchorAt(tk), style: svgText(t4.labelSize, t4.muted, t4.mono), children: signed$1(tk) })
61102
- ] }, `t${i}`)),
61103
- unit2 && /* @__PURE__ */ jsx$1("text", { x: innerW / 2, y: innerH + 26, textAnchor: "middle", style: svgText(t4.labelSize, t4.muted, t4.mono), children: unit2 })
61104
- ] }) }) });
61105
- }
61106
- function AreaRange({ lo: lo2, mid, hi, xTicks = [], yTicks = [], zero: zero2, tone: toneName, marks = [], height: height2, yFormat = "signed" }) {
61107
- const t4 = useChartTheme();
61108
- const [ref, w2] = useMeasuredWidth();
61109
- const hPx = height2 ?? 100;
61110
- const col = t4.tone(toneName ?? "brand");
61111
- const padL = yTicks.length ? 52 : 6;
61112
- const padR = 12;
61113
- const padT = marks.length ? 22 : 8;
61114
- const padB = xTicks.length ? 22 : 12;
61115
- const innerW = Math.max(0, w2 - padL - padR);
61116
- const innerH = hPx - padT - padB;
61117
- const xScale = createLinearScale({ domain: [0, Math.max(1, mid.length - 1)], range: [0, innerW] });
61118
- const fin = (x2, fallback) => typeof x2 === "number" && Number.isFinite(x2) ? x2 : fallback;
61119
- const data4 = mid.map((m2, i) => {
61120
- const mm = fin(m2, 0);
61121
- return { i, lo: fin(lo2[i], mm), hi: fin(hi[i], mm), mid: mm };
61122
- });
61123
- const dataMin = Math.min(...data4.map((d2) => d2.lo), zero2 ?? Infinity);
61124
- const dataMax = Math.max(...data4.map((d2) => d2.hi), zero2 ?? -Infinity);
61125
- const yHiN = niceCeil(Math.max(dataMax, 0));
61126
- const yLoN = dataMin < -0.08 * yHiN ? -niceCeil(-dataMin) : 0;
61127
- const yScale = createLinearScale({ domain: [yLoN, yHiN], range: [innerH, 0] });
61128
- const yfmt = (v3) => yFormat === "percent" ? `${Math.round(v3)}%` : signed$1(v3);
61129
- const yLabels = [yfmt(yHiN), yfmt((yHiN + yLoN) / 2), yfmt(yLoN)];
61130
- return /* @__PURE__ */ jsx$1(Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsx$1("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxs(Group, { left: padL, top: padT, children: [
61131
- /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: 0 }, to: { x: 0, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61132
- yTicks.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
61133
- /* @__PURE__ */ jsx$1("text", { x: -8, y: 10, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[0] }),
61134
- /* @__PURE__ */ jsx$1("text", { x: -8, y: innerH / 2 + 3, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[1] }),
61135
- /* @__PURE__ */ jsx$1("text", { x: -8, y: innerH - 1, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[2] })
61136
- ] }),
61137
- zero2 != null && /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: yScale(zero2) }, to: { x: innerW, y: yScale(zero2) }, stroke: t4.muted, strokeWidth: 1, strokeDasharray: "3 2" }),
61138
- /* @__PURE__ */ jsx$1(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" }),
61139
- /* @__PURE__ */ jsx$1(LinePath, { data: data4, x: (d2) => xScale(d2.i), y: (d2) => yScale(d2.mid), curve: monotoneX, stroke: col, strokeWidth: t4.lineWidth }),
61140
- marks.map((m2, i) => {
61141
- const mc = t4.tone(m2.tone);
61142
- const dotY = yScale(fin(mid[m2.at], 0));
61143
- const labY = Math.max(9, dotY - 9);
61144
- const atEnd = m2.at >= mid.length - 2;
61145
- const atStart = m2.at <= 1;
61146
- const align = atEnd ? "right" : atStart ? "left" : "center";
61147
- const labW = m2.label.length * 6.5 + 8;
61148
- const labX = atEnd ? -labW - 5 : atStart ? 5 : -labW / 2;
61149
- return /* @__PURE__ */ jsxs(Group, { left: xScale(m2.at), children: [
61150
- /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: -2 }, to: { x: 0, y: innerH }, stroke: mc, strokeWidth: 1, strokeDasharray: "2 3" }),
61151
- /* @__PURE__ */ jsx$1(Circle, { cx: 0, cy: dotY, r: t4.dotRadius, fill: mc, stroke: t4.surface, strokeWidth: 1.5 }),
61152
- /* @__PURE__ */ jsx$1(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 })
61153
- ] }, `mk${i}`);
61154
- }),
61155
- /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: innerH }, to: { x: innerW, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61156
- xTicks.map((tk, i) => {
61157
- const word = Number.isNaN(Number(tk));
61158
- return /* @__PURE__ */ jsx$1("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}`);
61159
- })
61160
- ] }) }) });
61161
- }
61162
- function OverlapHistogram({ treated, control, domain = [0, 1], supportLabel, positivityOk, height: height2 }) {
61163
- const t4 = useChartTheme();
61164
- const [ref, w2] = useMeasuredWidth();
61165
- const hPx = height2 ?? 150;
61166
- const padL = 8, padR = 8, padT = 16, padB = 26;
61167
- const innerW = Math.max(0, w2 - padL - padR);
61168
- const innerH = hPx - padT - padB;
61169
- const centerY = innerH / 2;
61170
- const halfH = centerY - 4;
61171
- const bins = Math.max(treated.length, control.length);
61172
- const x2 = createLinearScale({ domain, range: [0, innerW] });
61173
- const span = domain[1] - domain[0];
61174
- const binW = bins > 0 ? innerW / bins : innerW;
61175
- const barW = Math.max(1, binW * 0.78);
61176
- const maxVal = Math.max(1e-9, ...treated, ...control);
61177
- const tCol = t4.tone("pos");
61178
- const cCol = t4.tone("muted");
61179
- const ticks2 = [domain[0], (domain[0] + domain[1]) / 2, domain[1]];
61180
- const cx2 = (i) => x2(domain[0] + (i + 0.5) / bins * span);
61181
- return /* @__PURE__ */ jsx$1(Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsx$1("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxs(Group, { left: padL, top: padT, children: [
61182
- /* @__PURE__ */ jsx$1("text", { x: 0, y: -4, style: svgText(9, t4.faint, t4.body), children: "treated ↑" }),
61183
- supportLabel && /* @__PURE__ */ jsx$1("text", { x: innerW, y: -4, textAnchor: "end", style: svgText(t4.labelSize, positivityOk ? t4.tone("pos") : t4.tone("warn"), t4.mono, 600), children: supportLabel }),
61184
- Array.from({ length: bins }, (_2, i) => {
61185
- const ht = Number(treated[i] ?? 0) / maxVal * halfH;
61186
- const hc = Number(control[i] ?? 0) / maxVal * halfH;
61187
- const left = cx2(i) - barW / 2;
61188
- return /* @__PURE__ */ jsxs(Group, { children: [
61189
- ht > 0 && /* @__PURE__ */ jsx$1("rect", { x: left, y: centerY - ht, width: barW, height: ht, fill: tCol, fillOpacity: 0.85, rx: 0.5 }),
61190
- hc > 0 && /* @__PURE__ */ jsx$1("rect", { x: left, y: centerY, width: barW, height: hc, fill: cCol, fillOpacity: 0.6, rx: 0.5 })
61191
- ] }, i);
61192
- }),
61193
- /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: centerY }, to: { x: innerW, y: centerY }, stroke: t4.ruleStrong, strokeWidth: 1 }),
61194
- /* @__PURE__ */ jsx$1("text", { x: 0, y: innerH + 4, style: svgText(9, t4.faint, t4.body), children: "untreated ↓" }),
61195
- ticks2.map((tk, i) => /* @__PURE__ */ jsx$1("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}`))
61196
- ] }) }) });
61197
- }
61198
60978
  const arr = (v3) => v3 ? Array.from(v3, Number) : [];
61199
60979
  const arrI = (v3) => v3 ? Array.from(v3, Number) : [];
61200
- const fmt$1 = (x2) => {
61201
- const r2 = Number.isInteger(x2) ? String(x2) : x2.toFixed(1);
61202
- return r2 === "-0.0" ? "0.0" : r2;
61203
- };
61204
- const signed = (x2) => {
61205
- const f2 = fmt$1(x2);
61206
- return f2 === "0" || f2 === "0.0" || f2.startsWith("-") ? f2 : `+${f2}`;
61207
- };
60980
+ const ONE_DECIMAL = variant("number", { minimumFractionDigits: some(1n), maximumFractionDigits: some(1n), signDisplay: none$1 });
60981
+ const formatOf = (x2) => Number.isInteger(x2) ? void 0 : ONE_DECIMAL;
60982
+ const fmt$1 = (x2, words) => words.value(Math.abs(x2) < 0.05 ? 0 : x2, formatOf(x2));
60983
+ const signed = (x2, words) => words.value(x2, formatOf(x2), true);
61208
60984
  const clamp01 = (x2) => x2 < 0 ? 0 : x2 > 1 ? 1 : x2;
60985
+ const compareFloats = compareFor(FloatType);
61209
60986
  function band(absStd) {
61210
60987
  if (absStd >= 0.66) return { level: "large gap", tone: "neg" };
61211
60988
  if (absStd >= 0.33) return { level: "some", tone: "warn" };
@@ -61255,7 +61032,7 @@ function treatmentKind(cols, treatment) {
61255
61032
  return "value";
61256
61033
  }
61257
61034
  }
61258
- function deriveSpec(config2, cols, result, meta3, dataLen, subject) {
61035
+ function deriveSpec(config2, cols, result, meta3, dataLen, subject, words) {
61259
61036
  const outUnit = unitOf(meta3, config2.outcome);
61260
61037
  const balByCol = /* @__PURE__ */ new Map();
61261
61038
  for (const b2 of (result == null ? void 0 : result.balance) ?? []) {
@@ -61293,24 +61070,24 @@ function deriveSpec(config2, cols, result, meta3, dataLen, subject) {
61293
61070
  // n_total belongs to the Answer-tab counts strip; labelling the header
61294
61071
  // with it desyncs from the data after a population edit (and reads
61295
61072
  // wrong whenever the two legitimately differ).
61296
- dataLabel: `${dataLen} ${subject.many}`
61073
+ dataLabel: `${words.number(dataLen)} ${subject.many}`
61297
61074
  };
61298
61075
  }
61299
- function balanceDisplay(b2, categorical) {
61076
+ function balanceDisplay(b2, categorical, words) {
61300
61077
  const isProp = categorical.has(b2.base_column) && b2.treated_mean >= 0 && b2.treated_mean <= 1 && b2.control_mean >= 0 && b2.control_mean <= 1;
61301
- 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)}`;
61078
+ 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)}`;
61302
61079
  }
61303
- function deriveAnswer(config2, result, adj, meta3) {
61080
+ function deriveAnswer(config2, result, adj, meta3, words) {
61304
61081
  const ci = getSomeorUndefined(adj.ci);
61305
61082
  const nci = getSomeorUndefined(result.naive_ci);
61306
61083
  const categorical = new Set(getSomeorUndefined(config2.categorical) ?? []);
61307
- const balance = [...result.balance].sort((a2, b2) => Math.abs(b2.std_diff) - Math.abs(a2.std_diff)).map((b2) => ({
61084
+ const balance = [...result.balance].sort((a2, b2) => compareFloats(Math.abs(b2.std_diff), Math.abs(a2.std_diff))).map((b2) => ({
61308
61085
  // One-hot rows are `col=level` — label the BASE confounder, keep the level.
61309
61086
  col: b2.column,
61310
61087
  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})`}`,
61311
61088
  treated: b2.treated_mean,
61312
61089
  control: b2.control_mean,
61313
- display: balanceDisplay(b2, categorical),
61090
+ display: balanceDisplay(b2, categorical, words),
61314
61091
  frac: clamp01(Math.abs(b2.std_diff)),
61315
61092
  tone: band(Math.abs(b2.std_diff)).tone
61316
61093
  }));
@@ -61341,12 +61118,12 @@ function deriveAnswer(config2, result, adj, meta3) {
61341
61118
  balance
61342
61119
  };
61343
61120
  }
61344
- function deriveNarrative(result, a2, refute, higherBetter, subject) {
61121
+ function deriveNarrative(result, a2, refute, higherBetter, subject, words) {
61345
61122
  if (a2 === null) return null;
61346
61123
  const unit2 = a2.unit ? ` ${a2.unit}` : "";
61347
61124
  const dirUp = a2.effect > 0;
61348
61125
  const verb = higherBetter === void 0 ? dirUp ? "raises" : "lowers" : dirUp === higherBetter ? "improves" : "worsens";
61349
- const range = ` (likely between ${signed(a2.lo)} and ${signed(a2.hi)})`;
61126
+ const range = ` (likely between ${signed(a2.lo, words)} and ${signed(a2.hi, words)})`;
61350
61127
  const passed = (refute == null ? void 0 : refute.checks.filter((c2) => c2.passed).length) ?? 0;
61351
61128
  const total = (refute == null ? void 0 : refute.checks.length) ?? 0;
61352
61129
  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?”.`;
@@ -61357,13 +61134,13 @@ function deriveNarrative(result, a2, refute, higherBetter, subject) {
61357
61134
  segments: [
61358
61135
  { text: "Yes — ", strong: true },
61359
61136
  { text: `${a2.treatment} genuinely ${verb} ${a2.outcome}: about ` },
61360
- { text: `${signed(a2.effect)}${unit2}`, strong: true },
61137
+ { text: `${signed(a2.effect, words)}${unit2}`, strong: true },
61361
61138
  { text: ` per ${subject.one}${range}.${trustClause}` }
61362
61139
  ]
61363
61140
  };
61364
61141
  case "modest": {
61365
61142
  const tags = new Set(result.verdict_reasons.map((v3) => v3.type));
61366
- 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.` : ".";
61143
+ 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.` : ".";
61367
61144
  return {
61368
61145
  tone: "warn",
61369
61146
  segments: [
@@ -61378,14 +61155,14 @@ function deriveNarrative(result, a2, refute, higherBetter, subject) {
61378
61155
  tone: "warn",
61379
61156
  segments: [
61380
61157
  { text: "Don’t act on this yet — ", strong: true },
61381
- { 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.` }
61158
+ { 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.` }
61382
61159
  ]
61383
61160
  };
61384
61161
  default:
61385
61162
  return null;
61386
61163
  }
61387
61164
  }
61388
- function deriveRefusal(config2, result, meta3, subject) {
61165
+ function deriveRefusal(config2, result, meta3, subject, words) {
61389
61166
  const nT = Number(result.n_treated), nC = Number(result.n_control), nTot = Number(result.n_total);
61390
61167
  const treatment = labelOf(meta3, config2.treatment);
61391
61168
  if (result.verdict.type === "not_estimable") {
@@ -61395,22 +61172,22 @@ function deriveRefusal(config2, result, meta3, subject) {
61395
61172
  title: `Can’t estimate the effect of ${treatment}`,
61396
61173
  body: reason,
61397
61174
  evidence: [
61398
- { label: "treated", value: String(nT) },
61399
- { label: "untreated", value: String(nC) },
61400
- { label: subject.many, value: String(nTot) }
61175
+ { label: "treated", value: words.number(nT) },
61176
+ { label: "untreated", value: words.number(nC) },
61177
+ { label: subject.many, value: words.number(nTot) }
61401
61178
  ]
61402
61179
  };
61403
61180
  }
61404
61181
  if (result.verdict.type === "non_identifiable_positivity") {
61405
- const pct = Math.round(result.overlap.common_support_frac * 100);
61182
+ const pct = words.percent(result.overlap.common_support_frac);
61406
61183
  return {
61407
61184
  kind: "positivity",
61408
61185
  title: "No like-for-like comparison exists",
61409
- 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.`,
61186
+ 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.`,
61410
61187
  evidence: [
61411
- { label: "common support", value: `${pct}%` },
61412
- { label: "treated", value: String(nT) },
61413
- { label: "untreated", value: String(nC) }
61188
+ { label: "common support", value: pct },
61189
+ { label: "treated", value: words.number(nT) },
61190
+ { label: "untreated", value: words.number(nC) }
61414
61191
  ]
61415
61192
  };
61416
61193
  }
@@ -61419,20 +61196,19 @@ function deriveRefusal(config2, result, meta3, subject) {
61419
61196
  title: `Can’t estimate the effect of ${treatment}`,
61420
61197
  body: "The engine could not produce a like-for-like estimate for this configuration.",
61421
61198
  evidence: [
61422
- { label: "treated", value: String(nT) },
61423
- { label: "untreated", value: String(nC) },
61424
- { label: subject.many, value: String(nTot) }
61199
+ { label: "treated", value: words.number(nT) },
61200
+ { label: "untreated", value: words.number(nC) },
61201
+ { label: subject.many, value: words.number(nTot) }
61425
61202
  ]
61426
61203
  };
61427
61204
  }
61428
- function deriveOverlap(o2) {
61429
- const pct = Math.round(o2.common_support_frac * 100);
61205
+ function deriveOverlap(o2, words) {
61430
61206
  return {
61431
61207
  treated: arr(o2.treated_propensity),
61432
61208
  control: arr(o2.control_propensity),
61433
61209
  commonSupportFrac: o2.common_support_frac,
61434
61210
  positivityOk: o2.positivity_ok,
61435
- supportLabel: `${pct}% common support`
61211
+ supportLabel: `${words.percent(o2.common_support_frac)} common support`
61436
61212
  };
61437
61213
  }
61438
61214
  function zeroCrossing(xs, ys) {
@@ -61445,7 +61221,7 @@ function zeroCrossing(xs, ys) {
61445
61221
  }
61446
61222
  return null;
61447
61223
  }
61448
- function deriveRefute(r2, adj, meta3) {
61224
+ function deriveRefute(r2, adj, meta3, words) {
61449
61225
  const checks = [];
61450
61226
  const est = (adj == null ? void 0 : adj.effect) ?? 0;
61451
61227
  const placeboEffect = getSomeorUndefined(r2.placebo_effect);
@@ -61458,7 +61234,7 @@ function deriveRefute(r2, adj, meta3) {
61458
61234
  desc: "Shuffle which rows were treated; a real effect should collapse to zero.",
61459
61235
  // Speak the outcome, not the statistic: on fake labels the effect
61460
61236
  // should VANISH — say whether it did.
61461
- value: placeboEffect !== void 0 ? passed ? `vanished (${signed(placeboEffect)})` : `didn’t vanish (${signed(placeboEffect)})` : passed ? "vanished" : "didn’t vanish",
61237
+ value: placeboEffect !== void 0 ? passed ? `vanished (${signed(placeboEffect, words)})` : `didn’t vanish (${signed(placeboEffect, words)})` : passed ? "vanished" : "didn’t vanish",
61462
61238
  passed,
61463
61239
  tip: some("Randomly re-label which rows were treated. A genuine effect should vanish."),
61464
61240
  help: "check_shuffle"
@@ -61472,7 +61248,7 @@ function deriveRefute(r2, adj, meta3) {
61472
61248
  name: "Drop-some test",
61473
61249
  short: "drop-some",
61474
61250
  desc: "Re-estimate on random subsamples; a trustworthy effect stays put.",
61475
- value: passed ? `stayed at ${signed(ds)} ± ${fmt$1(dstd)}` : `moved to ${signed(ds)} ± ${fmt$1(dstd)}`,
61251
+ value: passed ? `stayed at ${signed(ds, words)} ± ${fmt$1(dstd, words)}` : `moved to ${signed(ds, words)} ± ${fmt$1(dstd, words)}`,
61476
61252
  passed,
61477
61253
  tip: none$1,
61478
61254
  help: "check_dropsome"
@@ -61492,14 +61268,14 @@ function deriveRefute(r2, adj, meta3) {
61492
61268
  }
61493
61269
  const sens = getSomeorUndefined(r2.sensitivity);
61494
61270
  const evalue = getSomeorUndefined(r2.robustness_value);
61495
- const benchmarks = sens ? [...sens.benchmarks].sort((a2, b2) => b2.strength - a2.strength) : [];
61271
+ const benchmarks = sens ? [...sens.benchmarks].sort((a2, b2) => compareFloats(b2.strength, a2.strength)) : [];
61496
61272
  if (sens !== void 0 || evalue !== void 0) {
61497
61273
  const strengths = sens ? arr(sens.strengths) : [];
61498
61274
  const effects = sens ? arr(sens.effects) : [];
61499
61275
  const tip = sens ? zeroCrossing(strengths, effects) : null;
61500
61276
  const strongest = benchmarks[0];
61501
- 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";
61502
- const scaleNote = strongest !== void 0 ? ` For scale, your strongest known factor (${labelOf(meta3, strongest.column)}) sits at ${fmt$1(strongest.strength)} on this axis.` : "";
61277
+ 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";
61278
+ 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.` : "";
61503
61279
  checks.push({
61504
61280
  name: "Hidden cause",
61505
61281
  short: "hidden cause",
@@ -61535,12 +61311,12 @@ function deriveRefute(r2, adj, meta3) {
61535
61311
  const at = atOf(b2.strength);
61536
61312
  return at === null ? [] : [{ at, label: `as strong as ${labelOf(meta3, b2.column)}`, tone: "muted", help: "sensitivity" }];
61537
61313
  });
61538
- sensVM = { lo: lo2, mid, hi, xTicks: ["none", "", "stronger"], yTicks: [fmt$1(yLo), fmt$1((yLo + yHi) / 2), fmt$1(yHi)], marks };
61314
+ sensVM = { lo: lo2, mid, hi, xTicks: ["none", "", "stronger"], yTicks: [fmt$1(yLo, words), fmt$1((yLo + yHi) / 2, words), fmt$1(yHi, words)], marks };
61539
61315
  }
61540
61316
  }
61541
61317
  return { checks, sens: sensVM };
61542
61318
  }
61543
- function deriveDose(dose, config2, meta3) {
61319
+ function deriveDose(dose, config2, meta3, words) {
61544
61320
  const grid = arr(dose.grid);
61545
61321
  const mid = arr(dose.effect);
61546
61322
  const lo2 = getSomeorUndefined(dose.lower) ? arr(getSomeorUndefined(dose.lower)) : mid.slice();
@@ -61558,17 +61334,17 @@ function deriveDose(dose, config2, meta3) {
61558
61334
  }
61559
61335
  }
61560
61336
  const xi = grid.length ? [0, Math.floor(grid.length / 2), grid.length - 1] : [];
61561
- const xTicks = xi.map((i) => fmt$1(grid[i]));
61337
+ const xTicks = xi.map((i) => fmt$1(grid[i], words));
61562
61338
  const yLo = Math.min(0, ...lo2), yHi = Math.max(...hi, 0);
61563
- const yTicks = [fmt$1(yLo), fmt$1((yLo + yHi) / 2), fmt$1(yHi)];
61339
+ const yTicks = [fmt$1(yLo, words), fmt$1((yLo + yHi) / 2, words), fmt$1(yHi, words)];
61564
61340
  const margSteps = marg.slice(1);
61565
61341
  let lastStep = margSteps.length - 1;
61566
61342
  while (lastStep > 0 && Math.abs(margSteps[lastStep]) < 0.12 * maxMarg) lastStep--;
61567
- const marginal = margSteps.slice(0, lastStep + 1).map((v3, i) => ({ label: `${fmt$1(grid[i + 1])}`, value: v3, frac: clamp01(Math.abs(v3) / maxMarg) }));
61343
+ 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) }));
61568
61344
  const stepFrom = here < sweet ? here : Math.max(0, sweet - 1);
61569
61345
  const gainToSweet = (mid[sweet] ?? 0) - (mid[stepFrom] ?? 0);
61570
61346
  const nextGain = sweet + 1 < mid.length ? mid[sweet + 1] - mid[sweet] : 0;
61571
- 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)}.`;
61347
+ 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)}.`;
61572
61348
  const marks = [];
61573
61349
  if (sizes.length) marks.push({ at: here, label: "you are here", tone: "muted", help: "dose_here" });
61574
61350
  marks.push({ at: sweet, label: "sweet spot", tone: "pos", help: "dose_sweet" });
@@ -61585,7 +61361,7 @@ function deriveDose(dose, config2, meta3) {
61585
61361
  marks,
61586
61362
  // Name the feature in the recommendation — a bare "≈ 5.5" doesn't say
61587
61363
  // 5.5 of WHAT.
61588
- recoLabel: `aim for ${featureLabel} ≈ ${fmt$1(grid[sweet] ?? 0)}${featureUnit ? " " + featureUnit : ""}`,
61364
+ recoLabel: `aim for ${featureLabel} ≈ ${fmt$1(grid[sweet] ?? 0, words)}${featureUnit ? " " + featureUnit : ""}`,
61589
61365
  recoEffect: mid[sweet] ?? 0,
61590
61366
  recoLo: lo2[sweet] ?? 0,
61591
61367
  recoHi: hi[sweet] ?? 0,
@@ -61594,11 +61370,11 @@ function deriveDose(dose, config2, meta3) {
61594
61370
  framing: `A different question from the headline: how ${outcomeLabel} responds as ${featureLabel} itself moves.`
61595
61371
  };
61596
61372
  }
61597
- function relTime(d2, now2) {
61373
+ function relTime(d2, now2, words) {
61598
61374
  const days = Math.floor((now2.getTime() - d2.getTime()) / 864e5);
61599
61375
  if (days <= 0) return "today";
61600
61376
  if (days === 1) return "yesterday";
61601
- if (days < 7) return d2.toLocaleDateString(void 0, { weekday: "short" });
61377
+ if (days < 7) return words.weekday(d2);
61602
61378
  return "last wk";
61603
61379
  }
61604
61380
  const VERDICT_WORD = {
@@ -61608,43 +61384,43 @@ const VERDICT_WORD = {
61608
61384
  non_identifiable_positivity: "no overlap",
61609
61385
  not_estimable: "n/a"
61610
61386
  };
61611
- function deriveJournalRow(row, now2, meta3) {
61387
+ function deriveJournalRow(row, now2, meta3, words) {
61612
61388
  const adj = getSomeorUndefined(row.adjusted);
61613
61389
  return {
61614
61390
  treatment: labelOf(meta3, row.config.treatment),
61615
61391
  outcome: labelOf(meta3, row.config.outcome),
61616
61392
  confounders: row.config.common_causes.map((c2) => labelOf(meta3, c2)).join(", "),
61617
- effect: adj !== void 0 ? signed(adj) : signed(row.naive),
61393
+ effect: adj !== void 0 ? signed(adj, words) : signed(row.naive, words),
61618
61394
  verdict: VERDICT_WORD[row.verdict.type],
61619
61395
  verdictTone: VERDICT_TONE[row.verdict.type],
61620
61396
  who: row.committed_by,
61621
- when: relTime(row.committed_at, now2),
61397
+ when: relTime(row.committed_at, now2, words),
61622
61398
  // The originating preset id (resolved to a label by the surface); `none` for a
61623
61399
  // free-form / pre-presets row.
61624
61400
  preset: row.preset
61625
61401
  };
61626
61402
  }
61627
- function deriveView(config2, ranConfig, cols, result, journal, meta3, dataLen, now2, subject = { one: "record", many: "records" }) {
61403
+ function deriveView(config2, ranConfig, cols, result, journal, meta3, dataLen, now2, subject = { one: "record", many: "records" }, words = formatters()) {
61628
61404
  var _a2;
61629
61405
  const adj = result ? getSomeorUndefined(result.adjusted) : void 0;
61630
61406
  const refutation = result ? getSomeorUndefined(result.refutation) : void 0;
61631
61407
  const doseR = result ? getSomeorUndefined(result.dose_response) : void 0;
61632
- const answer = result && adj ? deriveAnswer(ranConfig, result, adj, meta3) : null;
61633
- const refute = refutation ? deriveRefute(refutation, adj, meta3) : null;
61408
+ const answer = result && adj ? deriveAnswer(ranConfig, result, adj, meta3, words) : null;
61409
+ const refute = refutation ? deriveRefute(refutation, adj, meta3, words) : null;
61634
61410
  const higherBetter = getSomeorUndefined((_a2 = colMeta(meta3, ranConfig.outcome)) == null ? void 0 : _a2.higherIsBetter);
61635
61411
  return {
61636
61412
  // The set-up rail reflects the LIVE config (the editor); the result deck
61637
61413
  // reflects RANCONFIG — the config that produced `result` — so the result
61638
61414
  // strings never drift ahead of the numbers on a live picker edit.
61639
- spec: deriveSpec(config2, cols, result, meta3, dataLen, subject),
61415
+ spec: deriveSpec(config2, cols, result, meta3, dataLen, subject, words),
61640
61416
  verdict: result ? deriveVerdict(result.verdict) : null,
61641
- narrative: result ? deriveNarrative(result, answer, refute, higherBetter, subject) : null,
61417
+ narrative: result ? deriveNarrative(result, answer, refute, higherBetter, subject, words) : null,
61642
61418
  answer,
61643
- refusal: result && !adj ? deriveRefusal(ranConfig, result, meta3, subject) : null,
61644
- overlap: result ? deriveOverlap(result.overlap) : null,
61419
+ refusal: result && !adj ? deriveRefusal(ranConfig, result, meta3, subject, words) : null,
61420
+ overlap: result ? deriveOverlap(result.overlap, words) : null,
61645
61421
  refute,
61646
- dose: doseR && doseR.effect.length ? deriveDose(doseR, ranConfig, meta3) : null,
61647
- journal: journal ? journal.map((r2) => deriveJournalRow(r2, now2, meta3)) : null
61422
+ dose: doseR && doseR.effect.length ? deriveDose(doseR, ranConfig, meta3, words) : null,
61423
+ journal: journal ? journal.map((r2) => deriveJournalRow(r2, now2, meta3, words)) : null
61648
61424
  };
61649
61425
  }
61650
61426
  const DESIGN_HEADLINE = {
@@ -61663,7 +61439,7 @@ function deriveDesignOption(o2) {
61663
61439
  treatedShare: o2.treated_share
61664
61440
  };
61665
61441
  }
61666
- function deriveDesign(d2, result, ranConfig, meta3) {
61442
+ function deriveDesign(d2, result, ranConfig, meta3, words = formatters()) {
61667
61443
  const basis = d2.basis.type;
61668
61444
  const outcome = ranConfig.outcome;
61669
61445
  const unit2 = unitOf(meta3, outcome);
@@ -61695,9 +61471,9 @@ function deriveDesign(d2, result, ranConfig, meta3) {
61695
61471
  }
61696
61472
  return bi;
61697
61473
  };
61698
- const xTicks = len ? [String(ns[0]), String(ns[Math.floor((len - 1) / 2)]), String(ns[len - 1])] : [];
61474
+ const xTicks = len ? [words.number(ns[0]), words.number(ns[Math.floor((len - 1) / 2)]), words.number(ns[len - 1])] : [];
61699
61475
  const marks = [];
61700
- if (len) marks.push({ at: nearest(primary.nTotal), label: `target ${(d2.target_power * 100).toFixed(0)}%`, tone: "pos", help: "validate_power" });
61476
+ if (len) marks.push({ at: nearest(primary.nTotal), label: `target ${words.percent(d2.target_power)}`, tone: "pos", help: "validate_power" });
61701
61477
  const cp = getSomeorUndefined(d2.current_power);
61702
61478
  if (cp !== void 0 && len) {
61703
61479
  const curN = result ? Number(result.n_total) : 0;
@@ -61705,7 +61481,7 @@ function deriveDesign(d2, result, ranConfig, meta3) {
61705
61481
  const offScale = curN >= (ns[len - 1] ?? 0);
61706
61482
  marks.push({
61707
61483
  at: offScale ? len - 1 : nearest(curN),
61708
- label: offScale ? `you’re here · ${(cp * 100).toFixed(0)}% (off-scale)` : `you’re here ${(cp * 100).toFixed(0)}%`,
61484
+ label: offScale ? `you’re here · ${words.percent(cp)} (off-scale)` : `you’re here ${words.percent(cp)}`,
61709
61485
  tone: "muted",
61710
61486
  help: "validate_power"
61711
61487
  });
@@ -61719,13 +61495,204 @@ function deriveDesign(d2, result, ranConfig, meta3) {
61719
61495
  alternates: options2.slice(1),
61720
61496
  matchOn,
61721
61497
  curve: { mid: powers.slice(0, len).map((p2) => p2 * 100), xTicks, marks },
61722
- targetLabel: `${signed(d2.target_effect)}${unit2 ? ` ${unit2}` : ""}`,
61723
- targetPctLabel: `${(d2.target_power * 100).toFixed(0)}%`,
61498
+ targetLabel: `${signed(d2.target_effect, words)}${unit2 ? ` ${unit2}` : ""}`,
61499
+ targetPctLabel: words.percent(d2.target_power),
61724
61500
  holdback: basis === "create_control",
61725
61501
  showOverlap: basis === "restrict_to_overlap",
61726
61502
  faint
61727
61503
  };
61728
61504
  }
61505
+ function ChartLabel({ x: x2, y: y2, w: w2, align, size: size3, weight: weight8, color: color2, family, help, children: children2 }) {
61506
+ const span = /* @__PURE__ */ jsx$1("span", { style: { fontSize: `${size3}px`, fontFamily: family, fontWeight: weight8, color: color2, lineHeight: 1, whiteSpace: "nowrap" }, children: children2 });
61507
+ return /* @__PURE__ */ jsx$1("foreignObject", { x: x2, y: y2, width: w2, height: size3 + 6, style: { overflow: "visible" }, children: /* @__PURE__ */ jsx$1("div", { style: { textAlign: align, fontSize: `${size3}px`, lineHeight: 1 }, children: help ? /* @__PURE__ */ jsx$1(Help, { id: help, children: span }) : span }) });
61508
+ }
61509
+ function svgText(size3, fill, family, weight8) {
61510
+ return { fontSize: `${size3}px`, fill, fontFamily: family, ...weight8 !== void 0 ? { fontWeight: weight8 } : {} };
61511
+ }
61512
+ function useMeasuredWidth() {
61513
+ const ref = useRef(null);
61514
+ const [w2, setW] = useState(0);
61515
+ useLayoutEffect(() => {
61516
+ const el = ref.current;
61517
+ if (!el) return;
61518
+ const update2 = () => setW(el.clientWidth);
61519
+ update2();
61520
+ const ro = new ResizeObserver(update2);
61521
+ ro.observe(el);
61522
+ return () => ro.disconnect();
61523
+ }, []);
61524
+ return [ref, w2];
61525
+ }
61526
+ function useChartTheme() {
61527
+ const system = useChakraContext();
61528
+ const tok = (k2, fallback) => system.token(k2, fallback);
61529
+ const tones = {
61530
+ neg: tok("colors.fg.danger", "#b85a4a"),
61531
+ pos: tok("colors.fg.success", "#2f7a5b"),
61532
+ warn: tok("colors.fg.warning", "#b8862d"),
61533
+ muted: tok("colors.fg.muted", "#6b8080"),
61534
+ brand: tok("colors.brand.solid", "#3a7780")
61535
+ };
61536
+ return {
61537
+ mono: tok("fonts.mono", '"JetBrains Mono", ui-monospace, monospace'),
61538
+ body: tok("fonts.body", "system-ui, -apple-system, sans-serif"),
61539
+ ink: tok("colors.fg", "#111b22"),
61540
+ muted: tones.muted,
61541
+ faint: tok("colors.fg.subtle", "#9bb0b0"),
61542
+ rule: tok("colors.border.subtle", "#e2e8e8"),
61543
+ ruleStrong: tok("colors.border.strong", "#cbd5d5"),
61544
+ surface: tok("colors.bg.surface", "#ffffff"),
61545
+ tone: (t4) => tones[t4] ?? tones.brand,
61546
+ labelSize: 10,
61547
+ titleSize: 11,
61548
+ lineWidth: 1.8,
61549
+ barWidth: 2.5,
61550
+ dotRadius: 2.6,
61551
+ scatterRadius: 3.4,
61552
+ areaOpacity: 0.16
61553
+ };
61554
+ }
61555
+ const niceCeil = (v3) => {
61556
+ if (v3 <= 1e-9) return 0;
61557
+ const mag = Math.pow(10, Math.floor(Math.log10(v3)));
61558
+ const n2 = v3 / mag;
61559
+ 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;
61560
+ return step3 * mag;
61561
+ };
61562
+ function ForestPlot({ rows, min: min4, max: max5, unit: unit2, height: height2, rowHelp }) {
61563
+ const t4 = useChartTheme();
61564
+ const words = useFormatters();
61565
+ const [ref, w2] = useMeasuredWidth();
61566
+ const n2 = rows.length;
61567
+ const hPx = height2 ?? 26 + n2 * 38;
61568
+ const padL = 124, padR = 46, padT = 20, padB = 30;
61569
+ const innerW = Math.max(0, w2 - padL - padR);
61570
+ const innerH = hPx - padT - padB;
61571
+ const x2 = createLinearScale({ domain: [min4, max5], range: [0, innerW] });
61572
+ const rowH = innerH / Math.max(1, n2);
61573
+ const zeroX = Math.max(0, Math.min(innerW, x2(0)));
61574
+ const frac = (v3) => max5 > min4 ? (v3 - min4) / (max5 - min4) : 0.5;
61575
+ const anchorAt = (v3) => frac(v3) < 0.06 ? "start" : frac(v3) > 0.94 ? "end" : "middle";
61576
+ const zf = frac(0);
61577
+ const ticks2 = zf > 0.12 && zf < 0.88 ? [min4, 0, max5] : [min4, max5];
61578
+ return /* @__PURE__ */ jsx$1(Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsx$1("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxs(Group, { left: padL, top: padT, children: [
61579
+ /* @__PURE__ */ jsx$1(Line, { from: { x: zeroX, y: -4 }, to: { x: zeroX, y: innerH }, stroke: t4.muted, strokeWidth: 1, strokeDasharray: "3 2" }),
61580
+ /* @__PURE__ */ jsx$1("text", { x: zeroX, y: -6, textAnchor: anchorAt(0), style: svgText(t4.labelSize, t4.muted, t4.mono), children: "no effect" }),
61581
+ rows.map((r2, i) => {
61582
+ const cy = rowH * i + rowH / 2;
61583
+ const col = t4.tone(r2.tone);
61584
+ return /* @__PURE__ */ jsxs(Group, { top: cy, children: [
61585
+ /* @__PURE__ */ jsx$1(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" }),
61586
+ /* @__PURE__ */ jsx$1(Line, { from: { x: x2(r2.lo), y: -4 }, to: { x: x2(r2.lo), y: 4 }, stroke: col, strokeWidth: 1.5 }),
61587
+ /* @__PURE__ */ jsx$1(Line, { from: { x: x2(r2.hi), y: -4 }, to: { x: x2(r2.hi), y: 4 }, stroke: col, strokeWidth: 1.5 }),
61588
+ /* @__PURE__ */ jsx$1(Circle, { cx: x2(r2.est), cy: 0, r: t4.scatterRadius, fill: col, stroke: t4.surface, strokeWidth: 1.8 }),
61589
+ /* @__PURE__ */ jsx$1(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 }),
61590
+ r2.note && /* @__PURE__ */ jsx$1("text", { x: -padL + 2, y: 9, style: svgText(9, t4.faint, t4.body), children: r2.note }),
61591
+ /* @__PURE__ */ jsx$1("text", { x: innerW + padR - 2, y: 4, textAnchor: "end", style: svgText(t4.titleSize, col, t4.mono, 700), children: signed(r2.est, words) })
61592
+ ] }, i);
61593
+ }),
61594
+ /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: innerH }, to: { x: innerW, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61595
+ ticks2.map((tk, i) => /* @__PURE__ */ jsxs(Group, { left: Math.max(0, Math.min(innerW, x2(tk))), children: [
61596
+ /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: innerH }, to: { x: 0, y: innerH + 4 }, stroke: t4.ruleStrong, strokeWidth: 1 }),
61597
+ /* @__PURE__ */ jsx$1("text", { x: 0, y: innerH + 14, textAnchor: anchorAt(tk), style: svgText(t4.labelSize, t4.muted, t4.mono), children: signed(tk, words) })
61598
+ ] }, `t${i}`)),
61599
+ unit2 && /* @__PURE__ */ jsx$1("text", { x: innerW / 2, y: innerH + 26, textAnchor: "middle", style: svgText(t4.labelSize, t4.muted, t4.mono), children: unit2 })
61600
+ ] }) }) });
61601
+ }
61602
+ function AreaRange({ lo: lo2, mid, hi, xTicks = [], xTickWords = false, yTicks = [], zero: zero2, tone: toneName, marks = [], height: height2, yFormat = "signed" }) {
61603
+ const t4 = useChartTheme();
61604
+ const words = useFormatters();
61605
+ const [ref, w2] = useMeasuredWidth();
61606
+ const hPx = height2 ?? 100;
61607
+ const col = t4.tone(toneName ?? "brand");
61608
+ const padL = yTicks.length ? 52 : 6;
61609
+ const padR = 12;
61610
+ const padT = marks.length ? 22 : 8;
61611
+ const padB = xTicks.length ? 22 : 12;
61612
+ const innerW = Math.max(0, w2 - padL - padR);
61613
+ const innerH = hPx - padT - padB;
61614
+ const xScale = createLinearScale({ domain: [0, Math.max(1, mid.length - 1)], range: [0, innerW] });
61615
+ const fin = (x2, fallback) => typeof x2 === "number" && Number.isFinite(x2) ? x2 : fallback;
61616
+ const data4 = mid.map((m2, i) => {
61617
+ const mm = fin(m2, 0);
61618
+ return { i, lo: fin(lo2[i], mm), hi: fin(hi[i], mm), mid: mm };
61619
+ });
61620
+ const dataMin = Math.min(...data4.map((d2) => d2.lo), zero2 ?? Infinity);
61621
+ const dataMax = Math.max(...data4.map((d2) => d2.hi), zero2 ?? -Infinity);
61622
+ const yHiN = niceCeil(Math.max(dataMax, 0));
61623
+ const yLoN = dataMin < -0.08 * yHiN ? -niceCeil(-dataMin) : 0;
61624
+ const yScale = createLinearScale({ domain: [yLoN, yHiN], range: [innerH, 0] });
61625
+ const yfmt = (v3) => yFormat === "percent" ? words.percent(v3 / 100) : signed(v3, words);
61626
+ const yLabels = [yfmt(yHiN), yfmt((yHiN + yLoN) / 2), yfmt(yLoN)];
61627
+ return /* @__PURE__ */ jsx$1(Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsx$1("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxs(Group, { left: padL, top: padT, children: [
61628
+ /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: 0 }, to: { x: 0, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61629
+ yTicks.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
61630
+ /* @__PURE__ */ jsx$1("text", { x: -8, y: 10, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[0] }),
61631
+ /* @__PURE__ */ jsx$1("text", { x: -8, y: innerH / 2 + 3, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[1] }),
61632
+ /* @__PURE__ */ jsx$1("text", { x: -8, y: innerH - 1, textAnchor: "end", style: svgText(t4.labelSize, t4.muted, t4.mono), children: yLabels[2] })
61633
+ ] }),
61634
+ zero2 != null && /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: yScale(zero2) }, to: { x: innerW, y: yScale(zero2) }, stroke: t4.muted, strokeWidth: 1, strokeDasharray: "3 2" }),
61635
+ /* @__PURE__ */ jsx$1(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" }),
61636
+ /* @__PURE__ */ jsx$1(LinePath, { data: data4, x: (d2) => xScale(d2.i), y: (d2) => yScale(d2.mid), curve: monotoneX, stroke: col, strokeWidth: t4.lineWidth }),
61637
+ marks.map((m2, i) => {
61638
+ const mc = t4.tone(m2.tone);
61639
+ const dotY = yScale(fin(mid[m2.at], 0));
61640
+ const labY = Math.max(9, dotY - 9);
61641
+ const atEnd = m2.at >= mid.length - 2;
61642
+ const atStart = m2.at <= 1;
61643
+ const align = atEnd ? "right" : atStart ? "left" : "center";
61644
+ const labW = m2.label.length * 6.5 + 8;
61645
+ const labX = atEnd ? -labW - 5 : atStart ? 5 : -labW / 2;
61646
+ return /* @__PURE__ */ jsxs(Group, { left: xScale(m2.at), children: [
61647
+ /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: -2 }, to: { x: 0, y: innerH }, stroke: mc, strokeWidth: 1, strokeDasharray: "2 3" }),
61648
+ /* @__PURE__ */ jsx$1(Circle, { cx: 0, cy: dotY, r: t4.dotRadius, fill: mc, stroke: t4.surface, strokeWidth: 1.5 }),
61649
+ /* @__PURE__ */ jsx$1(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 })
61650
+ ] }, `mk${i}`);
61651
+ }),
61652
+ /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: innerH }, to: { x: innerW, y: innerH }, stroke: t4.rule, strokeWidth: 1 }),
61653
+ xTicks.map((tk, i) => {
61654
+ const word = xTickWords;
61655
+ return /* @__PURE__ */ jsx$1("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}`);
61656
+ })
61657
+ ] }) }) });
61658
+ }
61659
+ function OverlapHistogram({ treated, control, domain = [0, 1], supportLabel, positivityOk, height: height2 }) {
61660
+ const t4 = useChartTheme();
61661
+ const words = useFormatters();
61662
+ const [ref, w2] = useMeasuredWidth();
61663
+ const hPx = height2 ?? 150;
61664
+ const padL = 8, padR = 8, padT = 16, padB = 26;
61665
+ const innerW = Math.max(0, w2 - padL - padR);
61666
+ const innerH = hPx - padT - padB;
61667
+ const centerY = innerH / 2;
61668
+ const halfH = centerY - 4;
61669
+ const bins = Math.max(treated.length, control.length);
61670
+ const x2 = createLinearScale({ domain, range: [0, innerW] });
61671
+ const span = domain[1] - domain[0];
61672
+ const binW = bins > 0 ? innerW / bins : innerW;
61673
+ const barW = Math.max(1, binW * 0.78);
61674
+ const maxVal = Math.max(1e-9, ...treated, ...control);
61675
+ const tCol = t4.tone("pos");
61676
+ const cCol = t4.tone("muted");
61677
+ const ticks2 = [domain[0], (domain[0] + domain[1]) / 2, domain[1]];
61678
+ const cx2 = (i) => x2(domain[0] + (i + 0.5) / bins * span);
61679
+ return /* @__PURE__ */ jsx$1(Box, { ref, width: "100%", height: `${hPx}px`, children: w2 > 0 && /* @__PURE__ */ jsx$1("svg", { width: w2, height: hPx, style: { display: "block" }, children: /* @__PURE__ */ jsxs(Group, { left: padL, top: padT, children: [
61680
+ /* @__PURE__ */ jsx$1("text", { x: 0, y: -4, style: svgText(9, t4.faint, t4.body), children: "treated ↑" }),
61681
+ supportLabel && /* @__PURE__ */ jsx$1("text", { x: innerW, y: -4, textAnchor: "end", style: svgText(t4.labelSize, positivityOk ? t4.tone("pos") : t4.tone("warn"), t4.mono, 600), children: supportLabel }),
61682
+ Array.from({ length: bins }, (_2, i) => {
61683
+ const ht = Number(treated[i] ?? 0) / maxVal * halfH;
61684
+ const hc = Number(control[i] ?? 0) / maxVal * halfH;
61685
+ const left = cx2(i) - barW / 2;
61686
+ return /* @__PURE__ */ jsxs(Group, { children: [
61687
+ ht > 0 && /* @__PURE__ */ jsx$1("rect", { x: left, y: centerY - ht, width: barW, height: ht, fill: tCol, fillOpacity: 0.85, rx: 0.5 }),
61688
+ hc > 0 && /* @__PURE__ */ jsx$1("rect", { x: left, y: centerY, width: barW, height: hc, fill: cCol, fillOpacity: 0.6, rx: 0.5 })
61689
+ ] }, i);
61690
+ }),
61691
+ /* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: centerY }, to: { x: innerW, y: centerY }, stroke: t4.ruleStrong, strokeWidth: 1 }),
61692
+ /* @__PURE__ */ jsx$1("text", { x: 0, y: innerH + 4, style: svgText(9, t4.faint, t4.body), children: "untreated ↓" }),
61693
+ ticks2.map((tk, i) => /* @__PURE__ */ jsx$1("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}`))
61694
+ ] }) }) });
61695
+ }
61729
61696
  const SUBJECT_DEFAULT = { one: "record", many: "records" };
61730
61697
  const AUTORUN_MAX_ROWS = 5e4;
61731
61698
  const TONE_TOKEN = {
@@ -61753,7 +61720,7 @@ function kindOfTypeValue(t4) {
61753
61720
  }
61754
61721
  }
61755
61722
  function useColumns(workspace, source) {
61756
- const types = source ? getBindingTypes(workspace, source) : void 0;
61723
+ const types = getBindingTypes(workspace, source);
61757
61724
  return useMemo(() => {
61758
61725
  const st = types == null ? void 0 : types.sourceType;
61759
61726
  if (!st || st.type !== "Array") return { columns: [], rowArrayType: null };
@@ -61765,35 +61732,9 @@ function useColumns(workspace, source) {
61765
61732
  };
61766
61733
  }, [types == null ? void 0 : types.sourceType]);
61767
61734
  }
61768
- function rowMatchesAll(row, preds) {
61769
- return preds.every((p2) => {
61770
- const { fieldId, op } = p2.value;
61771
- const v3 = row[fieldId];
61772
- const ov = op.value;
61773
- switch (op.type) {
61774
- case "eq":
61775
- case "is":
61776
- return v3 === ov;
61777
- case "neq":
61778
- return v3 !== ov;
61779
- case "lt":
61780
- return num(v3) != null && num(ov) != null ? num(v3) < num(ov) : true;
61781
- case "lte":
61782
- return num(v3) != null && num(ov) != null ? num(v3) <= num(ov) : true;
61783
- case "gt":
61784
- return num(v3) != null && num(ov) != null ? num(v3) > num(ov) : true;
61785
- case "gte":
61786
- return num(v3) != null && num(ov) != null ? num(v3) >= num(ov) : true;
61787
- case "in":
61788
- return isEastSet(ov) ? ov.has(v3) : true;
61789
- case "notIn":
61790
- return isEastSet(ov) ? !ov.has(v3) : true;
61791
- default:
61792
- return true;
61793
- }
61794
- });
61735
+ function inPopulation(row, population) {
61736
+ return population.every((p2) => slicePredicateMatches(p2, row));
61795
61737
  }
61796
- const num = (x2) => typeof x2 === "number" ? x2 : typeof x2 === "bigint" ? Number(x2) : null;
61797
61738
  function Cap({ children: children2, help }) {
61798
61739
  return /* @__PURE__ */ jsxs(Fragment, { children: [
61799
61740
  /* @__PURE__ */ jsx$1(Text, { textStyle: "caption.eyebrow", fontSize: "9px", mb: "2.5", children: help ? /* @__PURE__ */ jsx$1(Help, { id: help, children: children2 }) : children2 }),
@@ -61906,7 +61847,7 @@ function LoadingSkeleton() {
61906
61847
  ] })
61907
61848
  ] });
61908
61849
  }
61909
- const experimentValueEqual = equalFor(Experiment.Component.schema);
61850
+ const experimentValueEqual = equivalentFor(Experiment.Component.schema);
61910
61851
  const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
61911
61852
  var _a2, _b2, _c2;
61912
61853
  const v3 = value;
@@ -61916,6 +61857,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
61916
61857
  const bs = useSlotRecipe({ key: "barStrip" })({});
61917
61858
  const statusR = useSlotRecipe({ key: "status" });
61918
61859
  const es = useSlotRecipe({ key: "eyebrowRow" })({});
61860
+ const words = useFormatters();
61919
61861
  const workspace = getReactiveDatasetCache().getConfig().workspace ?? "";
61920
61862
  const data4 = useBindingValue(v3.data);
61921
61863
  const journalBind = useBindingValue(v3.journal.type === "some" ? v3.journal.value : null);
@@ -61963,7 +61905,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
61963
61905
  const population = localPop;
61964
61906
  const filteredRows = useMemo(() => {
61965
61907
  if (!data4.value) return null;
61966
- return population.length ? data4.value.filter((r2) => rowMatchesAll(r2, population)) : data4.value;
61908
+ return population.length ? data4.value.filter((r2) => inPopulation(r2, population)) : data4.value;
61967
61909
  }, [data4.value, population]);
61968
61910
  const fields = useMemo(
61969
61911
  () => columns.filter((c2) => c2.kind !== "other").map((c2) => {
@@ -62065,8 +62007,8 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62065
62007
  }, [ranConfig, config2, meta3, subject]);
62066
62008
  const view = useMemo(() => {
62067
62009
  if (!config2) return null;
62068
- return deriveView(config2, ranConfig ?? config2, columns, shownResult, journalBind.value, meta3, nRows, now2, subject);
62069
- }, [config2, ranConfig, columns, shownResult, journalBind.value, meta3, nRows, now2, subject]);
62010
+ return deriveView(config2, ranConfig ?? config2, columns, shownResult, journalBind.value, meta3, nRows, now2, subject, words);
62011
+ }, [config2, ranConfig, columns, shownResult, journalBind.value, meta3, nRows, now2, subject, words]);
62070
62012
  const designConfigValue = useMemo(() => ({
62071
62013
  alpha: none$1,
62072
62014
  target_power: none$1,
@@ -62079,15 +62021,15 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62079
62021
  var _a3;
62080
62022
  if (tab !== "validate" || !hasDesign || design.pending || precomputedDesign !== null) return;
62081
62023
  if (!filteredRows || !config2 || !shownResult) return;
62082
- if (((_a3 = designSnapRef.current) == null ? void 0 : _a3.result) === shownResult) return;
62024
+ if (Object.is((_a3 = designSnapRef.current) == null ? void 0 : _a3.result, shownResult)) return;
62083
62025
  designSnapRef.current = { result: shownResult, config: ranConfig ?? config2 };
62084
62026
  design.call(filteredRows, ranConfig ?? config2, shownResult, designConfigValue);
62085
62027
  }, [tab, hasDesign, precomputedDesign, filteredRows, config2, ranConfig, shownResult, design, designConfigValue]);
62086
62028
  const vmDesign = useMemo(() => {
62087
- if (precomputedDesign !== null && shownResult !== null && config2) return deriveDesign(precomputedDesign, shownResult, ranConfig ?? config2, meta3);
62088
- return design.result && designSnapRef.current ? deriveDesign(design.result, designSnapRef.current.result, designSnapRef.current.config, meta3) : null;
62089
- }, [precomputedDesign, shownResult, config2, ranConfig, design.result, meta3]);
62090
- const designFresh = precomputedDesign !== null && shownResult !== null || design.result !== null && ((_b2 = designSnapRef.current) == null ? void 0 : _b2.result) === shownResult && !design.pending;
62029
+ if (precomputedDesign !== null && shownResult !== null && config2) return deriveDesign(precomputedDesign, shownResult, ranConfig ?? config2, meta3, words);
62030
+ return design.result && designSnapRef.current ? deriveDesign(design.result, designSnapRef.current.result, designSnapRef.current.config, meta3, words) : null;
62031
+ }, [precomputedDesign, shownResult, config2, ranConfig, design.result, meta3, words]);
62032
+ const designFresh = precomputedDesign !== null && shownResult !== null || design.result !== null && Object.is((_b2 = designSnapRef.current) == null ? void 0 : _b2.result, shownResult) && !design.pending;
62091
62033
  if (!config2 || !view) {
62092
62034
  const failed2 = experiment.status === "failed";
62093
62035
  const noConfigs = !configsBind.error && configs.length === 0;
@@ -62155,7 +62097,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62155
62097
  readonly && /* @__PURE__ */ jsx$1(Box, { as: "span", css: badge({ variant: "plain", size: "sm" }), textTransform: "none", letterSpacing: "normal", children: "View only" }),
62156
62098
  /* @__PURE__ */ jsxs(Box, { as: "span", css: dataStatus.root, children: [
62157
62099
  /* @__PURE__ */ jsx$1(Box, { as: "span", css: dataStatus.indicator }),
62158
- /* @__PURE__ */ jsx$1(Box, { as: "span", css: dataStatus.label, children: stale ? `${nRows} rows` : vs.dataLabel })
62100
+ /* @__PURE__ */ jsx$1(Box, { as: "span", css: dataStatus.label, children: stale ? `${words.number(nRows)} rows` : vs.dataLabel })
62159
62101
  ] }),
62160
62102
  /* @__PURE__ */ jsx$1(GuidanceToggle, { on: guidance, onToggle: () => setGuidance((g2) => !g2) }),
62161
62103
  canRun && /* @__PURE__ */ jsx$1(ActionButton, { button, variant: "solid", label: "Run", onClick: onRun, disabled: runDisabled, pulse: stale }),
@@ -62188,7 +62130,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62188
62130
  "add another"
62189
62131
  ] }) })
62190
62132
  ] }) }),
62191
- /* @__PURE__ */ jsx$1(Step, { n: 4, title: `Which ${subject.many}?`, help: "step_population", children: /* @__PURE__ */ jsx$1(FilterRail, { fields, population, onChange: editPopulation, chip, button, readonly, subjectMany: subject.many }) }),
62133
+ /* @__PURE__ */ jsx$1(Step, { n: 4, title: `Which ${subject.many}?`, help: "step_population", children: /* @__PURE__ */ jsx$1(FilterRail, { fields, population, onChange: editPopulation, chip, button, readonly, subjectMany: subject.many, words }) }),
62192
62134
  /* @__PURE__ */ jsxs(Box, { as: "details", borderTopWidth: "1px", borderColor: "border.subtle", children: [
62193
62135
  /* @__PURE__ */ jsxs(
62194
62136
  Box,
@@ -62306,10 +62248,11 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62306
62248
  subjectMany: subject.many,
62307
62249
  higherBetter,
62308
62250
  badge,
62309
- barList
62251
+ barList,
62252
+ words
62310
62253
  }
62311
62254
  ),
62312
- activeTab === "answer" && !a2 && ref && /* @__PURE__ */ jsx$1(RefusalZone, { refusal: ref, overlap: ov, naiveValue: (shownResult == null ? void 0 : shownResult.naive) ?? 0, outcome: vs.outcomeLabel }),
62255
+ activeTab === "answer" && !a2 && ref && /* @__PURE__ */ jsx$1(RefusalZone, { refusal: ref, overlap: ov, naiveValue: (shownResult == null ? void 0 : shownResult.naive) ?? 0, outcome: vs.outcomeLabel, words }),
62313
62256
  activeTab === "trust" && vr && /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
62314
62257
  /* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", mb: "3.5", children: /* @__PURE__ */ jsx$1(Help, { id: "trust_intro", children: "Before trusting the answer we tried to break it — colour shows pass / caution." }) }),
62315
62258
  /* @__PURE__ */ jsx$1(Box, { layerStyle: "frame.flat", children: vr.checks.map((c2, i) => {
@@ -62337,6 +62280,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62337
62280
  zero: 0,
62338
62281
  tone: "brand",
62339
62282
  xTicks: vr.sens.xTicks,
62283
+ xTickWords: true,
62340
62284
  yTicks: vr.sens.yTicks,
62341
62285
  marks: vr.sens.marks,
62342
62286
  height: vr.sens.marks.length ? 148 : 132
@@ -62382,13 +62326,13 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62382
62326
  /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", gap: "0.5", children: [
62383
62327
  /* @__PURE__ */ jsx$1(Text, { textStyle: "caption.eyebrow", children: vd.recoLabel }),
62384
62328
  /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "baseline", gap: "2", children: [
62385
- /* @__PURE__ */ jsx$1(Text, { textStyle: "mono-kpi", fontFamily: "heading", color: "brand.solid", children: signed(vd.recoEffect) }),
62329
+ /* @__PURE__ */ jsx$1(Text, { textStyle: "mono-kpi", fontFamily: "heading", color: "brand.solid", children: signed(vd.recoEffect, words) }),
62386
62330
  /* @__PURE__ */ jsxs(Text, { textStyle: "mono.sm", color: "fg.muted", children: [
62387
62331
  vd.outcome,
62388
62332
  " · ",
62389
- signed(vd.recoLo),
62333
+ signed(vd.recoLo, words),
62390
62334
  " … ",
62391
- signed(vd.recoHi)
62335
+ signed(vd.recoHi, words)
62392
62336
  ] })
62393
62337
  ] })
62394
62338
  ] }),
@@ -62400,7 +62344,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62400
62344
  vd.outcome,
62401
62345
  " per step"
62402
62346
  ] }),
62403
- /* @__PURE__ */ jsx$1(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) }))) })
62347
+ /* @__PURE__ */ jsx$1(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) }))) })
62404
62348
  ] })
62405
62349
  ] })
62406
62350
  ] }),
@@ -62418,7 +62362,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62418
62362
  " tab for why)."
62419
62363
  ] })
62420
62364
  ] }),
62421
- activeTab === "validate" && (design.status === "failed" && design.error ? /* @__PURE__ */ jsx$1(Box, { px: "4.5", pt: "4.5", children: /* @__PURE__ */ jsx$1(RunError, { error: design.error }) }) : designFresh && vmDesign ? /* @__PURE__ */ jsx$1(ValidatePanel, { vm: vmDesign, barList }) : !hasDesign && precomputedDesign === null ? /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
62365
+ activeTab === "validate" && (design.status === "failed" && design.error ? /* @__PURE__ */ jsx$1(Box, { px: "4.5", pt: "4.5", children: /* @__PURE__ */ jsx$1(RunError, { error: design.error }) }) : designFresh && vmDesign ? /* @__PURE__ */ jsx$1(ValidatePanel, { vm: vmDesign, barList, words }) : !hasDesign && precomputedDesign === null ? /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
62422
62366
  /* @__PURE__ */ jsxs(Box, { display: "inline-flex", alignItems: "center", gap: "2", mb: "2", color: "fg.muted", children: [
62423
62367
  /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation, style: { fontSize: "13px" } }),
62424
62368
  /* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", fontWeight: "semibold", color: "fg.default", children: "No trial recipe for this question" })
@@ -62435,7 +62379,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62435
62379
  /* @__PURE__ */ jsxs(Box, { css: es.root, bg: "bg.canvas", borderTopWidth: "1px", borderColor: "border.subtle", children: [
62436
62380
  /* @__PURE__ */ jsx$1(Box, { css: es.lbl, children: /* @__PURE__ */ jsx$1(Help, { id: "journal", children: "Committed experiments" }) }),
62437
62381
  /* @__PURE__ */ jsx$1(Box, { css: es.meta, children: /* @__PURE__ */ jsxs(Text, { as: "span", children: [
62438
- /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: journal.length }),
62382
+ /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: words.number(journal.length) }),
62439
62383
  " on record",
62440
62384
  journal.length > 50 ? " · showing newest 50" : ""
62441
62385
  ] }) })
@@ -62477,7 +62421,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
62477
62421
  ] })
62478
62422
  ] }) });
62479
62423
  }, (prev2, next2) => experimentValueEqual(prev2.value, next2.value) && prev2.storageKey === next2.storageKey);
62480
- function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMany, higherBetter, badge, barList }) {
62424
+ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMany, higherBetter, badge, barList, words }) {
62481
62425
  const dirUp = a2.effect > 0;
62482
62426
  const statusWord = higherBetter === void 0 ? dirUp ? "Higher" : "Lower" : dirUp === higherBetter ? "Better" : "Worse";
62483
62427
  const lowerWord = a2.naive < 0 ? "lower" : "higher";
@@ -62492,7 +62436,7 @@ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMa
62492
62436
  /* @__PURE__ */ jsx$1(Text, { textStyle: "mono.sm", color: "fg.muted", children: a2.outcome }),
62493
62437
  /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "baseline", gap: "2.5", children: [
62494
62438
  /* @__PURE__ */ jsx$1(Text, { textStyle: "mono-kpi", fontFamily: "heading", fontSize: "32px", color: kpiColor, children: /* @__PURE__ */ jsxs(Help, { id: "answer_effect", children: [
62495
- signed(a2.effect),
62439
+ signed(a2.effect, words),
62496
62440
  a2.unit ? /* @__PURE__ */ jsxs(Text, { as: "span", fontSize: "16px", color: "fg.muted", children: [
62497
62441
  " ",
62498
62442
  a2.unit
@@ -62500,9 +62444,9 @@ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMa
62500
62444
  ] }) }),
62501
62445
  /* @__PURE__ */ jsx$1(Text, { textStyle: "mono.sm", color: "fg.muted", children: /* @__PURE__ */ jsxs(Help, { id: "answer_ci", children: [
62502
62446
  "likely between ",
62503
- signed(a2.lo),
62447
+ signed(a2.lo, words),
62504
62448
  " and ",
62505
- signed(a2.hi)
62449
+ signed(a2.hi, words)
62506
62450
  ] }) })
62507
62451
  ] })
62508
62452
  ] }),
@@ -62566,7 +62510,7 @@ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMa
62566
62510
  " on ",
62567
62511
  /* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", children: a2.outcome }),
62568
62512
  " (",
62569
- signed(a2.naive),
62513
+ signed(a2.naive, words),
62570
62514
  ") — but they also differ most on ",
62571
62515
  /* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", children: top.label }),
62572
62516
  " (",
@@ -62625,13 +62569,13 @@ function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMa
62625
62569
  /* @__PURE__ */ jsx$1(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 }))) })
62626
62570
  ] }),
62627
62571
  /* @__PURE__ */ jsx$1(Box, { mt: "3.5", children: /* @__PURE__ */ jsx$1(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__ */ jsxs(Text, { textStyle: "mono.sm", color: "fg.muted", children: [
62628
- /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: Number(n2) }),
62572
+ /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: words.number(n2) }),
62629
62573
  " ",
62630
62574
  label
62631
62575
  ] }, i)) }) })
62632
62576
  ] });
62633
62577
  }
62634
- function RefusalZone({ refusal, overlap, naiveValue, outcome }) {
62578
+ function RefusalZone({ refusal, overlap, naiveValue, outcome, words }) {
62635
62579
  return /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
62636
62580
  /* @__PURE__ */ jsxs(Box, { display: "inline-flex", alignItems: "center", gap: "2", mb: "2", color: "fg.warning", children: [
62637
62581
  /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation, style: { fontSize: "14px" } }),
@@ -62654,11 +62598,11 @@ function RefusalZone({ refusal, overlap, naiveValue, outcome }) {
62654
62598
  "Raw average difference in ",
62655
62599
  outcome,
62656
62600
  " (context only, not an answer): ",
62657
- /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", color: "fg.muted", children: signed(naiveValue) })
62601
+ /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", color: "fg.muted", children: signed(naiveValue, words) })
62658
62602
  ] })
62659
62603
  ] });
62660
62604
  }
62661
- function ValidatePanel({ vm, barList }) {
62605
+ function ValidatePanel({ vm, barList, words }) {
62662
62606
  const stat = useSlotRecipe({ key: "stat" })({ size: "lg" });
62663
62607
  const meter = useSlotRecipe({ key: "segmentedMeter" })({});
62664
62608
  return /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
@@ -62666,7 +62610,7 @@ function ValidatePanel({ vm, barList }) {
62666
62610
  /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "flex-end", gap: "5", flexWrap: "wrap", children: [
62667
62611
  /* @__PURE__ */ jsxs(Box, { css: stat.root, children: [
62668
62612
  /* @__PURE__ */ jsx$1(Text, { css: stat.label, children: /* @__PURE__ */ jsx$1(Help, { id: "validate_size", children: vm.holdback ? "to hold back from" : "to run" }) }),
62669
- vm.faint ? /* @__PURE__ */ jsx$1(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__ */ jsx$1(Text, { css: stat.valueText, color: "brand.solid", children: vm.primary.nTotal.toLocaleString() })
62613
+ vm.faint ? /* @__PURE__ */ jsx$1(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__ */ jsx$1(Text, { css: stat.valueText, color: "brand.solid", children: words.number(vm.primary.nTotal) })
62670
62614
  ] }),
62671
62615
  /* @__PURE__ */ jsxs(Box, { css: meter.root, flex: "1", minW: "220px", children: [
62672
62616
  /* @__PURE__ */ jsx$1(Text, { css: meter.label, children: /* @__PURE__ */ jsx$1(Help, { id: "validate_split", children: vm.holdback ? "Hold-back split" : "Split" }) }),
@@ -62678,7 +62622,7 @@ function ValidatePanel({ vm, barList }) {
62678
62622
  /* @__PURE__ */ jsxs(Box, { css: meter.keyItem, children: [
62679
62623
  /* @__PURE__ */ jsx$1(Box, { css: meter.keyDot, bg: "brand.solid" }),
62680
62624
  /* @__PURE__ */ jsxs("span", { children: [
62681
- /* @__PURE__ */ jsx$1(Text, { as: "span", css: meter.valueText, children: vm.primary.nTreated.toLocaleString() }),
62625
+ /* @__PURE__ */ jsx$1(Text, { as: "span", css: meter.valueText, children: words.number(vm.primary.nTreated) }),
62682
62626
  " ",
62683
62627
  vm.holdback ? "treated" : "get it"
62684
62628
  ] })
@@ -62686,7 +62630,7 @@ function ValidatePanel({ vm, barList }) {
62686
62630
  /* @__PURE__ */ jsxs(Box, { css: meter.keyItem, children: [
62687
62631
  /* @__PURE__ */ jsx$1(Box, { css: meter.keyDot, bg: "bg.emphasized" }),
62688
62632
  /* @__PURE__ */ jsxs("span", { children: [
62689
- /* @__PURE__ */ jsx$1(Text, { as: "span", css: meter.valueText, children: vm.primary.nControl.toLocaleString() }),
62633
+ /* @__PURE__ */ jsx$1(Text, { as: "span", css: meter.valueText, children: words.number(vm.primary.nControl) }),
62690
62634
  " ",
62691
62635
  vm.holdback ? "held back" : "left alone"
62692
62636
  ] })
@@ -62719,16 +62663,16 @@ function ValidatePanel({ vm, barList }) {
62719
62663
  vm.alternates.length > 0 && /* @__PURE__ */ jsx$1(Box, { display: "flex", flexDirection: "column", gap: "1.5", mt: "3", pt: "3", borderTopWidth: "1px", borderColor: "border.subtle", children: vm.alternates.map((o2, i) => /* @__PURE__ */ jsxs(Text, { textStyle: "caption", color: "fg.muted", children: [
62720
62664
  /* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", color: "fg.default", children: o2.label }),
62721
62665
  " · ",
62722
- o2.nTotal.toLocaleString(),
62666
+ words.number(o2.nTotal),
62723
62667
  " total (",
62724
- o2.nTreated.toLocaleString(),
62668
+ words.number(o2.nTreated),
62725
62669
  " / ",
62726
- o2.nControl.toLocaleString(),
62670
+ words.number(o2.nControl),
62727
62671
  ")"
62728
62672
  ] }, i)) })
62729
62673
  ] });
62730
62674
  }
62731
- function FilterRail({ fields, population, onChange: onChange2, chip, button, readonly, subjectMany }) {
62675
+ function FilterRail({ fields, population, onChange: onChange2, chip, button, readonly, subjectMany, words }) {
62732
62676
  const [open, setOpen] = useState(null);
62733
62677
  const replaceAt = (i, p2) => onChange2(population.map((f2, j2) => j2 === i ? p2 : f2));
62734
62678
  const removeAt = (i) => onChange2(population.filter((_2, j2) => j2 !== i));
@@ -62737,7 +62681,7 @@ function FilterRail({ fields, population, onChange: onChange2, chip, button, rea
62737
62681
  return /* @__PURE__ */ jsx$1(Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: population.length === 0 ? /* @__PURE__ */ jsxs(Box, { css: chip({ tone: "plain", numeric: true, shape: "rounded" }), children: [
62738
62682
  "all ",
62739
62683
  subjectMany
62740
- ] }) : population.map((pred, i) => /* @__PURE__ */ jsx$1(Box, { css: chip({ tone: "brand", numeric: true, shape: "rounded" }), flexShrink: 0, children: /* @__PURE__ */ jsx$1(Box, { as: "span", whiteSpace: "nowrap", children: formatPredicate(pred) }) }, i)) });
62684
+ ] }) : population.map((pred, i) => /* @__PURE__ */ jsx$1(Box, { css: chip({ tone: "brand", numeric: true, shape: "rounded" }), flexShrink: 0, children: /* @__PURE__ */ jsx$1(Box, { as: "span", whiteSpace: "nowrap", children: formatPredicate(pred, words) }) }, i)) });
62741
62685
  }
62742
62686
  return /* @__PURE__ */ jsxs(Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: [
62743
62687
  population.map((pred, i) => /* @__PURE__ */ jsx$1(
@@ -62751,7 +62695,7 @@ function FilterRail({ fields, population, onChange: onChange2, chip, button, rea
62751
62695
  ] }),
62752
62696
  footActions: done,
62753
62697
  trigger: /* @__PURE__ */ jsxs(Box, { css: chip({ tone: "brand", numeric: true, shape: "rounded" }), cursor: "pointer", flexShrink: 0, children: [
62754
- /* @__PURE__ */ jsx$1(Box, { as: "span", whiteSpace: "nowrap", children: formatPredicate(pred) }),
62698
+ /* @__PURE__ */ jsx$1(Box, { as: "span", whiteSpace: "nowrap", children: formatPredicate(pred, words) }),
62755
62699
  /* @__PURE__ */ jsx$1(Box, { as: "button", display: "inline-flex", alignItems: "center", cursor: "pointer", color: "brand.fg", flexShrink: "0", fontSize: "10px", onClick: (e3) => {
62756
62700
  e3.stopPropagation();
62757
62701
  removeAt(i);
@@ -62877,20 +62821,8 @@ function viewFor(binding) {
62877
62821
  const patch = binding.patch.type === "some" ? binding.patch.value : void 0;
62878
62822
  return defaultBindRuntime.buildBindHandle(types.sourceType, source, patch, binding.mode.type);
62879
62823
  }
62880
- function stableStringify(v3) {
62881
- return JSON.stringify(v3, (_k, x2) => {
62882
- if (typeof x2 === "bigint") return `${x2}n`;
62883
- if (x2 instanceof Date) return x2.toISOString();
62884
- if (isEastSet(x2)) return [...x2].sort();
62885
- if (isEastDict(x2)) return [...x2.entries()].sort((a2, b2) => String(a2[0]).localeCompare(String(b2[0])));
62886
- return x2;
62887
- });
62888
- }
62889
- function hashString2(s2) {
62890
- let h2 = 5381;
62891
- for (let i = 0; i < s2.length; i++) h2 = (h2 << 5) + h2 + s2.charCodeAt(i) | 0;
62892
- return (h2 >>> 0).toString(36);
62893
- }
62824
+ const printDescriptors = printFor(StructType({ decisions: ArrayType(DiffBindingType), judgements: DiffBindingType }));
62825
+ const printTypeValue = printFor(EastTypeValueType);
62894
62826
  function readSelectionAt(selectionKey) {
62895
62827
  StateRuntime.trackKey(selectionKey);
62896
62828
  const bytes = StateRuntime.getStore().read(selectionKey);
@@ -62932,16 +62864,6 @@ function removeFromOwningView(decisions, caseId) {
62932
62864
  }
62933
62865
  }
62934
62866
  const decisionHandleCache = /* @__PURE__ */ new Map();
62935
- function typeToken(tv) {
62936
- const seen = /* @__PURE__ */ new WeakSet();
62937
- return JSON.stringify(tv, (_k, v3) => {
62938
- if (typeof v3 === "object" && v3 !== null) {
62939
- if (seen.has(v3)) return "<cyc>";
62940
- seen.add(v3);
62941
- }
62942
- return typeof v3 === "bigint" ? `${v3}n` : v3;
62943
- });
62944
- }
62945
62867
  function compileDecisionMethods(constraintType, decisions, judgements, selectionKey) {
62946
62868
  const platform = getRegisteredPlatformImplementations();
62947
62869
  const c2 = fromEastTypeValue(constraintType);
@@ -63009,7 +62931,7 @@ function buildDecisionHandle(decisions, judgements, constraintType) {
63009
62931
  const at = (j2) => j2.resolvedAt.type === "some" ? j2.resolvedAt.value.getTime() : 0;
63010
62932
  return entries.sort((a2, b2) => at(b2) - at(a2));
63011
62933
  };
63012
- const cacheKey = `${hashString2(stableStringify({ decisions, judgements }))}|${typeToken(cType)}`;
62934
+ const cacheKey = `${printDescriptors({ decisions, judgements })}|${printTypeValue(canonicalTypeValue(cType))}`;
63013
62935
  let methods = decisionHandleCache.get(cacheKey);
63014
62936
  if (methods === void 0) {
63015
62937
  methods = compileDecisionMethods(cType, decisions, judgements, selectionKey);
@@ -63199,91 +63121,71 @@ const OP_WORDS = {
63199
63121
  notIn: "not in",
63200
63122
  is: "is"
63201
63123
  };
63202
- function formatScalar(v3) {
63203
- if (v3 instanceof Date) {
63204
- return `${v3.toLocaleString("en", { month: "short" })} ${v3.getDate()}`;
63205
- }
63206
- if (isEastSet(v3)) {
63207
- return `{${[...v3].map(formatScalar).join(", ")}}`;
63124
+ const PRINTERS = /* @__PURE__ */ new WeakMap();
63125
+ function printerOf(contract) {
63126
+ let printer = PRINTERS.get(contract);
63127
+ if (printer === void 0) {
63128
+ const context = /* @__PURE__ */ new Map();
63129
+ printFor(contract.type, context);
63130
+ printer = (type) => printFor(type, context);
63131
+ PRINTERS.set(contract, printer);
63208
63132
  }
63209
- if (v3 !== null && typeof v3 === "object" && !v3.type) {
63210
- return Object.entries(v3).map(([k2, x2]) => `${k2} ${formatScalar(x2)}`).join(" · ");
63211
- }
63212
- return String(v3);
63133
+ return printer;
63213
63134
  }
63214
- function formatConstraint(constraint, payloadType, levers) {
63215
- var _a2, _b2;
63216
- const c2 = constraint;
63217
- const lever = ((_a2 = levers == null ? void 0 : levers.find((l2) => l2.case === c2.type)) == null ? void 0 : _a2.label) ?? c2.type;
63218
- if ((payloadType == null ? void 0 : payloadType.type) === "Variant") {
63219
- const op = c2.value;
63220
- const word = OP_WORDS[op.type] ?? op.type;
63221
- const opType = (_b2 = payloadType.cases) == null ? void 0 : _b2[op.type];
63222
- if ((opType == null ? void 0 : opType.type) === "Struct" && op.value !== null && typeof op.value === "object") {
63223
- const r2 = op.value;
63224
- if ("min" in r2 && "max" in r2) {
63225
- return { lever, op: word, value: `${formatScalar(r2.min)} – ${formatScalar(r2.max)}` };
63226
- }
63135
+ function formatValue(value, type, words, print) {
63136
+ switch (type.type) {
63137
+ case "DateTime":
63138
+ return words.monthDay(value);
63139
+ case "Float":
63140
+ return words.float(value);
63141
+ case "String":
63142
+ return value;
63143
+ case "Set": {
63144
+ const member = type.value;
63145
+ return `{${[...value].map((m2) => formatValue(m2, member, words, print)).join(", ")}}`;
63227
63146
  }
63228
- return { lever, op: word, value: formatScalar(op.value) };
63229
- }
63230
- return { lever, op: "·", value: formatScalar(c2.value) };
63231
- }
63232
- const PRIMITIVES = /* @__PURE__ */ new Set(["String", "Integer", "Float", "DateTime", "Boolean"]);
63233
- function normalizeTypeValue(tv) {
63234
- var _a2;
63235
- const n2 = tv;
63236
- if (n2.cases !== void 0 || n2.fields !== void 0) {
63237
- const out = { type: n2.type };
63238
- if (n2.cases) out.cases = Object.fromEntries(Object.entries(n2.cases).map(([k2, v3]) => [k2, normalizeTypeValue(v3)]));
63239
- if (n2.fields) out.fields = Object.fromEntries(Object.entries(n2.fields).map(([k2, v3]) => [k2, normalizeTypeValue(v3)]));
63240
- if (n2.key) out.key = normalizeTypeValue(n2.key);
63241
- if (n2.value !== void 0 && (n2.type === "Array" || n2.type === "Dict")) out.value = normalizeTypeValue(n2.value);
63242
- return out;
63243
- }
63244
- switch (n2.type) {
63245
63147
  case "Struct":
63246
- return { type: "Struct", fields: Object.fromEntries(n2.value.map((f2) => [f2.name, normalizeTypeValue(f2.type)])) };
63247
- case "Variant":
63248
- return { type: "Variant", cases: Object.fromEntries(n2.value.map((f2) => [f2.name, normalizeTypeValue(f2.type)])) };
63249
- case "Array":
63250
- return { type: "Array", value: normalizeTypeValue(n2.value) };
63251
- case "Dict": {
63252
- const d2 = n2.value;
63253
- return { type: "Dict", key: normalizeTypeValue(d2.key), value: normalizeTypeValue(d2.value) };
63254
- }
63255
- case "Recursive": {
63256
- const w2 = n2.value;
63257
- if ((w2 == null ? void 0 : w2.type) === "wrapper" && ((_a2 = w2.value) == null ? void 0 : _a2.inner)) return normalizeTypeValue(w2.value.inner);
63258
- return { type: n2.type };
63259
- }
63148
+ return type.value.map((f2) => `${f2.name} ${formatValue(value[f2.name], f2.type, words, print)}`).join(" · ");
63260
63149
  default:
63261
- return { type: n2.type };
63150
+ return print(type)(value);
63262
63151
  }
63263
63152
  }
63264
- function emptyFor(node2) {
63265
- switch (node2.type) {
63266
- case "Integer":
63267
- return 0n;
63268
- case "Float":
63269
- return 0;
63270
- case "DateTime":
63271
- return /* @__PURE__ */ new Date();
63272
- case "Boolean":
63273
- return false;
63274
- case "String":
63275
- return "";
63276
- case "Struct":
63277
- return Object.fromEntries(Object.entries(node2.fields ?? {}).map(([k2, f2]) => [k2, emptyFor(f2)]));
63278
- default:
63279
- return null;
63153
+ function formatConstraint(constraint, contract, levers, words = formatters()) {
63154
+ var _a2;
63155
+ const lever = ((_a2 = levers == null ? void 0 : levers.find((l2) => l2.case === constraint.type)) == null ? void 0 : _a2.label) ?? constraint.type;
63156
+ const payload = contract == null ? void 0 : contract.payloads.get(constraint.type);
63157
+ if (contract === void 0 || payload === void 0) return { lever, op: "·", value: "" };
63158
+ const print = printerOf(contract);
63159
+ if (payload.type === "Variant") {
63160
+ const op = constraint.value;
63161
+ const word = OP_WORDS[op.type] ?? op.type;
63162
+ const opType = payload.value.find((c2) => c2.name === op.type).type;
63163
+ if (opType.type === "Struct") {
63164
+ const fields = opType.value;
63165
+ const min4 = fields.find((f2) => f2.name === "min");
63166
+ const max5 = fields.find((f2) => f2.name === "max");
63167
+ if (min4 !== void 0 && max5 !== void 0) {
63168
+ const range = op.value;
63169
+ return { lever, op: word, value: `${formatValue(range.min, min4.type, words, print)} – ${formatValue(range.max, max5.type, words, print)}` };
63170
+ }
63171
+ }
63172
+ return { lever, op: word, value: formatValue(op.value, opType, words, print) };
63280
63173
  }
63174
+ return { lever, op: "·", value: formatValue(constraint.value, payload, words, print) };
63281
63175
  }
63282
- function leverPayloadEditable(node2) {
63283
- if (!node2) return false;
63284
- if (PRIMITIVES.has(node2.type)) return true;
63285
- if (node2.type === "Struct") return Object.values(node2.fields ?? {}).every((f2) => PRIMITIVES.has(f2.type));
63286
- 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)));
63176
+ const PRIMITIVES = /* @__PURE__ */ new Set(["String", "Integer", "Float", "DateTime", "Boolean"]);
63177
+ const NULL_TYPE = toEastTypeValue(NullType);
63178
+ function emptyFor(type) {
63179
+ if (type.type === "DateTime") return /* @__PURE__ */ new Date();
63180
+ if (type.type === "Struct") return Object.fromEntries(type.value.map((f2) => [f2.name, emptyFor(f2.type)]));
63181
+ return defaultValue(type);
63182
+ }
63183
+ function leverPayloadEditable(payload) {
63184
+ if (payload === void 0) return false;
63185
+ const primitive = (t4) => PRIMITIVES.has(t4.type);
63186
+ const structOfPrimitives = (t4) => t4.type === "Struct" && t4.value.every((f2) => primitive(f2.type));
63187
+ if (primitive(payload) || structOfPrimitives(payload)) return true;
63188
+ if (payload.type === "Variant") return payload.value.every((c2) => primitive(c2.type) || structOfPrimitives(c2.type));
63287
63189
  return false;
63288
63190
  }
63289
63191
  const inputStyle = some({ size: some(variant("sm", null)) });
@@ -63291,17 +63193,17 @@ function LeverEditor({ leverCase, payload, onInject }) {
63291
63193
  var _a2;
63292
63194
  const button = useRecipe({ key: "button" });
63293
63195
  const isOpVariant = payload.type === "Variant";
63294
- const ops = useMemo(() => isOpVariant ? Object.keys(payload.cases ?? {}) : [], [isOpVariant, payload]);
63196
+ const ops = useMemo(() => payload.type === "Variant" ? payload.value.map((c2) => c2.name) : [], [payload]);
63295
63197
  const [opTag, setOpTag] = useState(ops[0] ?? "");
63296
- const active = isOpVariant ? ((_a2 = payload.cases) == null ? void 0 : _a2[opTag]) ?? { type: "Null" } : payload;
63198
+ const active = payload.type === "Variant" ? ((_a2 = payload.value.find((c2) => c2.name === opTag)) == null ? void 0 : _a2.type) ?? NULL_TYPE : payload;
63297
63199
  const valRef = useRef(emptyFor(active));
63298
63200
  const keyRef = useRef(`${leverCase}:${opTag}`);
63299
63201
  if (keyRef.current !== `${leverCase}:${opTag}`) {
63300
63202
  keyRef.current = `${leverCase}:${opTag}`;
63301
63203
  valRef.current = emptyFor(active);
63302
63204
  }
63303
- const primitiveInput = (node2, key, get3, set3) => {
63304
- switch (node2.type) {
63205
+ const primitiveInput = (type, key, get3, set3) => {
63206
+ switch (type.type) {
63305
63207
  case "Integer":
63306
63208
  return /* @__PURE__ */ jsx$1(EastChakraIntegerInput, { value: { value: get3(), onChange: some(set3), style: inputStyle } }, key);
63307
63209
  case "Float":
@@ -63314,7 +63216,7 @@ function LeverEditor({ leverCase, payload, onInject }) {
63314
63216
  {
63315
63217
  ariaLabel: key,
63316
63218
  value: {
63317
- value: some(String(get3())),
63219
+ value: some(get3() === true ? "true" : "false"),
63318
63220
  items: [{ value: "true", label: "true", disabled: none$1 }, { value: "false", label: "false", disabled: none$1 }],
63319
63221
  placeholder: none$1,
63320
63222
  multiple: none$1,
@@ -63327,17 +63229,19 @@ function LeverEditor({ leverCase, payload, onInject }) {
63327
63229
  },
63328
63230
  key
63329
63231
  );
63232
+ case "String":
63233
+ return /* @__PURE__ */ jsx$1(EastChakraStringInput, { value: { value: get3(), onChange: some(set3), style: inputStyle } }, key);
63330
63234
  default:
63331
- return /* @__PURE__ */ jsx$1(EastChakraStringInput, { value: { value: String(get3() ?? ""), onChange: some(set3), style: inputStyle } }, key);
63235
+ return null;
63332
63236
  }
63333
63237
  };
63334
63238
  const valueControls = useMemo(() => {
63335
63239
  const k2 = keyRef.current;
63336
63240
  if (active.type === "Struct") {
63337
- return Object.entries(active.fields ?? {}).map(([field, node2]) => /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "6px", minW: 0, children: [
63241
+ return active.value.map(({ name: field, type }) => /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "6px", minW: 0, children: [
63338
63242
  /* @__PURE__ */ jsx$1(Box, { as: "span", textStyle: "caption.eyebrow", color: "fg.subtle", flexShrink: 0, children: field }),
63339
63243
  primitiveInput(
63340
- node2,
63244
+ type,
63341
63245
  `${k2}.${field}.in`,
63342
63246
  () => valRef.current[field],
63343
63247
  (v3) => {
@@ -63393,11 +63297,12 @@ function LeverEditor({ leverCase, payload, onInject }) {
63393
63297
  }
63394
63298
  );
63395
63299
  }
63396
- function fmt(d2, n2, showSign = false) {
63397
- return formatTick(n2, getSomeorUndefined(d2.format), showSign);
63300
+ function fmt(words, d2, n2, showSign = false) {
63301
+ return words.value(n2, getSomeorUndefined(d2.format), showSign);
63398
63302
  }
63399
63303
  const caption = { textStyle: "caption.eyebrow", color: "fg.muted" };
63400
63304
  const EvidenceFacet = memo(function EvidenceFacet2({ decision, children: children2 }) {
63305
+ const words = useFormatters();
63401
63306
  const stakes = getSomeorUndefined(decision.stakes);
63402
63307
  const downside = getSomeorUndefined(decision.downside);
63403
63308
  const confidence = getSomeorUndefined(decision.confidence);
@@ -63413,15 +63318,12 @@ const EvidenceFacet = memo(function EvidenceFacet2({ decision, children: childre
63413
63318
  ] }),
63414
63319
  downside !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
63415
63320
  "if wrong ",
63416
- /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", color: "fg.danger", children: fmt(decision, downside, true) }),
63321
+ /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", color: "fg.danger", children: fmt(words, decision, downside, true) }),
63417
63322
  " · "
63418
63323
  ] }),
63419
63324
  confidence !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
63420
63325
  "confidence ",
63421
- /* @__PURE__ */ jsxs(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: [
63422
- Math.round(confidence * 100),
63423
- "%"
63424
- ] })
63326
+ /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: words.percent(confidence) })
63425
63327
  ] })
63426
63328
  ] })
63427
63329
  ] }),
@@ -63437,8 +63339,9 @@ const EvidenceFacet = memo(function EvidenceFacet2({ decision, children: childre
63437
63339
  children2
63438
63340
  ] });
63439
63341
  });
63342
+ const compareValues$1 = compareFor(FloatType);
63440
63343
  function rankOptions(d2) {
63441
- const alternatives = [...d2.alternatives].sort((a2, b2) => b2.value - a2.value).map((a2) => ({
63344
+ const alternatives = [...d2.alternatives].sort((a2, b2) => compareValues$1(b2.value, a2.value)).map((a2) => ({
63442
63345
  label: a2.label,
63443
63346
  value: a2.value,
63444
63347
  downside: getSomeorUndefined(a2.downside),
@@ -63458,14 +63361,15 @@ function rankOptions(d2) {
63458
63361
  ...alternatives
63459
63362
  ].map((o2, i) => ({ ...o2, rank: i + 1 }));
63460
63363
  }
63461
- function metaLine(o2) {
63364
+ function metaLine(o2, words) {
63462
63365
  const parts = [];
63463
63366
  if (o2.recommended) parts.push("recommended");
63464
- if (o2.confidence !== void 0) parts.push(`${Math.round(o2.confidence * 100)}% conf`);
63367
+ if (o2.confidence !== void 0) parts.push(`${words.percent(o2.confidence)} conf`);
63465
63368
  if (!o2.recommended && o2.note !== void 0) parts.push(o2.note);
63466
63369
  return parts.join(" · ");
63467
63370
  }
63468
63371
  const OptionsFacet = memo(function OptionsFacet2({ decision, narrow }) {
63372
+ const words = useFormatters();
63469
63373
  const options2 = rankOptions(decision);
63470
63374
  const maxUp = Math.max(...options2.map((o2) => Math.max(o2.value, 0)), 1e-9);
63471
63375
  const maxDown = Math.max(...options2.map((o2) => Math.abs(o2.downside ?? 0)), 1e-9);
@@ -63481,7 +63385,7 @@ const OptionsFacet = memo(function OptionsFacet2({ decision, narrow }) {
63481
63385
  return /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", gap: "10px", children: [
63482
63386
  /* @__PURE__ */ jsxs(Text, { ...caption, color: "fg", children: [
63483
63387
  "Options · ",
63484
- options2.length,
63388
+ words.number(options2.length),
63485
63389
  " evaluated"
63486
63390
  ] }),
63487
63391
  options2.map((o2) => /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", gap: "4px", pl: "8px", ...o2.recommended ? { boxShadow: "inset 2px 0 0 var(--chakra-colors-accent-brand)" } : {}, children: [
@@ -63490,8 +63394,8 @@ const OptionsFacet = memo(function OptionsFacet2({ decision, narrow }) {
63490
63394
  " ",
63491
63395
  /* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: o2.recommended ? "semibold" : "normal", children: o2.label })
63492
63396
  ] }),
63493
- meter(upLabel, o2.value / maxUp, fmt(decision, o2.value, signed2), signed2 ? "success" : "neutral"),
63494
- meter("If wrong", (o2.downside ?? 0) / maxDown, o2.downside !== void 0 ? fmt(decision, o2.downside, true) : "—", "danger")
63397
+ meter(upLabel, o2.value / maxUp, fmt(words, decision, o2.value, signed2), signed2 ? "success" : "neutral"),
63398
+ meter("If wrong", (o2.downside ?? 0) / maxDown, o2.downside !== void 0 ? fmt(words, decision, o2.downside, true) : "—", "danger")
63495
63399
  ] }, o2.rank))
63496
63400
  ] });
63497
63401
  }
@@ -63499,7 +63403,7 @@ const OptionsFacet = memo(function OptionsFacet2({ decision, narrow }) {
63499
63403
  /* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: "minmax(180px, 1.1fr) 1fr 1fr", alignItems: "baseline", gap: "8px", children: [
63500
63404
  /* @__PURE__ */ jsxs(Text, { ...caption, color: "fg", children: [
63501
63405
  "Options · ",
63502
- options2.length,
63406
+ words.number(options2.length),
63503
63407
  " evaluated"
63504
63408
  ] }),
63505
63409
  /* @__PURE__ */ jsx$1(Text, { ...caption, textAlign: "center", children: "If wrong" }),
@@ -63521,15 +63425,15 @@ const OptionsFacet = memo(function OptionsFacet2({ decision, narrow }) {
63521
63425
  /* @__PURE__ */ jsxs(Box, { minW: 0, pl: o2.recommended ? "6px" : "0", display: "flex", alignItems: "baseline", gap: "6px", children: [
63522
63426
  /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontSize: "11px", color: "fg.subtle", flexShrink: 0, children: o2.rank }),
63523
63427
  /* @__PURE__ */ jsx$1(Text, { as: "span", fontSize: "12.5px", fontWeight: o2.recommended ? "semibold" : "normal", flexShrink: 0, children: o2.label }),
63524
- metaLine(o2) !== "" && /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontSize: "10.5px", color: "fg.muted", minW: 0, truncate: true, children: metaLine(o2) })
63428
+ metaLine(o2, words) !== "" && /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontSize: "10.5px", color: "fg.muted", minW: 0, truncate: true, children: metaLine(o2, words) })
63525
63429
  ] }),
63526
63430
  /* @__PURE__ */ jsx$1(Box, { display: "flex", justifyContent: "flex-end", alignItems: "center", gap: "6px", height: "16px", children: o2.downside !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
63527
- /* @__PURE__ */ jsx$1(Text, { fontSize: "10.5px", fontFamily: "mono", color: "fg.danger", flexShrink: 0, children: fmt(decision, o2.downside, true) }),
63431
+ /* @__PURE__ */ jsx$1(Text, { fontSize: "10.5px", fontFamily: "mono", color: "fg.danger", flexShrink: 0, children: fmt(words, decision, o2.downside, true) }),
63528
63432
  /* @__PURE__ */ jsx$1(Box, { height: "12px", width: `${Math.round(downFrac * 100)}%`, bg: "fg.danger", opacity: 0.55 })
63529
63433
  ] }) }),
63530
63434
  /* @__PURE__ */ jsx$1(Box, { display: "flex", alignItems: "center", gap: "6px", height: "16px", borderLeftWidth: "1px", borderColor: "border.strong", children: o2.value > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
63531
63435
  /* @__PURE__ */ jsx$1(Box, { height: "12px", width: `${Math.round(upFrac * 100)}%`, bg: signed2 ? "fg.success" : "fg.subtle", opacity: 0.6 }),
63532
- /* @__PURE__ */ jsx$1(Text, { fontSize: "10.5px", fontFamily: "mono", color: signed2 ? "fg.success" : "fg.muted", flexShrink: 0, children: fmt(decision, o2.value, signed2) })
63436
+ /* @__PURE__ */ jsx$1(Text, { fontSize: "10.5px", fontFamily: "mono", color: signed2 ? "fg.success" : "fg.muted", flexShrink: 0, children: fmt(words, decision, o2.value, signed2) })
63533
63437
  ] }) })
63534
63438
  ]
63535
63439
  },
@@ -63543,8 +63447,9 @@ const ANSWERS = [
63543
63447
  { literal: "no", label: "No" },
63544
63448
  { literal: "unknown", label: "Don't know" }
63545
63449
  ];
63546
- const JudgementFacet = memo(function JudgementFacet2({ decision, handle, leverPayloads }) {
63450
+ const JudgementFacet = memo(function JudgementFacet2({ decision, handle, contract }) {
63547
63451
  var _a2;
63452
+ const words = useFormatters();
63548
63453
  const button = useRecipe({ key: "button" });
63549
63454
  const input = useRecipe({ key: "input" });
63550
63455
  const judgement = handle.judgementFor(decision.id);
@@ -63557,11 +63462,12 @@ const JudgementFacet = memo(function JudgementFacet2({ decision, handle, leverPa
63557
63462
  if (knowledge !== stagedKnowledge) handle.addKnowledge(decision.id, knowledge);
63558
63463
  }, [knowledge, stagedKnowledge, handle, decision.id]);
63559
63464
  const levers = useMemo(
63560
- () => decision.levers.filter((l2) => leverPayloadEditable(leverPayloads[l2.case])),
63561
- [decision.levers, leverPayloads]
63465
+ () => decision.levers.filter((l2) => leverPayloadEditable(contract == null ? void 0 : contract.payloads.get(l2.case))),
63466
+ [decision.levers, contract]
63562
63467
  );
63563
63468
  const [leverCase, setLeverCase] = useState(((_a2 = levers[0]) == null ? void 0 : _a2.case) ?? "");
63564
63469
  const activeLever = levers.find((l2) => l2.case === leverCase) ?? levers[0];
63470
+ const activePayload = activeLever === void 0 ? void 0 : contract == null ? void 0 : contract.payloads.get(activeLever.case);
63565
63471
  const gate = handle.commitStateFor(decision.id);
63566
63472
  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;
63567
63473
  const onInject = useCallback((constraint) => {
@@ -63607,8 +63513,7 @@ const JudgementFacet = memo(function JudgementFacet2({ decision, handle, leverPa
63607
63513
  (levers.length > 0 || judgement.constraints.length > 0) && /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", gap: "6px", children: [
63608
63514
  /* @__PURE__ */ jsx$1(Text, { ...caption, children: "Inject constraint · next run folds it in" }),
63609
63515
  judgement.constraints.length > 0 && /* @__PURE__ */ jsx$1(Box, { display: "flex", gap: "12px", flexWrap: "wrap", children: judgement.constraints.map((c2, i) => {
63610
- const tag = c2.type;
63611
- const f2 = formatConstraint(c2, leverPayloads[tag], decision.levers);
63516
+ const f2 = formatConstraint(c2, contract, decision.levers, words);
63612
63517
  return /* @__PURE__ */ jsxs(Text, { as: "span", fontFamily: "mono", fontSize: "11px", children: [
63613
63518
  /* @__PURE__ */ jsx$1(Text, { as: "span", color: "accent.brand", fontWeight: "semibold", children: f2.lever }),
63614
63519
  " ",
@@ -63617,7 +63522,7 @@ const JudgementFacet = memo(function JudgementFacet2({ decision, handle, leverPa
63617
63522
  /* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", children: f2.value })
63618
63523
  ] }, i);
63619
63524
  }) }),
63620
- activeLever !== void 0 && /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap", children: [
63525
+ activeLever !== void 0 && activePayload !== void 0 && /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "8px", flexWrap: "wrap", children: [
63621
63526
  levers.length > 1 ? /* @__PURE__ */ jsx$1(Box, { flexShrink: 0, css: { "& [data-scope=select][data-part=root]": { width: "auto", minWidth: "160px" } }, children: /* @__PURE__ */ jsx$1(
63622
63527
  EastChakraSelect,
63623
63528
  {
@@ -63639,7 +63544,7 @@ const JudgementFacet = memo(function JudgementFacet2({ decision, handle, leverPa
63639
63544
  LeverEditor,
63640
63545
  {
63641
63546
  leverCase: activeLever.case,
63642
- payload: leverPayloads[activeLever.case],
63547
+ payload: activePayload,
63643
63548
  onInject
63644
63549
  },
63645
63550
  activeLever.case
@@ -63662,11 +63567,54 @@ const JudgementFacet = memo(function JudgementFacet2({ decision, handle, leverPa
63662
63567
  ] })
63663
63568
  ] });
63664
63569
  });
63570
+ function body(type) {
63571
+ return type.type === "Recursive" && type.value.type === "wrapper" ? type.value.value.inner : type;
63572
+ }
63573
+ function constraintContractOf(judgementsType) {
63574
+ const dict = body(judgementsType);
63575
+ if (dict.type !== "Dict") return void 0;
63576
+ const record = body(dict.value.value);
63577
+ if (record.type !== "Struct") return void 0;
63578
+ const field = record.value.find((f2) => f2.name === "constraints");
63579
+ if (field === void 0) return void 0;
63580
+ const constraints = body(field.type);
63581
+ if (constraints.type !== "Array") return void 0;
63582
+ const contract = constraints.value;
63583
+ const cases = body(contract);
63584
+ if (cases.type !== "Variant") return void 0;
63585
+ return {
63586
+ type: contract,
63587
+ payloads: new Map(cases.value.map((c2) => [c2.name, c2.type]))
63588
+ };
63589
+ }
63590
+ function useConstraintContract(ref) {
63591
+ const workspace = getReactiveDatasetCache().getConfig().workspace ?? "";
63592
+ return useMemo(() => {
63593
+ if (ref === null) return void 0;
63594
+ const judgements = getBindingTypes(workspace, ref.judgements.source);
63595
+ return judgements === void 0 ? void 0 : constraintContractOf(judgements.sourceType);
63596
+ }, [ref, workspace]);
63597
+ }
63665
63598
  const URGENCY_RANK = {
63666
63599
  overdue: 0,
63667
63600
  due: 1,
63668
63601
  routine: 2
63669
63602
  };
63603
+ const compareInstants = compareFor(DateTimeType);
63604
+ const compareValues = compareFor(FloatType);
63605
+ function compareByUrgency(a2, b2) {
63606
+ const rank = URGENCY_RANK[a2.urgency.type] - URGENCY_RANK[b2.urgency.type];
63607
+ if (rank !== 0) return rank;
63608
+ const da = a2.deadline.type === "some" ? a2.deadline.value : void 0;
63609
+ const db = b2.deadline.type === "some" ? b2.deadline.value : void 0;
63610
+ if (da !== void 0 && db !== void 0) {
63611
+ const byDeadline = compareInstants(da, db);
63612
+ if (byDeadline !== 0) return byDeadline;
63613
+ } else if (da !== db) {
63614
+ return da === void 0 ? 1 : -1;
63615
+ }
63616
+ return compareValues(b2.value, a2.value);
63617
+ }
63670
63618
  const URGENCY_GROUP_LABEL = {
63671
63619
  overdue: "Overdue",
63672
63620
  due: "Due today",
@@ -63713,10 +63661,10 @@ const URGENCY_TONE = {
63713
63661
  };
63714
63662
  const EXIT_MS = 560;
63715
63663
  const NARROW_PX = 560;
63716
- function decisionValue(d2, n2, showSign = false) {
63717
- return formatTick(n2, getSomeorUndefined(d2.format), showSign);
63664
+ function decisionValue(words, d2, n2, showSign = false) {
63665
+ return words.value(n2, getSomeorUndefined(d2.format), showSign);
63718
63666
  }
63719
- function deadlineSuffix(d2) {
63667
+ function deadlineSuffix(d2, words) {
63720
63668
  const deadline = getSomeorUndefined(d2.deadline);
63721
63669
  if (deadline === void 0) return "";
63722
63670
  if (d2.urgency.type === "overdue") {
@@ -63725,34 +63673,16 @@ function deadlineSuffix(d2) {
63725
63673
  if (hours < 48) return ` ${hours}h`;
63726
63674
  return ` ${Math.round(hours / 24)}d`;
63727
63675
  }
63728
- if (d2.urgency.type === "due") {
63729
- const h2 = deadline.getHours();
63730
- const m2 = deadline.getMinutes();
63731
- const meridiem = h2 >= 12 ? "pm" : "am";
63732
- const clock2 = h2 % 12 === 0 ? 12 : h2 % 12;
63733
- return m2 === 0 ? ` ${clock2}${meridiem}` : ` ${clock2}:${String(m2).padStart(2, "0")}${meridiem}`;
63734
- }
63676
+ if (d2.urgency.type === "due") return ` ${words.time(deadline)}`;
63735
63677
  return "";
63736
63678
  }
63737
- function useLeverPayloads(ref) {
63738
- const cache3 = getReactiveDatasetCache();
63739
- const workspace = cache3.getConfig().workspace ?? "";
63740
- return useMemo(() => {
63741
- var _a2, _b2, _c2;
63742
- if (!ref) return {};
63743
- const judgements = getBindingTypes(workspace, ref.judgements.source);
63744
- if (!(judgements == null ? void 0 : judgements.sourceType)) return {};
63745
- const root2 = normalizeTypeValue(judgements.sourceType);
63746
- const constraint = (_c2 = (_b2 = (_a2 = root2.value) == null ? void 0 : _a2.fields) == null ? void 0 : _b2["constraints"]) == null ? void 0 : _c2.value;
63747
- return (constraint == null ? void 0 : constraint.type) === "Variant" ? constraint.cases ?? {} : {};
63748
- }, [ref, workspace]);
63749
- }
63750
- const Row = memo(function Row2({ decision, handle, selected: selected2, narrow, leverPayloads, modify, evidence, defaultFacet, facetInclude, apply: apply2, reject: reject2, leaving, storageKey }) {
63679
+ const Row = memo(function Row2({ decision, handle, selected: selected2, narrow, contract, modify, evidence, defaultFacet, facetInclude, apply: apply2, reject: reject2, leaving, storageKey }) {
63751
63680
  var _a2, _b2;
63752
63681
  const dq = useSlotRecipe({ key: "decisionQueue" });
63753
63682
  const status = useSlotRecipe({ key: "status" });
63754
63683
  const tabs = useSlotRecipe({ key: "facetTabs" });
63755
63684
  const button = useRecipe({ key: "button" });
63685
+ const words = useFormatters();
63756
63686
  const rs = dq({});
63757
63687
  const ts = tabs({});
63758
63688
  const st = status({ status: URGENCY_TONE[decision.urgency.type], size: "md" });
@@ -63778,10 +63708,15 @@ const Row = memo(function Row2({ decision, handle, selected: selected2, narrow,
63778
63708
  const handleReject = useCallback(() => {
63779
63709
  reject2(decision);
63780
63710
  }, [reject2, decision]);
63711
+ const stageUpdate = handle.update;
63712
+ const updateDecision = useCallback((next2) => {
63713
+ stageUpdate(next2);
63714
+ return null;
63715
+ }, [stageUpdate]);
63781
63716
  const probe = useMemo(() => {
63782
63717
  if (!selected2 || facet !== "modify" || !modify) return null;
63783
- return modify(decision, handle.update);
63784
- }, [selected2, facet, modify, decision, handle.update]);
63718
+ return modify(decision, updateDecision);
63719
+ }, [selected2, facet, modify, decision, updateDecision]);
63785
63720
  const canvas = useMemo(() => {
63786
63721
  if (!selected2 || facet !== "evidence" || !evidence) return null;
63787
63722
  return evidence(decision);
@@ -63830,11 +63765,11 @@ const Row = memo(function Row2({ decision, handle, selected: selected2, narrow,
63830
63765
  /* @__PURE__ */ jsx$1(Box, { as: "span", css: st.indicator }),
63831
63766
  /* @__PURE__ */ jsxs(Box, { as: "span", css: st.label, children: [
63832
63767
  decision.urgency.type,
63833
- deadlineSuffix(decision)
63768
+ deadlineSuffix(decision, words)
63834
63769
  ] })
63835
63770
  ] });
63836
63771
  const valueSigned = ((_b2 = getSomeorUndefined(decision.valueAxis)) == null ? void 0 : _b2.signed) ?? true;
63837
- const valueText = /* @__PURE__ */ jsx$1(Text, { fontFamily: "mono", fontWeight: "semibold", textAlign: "right", ...valueSigned && decision.value >= 0 && selected2 ? { color: "fg.success" } : {}, children: decisionValue(decision, decision.value, valueSigned && selected2) });
63772
+ const valueText = /* @__PURE__ */ jsx$1(Text, { fontFamily: "mono", fontWeight: "semibold", textAlign: "right", ...valueSigned && decision.value >= 0 && selected2 ? { color: "fg.success" } : {}, children: decisionValue(words, decision, decision.value, valueSigned && selected2) });
63838
63773
  return /* @__PURE__ */ jsxs(Box, { css: rs.rowShell, ...leaving ? { "data-leaving": leaving } : {}, children: [
63839
63774
  narrow ? /* @__PURE__ */ jsxs(Box, { px: "14px", py: "10px", children: [
63840
63775
  /* @__PURE__ */ jsxs(Box, { display: "flex", justifyContent: "space-between", alignItems: "baseline", children: [
@@ -63858,7 +63793,7 @@ const Row = memo(function Row2({ decision, handle, selected: selected2, narrow,
63858
63793
  selected2 && /* @__PURE__ */ jsxs(Box, { px: narrow ? "14px" : "18px", py: "12px", borderTopWidth: "1px", borderColor: "border.subtle", bg: "bg.canvas", children: [
63859
63794
  facet === "evidence" && /* @__PURE__ */ jsx$1(EvidenceFacet, { decision, children: canvas != null && /* @__PURE__ */ jsx$1(EastChakraComponent, { value: canvas, storageKey: `${storageKey}-evidence-${decision.id}` }) }),
63860
63795
  facet === "options" && /* @__PURE__ */ jsx$1(OptionsFacet, { decision, narrow }),
63861
- facet === "judgement" && /* @__PURE__ */ jsx$1(JudgementFacet, { decision, handle, leverPayloads }),
63796
+ facet === "judgement" && /* @__PURE__ */ jsx$1(JudgementFacet, { decision, handle, contract }),
63862
63797
  facet === "modify" && probe != null && /* @__PURE__ */ jsx$1(EastChakraComponent, { value: probe, storageKey: `${storageKey}-modify-${decision.id}` })
63863
63798
  ] })
63864
63799
  ] });
@@ -63867,6 +63802,7 @@ const RoutineGroup = memo(function RoutineGroup2({ routine, acceptAll, leaving,
63867
63802
  const dq = useSlotRecipe({ key: "decisionQueue" });
63868
63803
  const status = useSlotRecipe({ key: "status" });
63869
63804
  const button = useRecipe({ key: "button" });
63805
+ const words = useFormatters();
63870
63806
  const rs = dq({});
63871
63807
  const st = status({ status: "neutral", size: "md" });
63872
63808
  const total = useMemo(() => routine.reduce((acc, d2) => acc + d2.value, 0), [routine]);
@@ -63888,15 +63824,15 @@ const RoutineGroup = memo(function RoutineGroup2({ routine, acceptAll, leaving,
63888
63824
  d2.kind
63889
63825
  ] })
63890
63826
  ] }),
63891
- /* @__PURE__ */ jsx$1(Box, { css: rs.routineValue, children: decisionValue(d2, d2.value) })
63827
+ /* @__PURE__ */ jsx$1(Box, { css: rs.routineValue, children: decisionValue(words, d2, d2.value) })
63892
63828
  ] }) }, d2.id)),
63893
63829
  /* @__PURE__ */ jsxs(Box, { css: rs.summary, ...narrow ? { marginLeft: "0", flexWrap: "wrap" } : {}, children: [
63894
63830
  /* @__PURE__ */ jsxs(Box, { as: "span", css: rs.summaryCap, children: [
63895
- routine.length,
63831
+ words.number(routine.length),
63896
63832
  " routine"
63897
63833
  ] }),
63898
63834
  /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.subtle", children: "·" }),
63899
- /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: formatTick(total, format2) }),
63835
+ /* @__PURE__ */ jsx$1(Text, { as: "span", fontFamily: "mono", fontWeight: "semibold", children: words.value(total, format2) }),
63900
63836
  /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.muted", children: "total" }),
63901
63837
  acceptAll && /* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "solid", size: "xs" }), ml: "auto", onClick: handleAcceptAll, children: "Accept all" })
63902
63838
  ] })
@@ -63905,6 +63841,7 @@ const RoutineGroup = memo(function RoutineGroup2({ routine, acceptAll, leaving,
63905
63841
  const GroupHead = memo(function GroupHead2({ group: group2, collapsible, collapsed, onToggle, acceptAll }) {
63906
63842
  const dq = useSlotRecipe({ key: "decisionQueue" });
63907
63843
  const button = useRecipe({ key: "button" });
63844
+ const words = useFormatters();
63908
63845
  const rs = dq({});
63909
63846
  const format2 = group2.decisions[0] ? getSomeorUndefined(group2.decisions[0].format) : void 0;
63910
63847
  const handleToggle = useCallback(() => {
@@ -63919,11 +63856,11 @@ const GroupHead = memo(function GroupHead2({ group: group2, collapsible, collaps
63919
63856
  /* @__PURE__ */ jsxs(Box, { as: "span", css: rs.groupLabel, children: [
63920
63857
  group2.label,
63921
63858
  " · ",
63922
- group2.decisions.length
63859
+ words.number(group2.decisions.length)
63923
63860
  ] }),
63924
63861
  /* @__PURE__ */ jsxs(Box, { as: "span", css: rs.groupSummary, children: [
63925
- formatTick(group2.total, format2),
63926
- group2.pastSla > 0 ? ` · ${group2.pastSla} past SLA` : ""
63862
+ words.value(group2.total, format2),
63863
+ group2.pastSla > 0 ? ` · ${words.number(group2.pastSla)} past SLA` : ""
63927
63864
  ] }),
63928
63865
  acceptAll && /* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "solid", size: "xs" }), onClick: handleAcceptAll, children: "Accept all" })
63929
63866
  ] });
@@ -63935,10 +63872,11 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
63935
63872
  const dq = useSlotRecipe({ key: "decisionQueue" });
63936
63873
  const qs = dq({});
63937
63874
  const chip = useRecipe({ key: "chip" });
63875
+ const words = useFormatters();
63938
63876
  const handleRef = value.handle;
63939
63877
  const handle = useDecisionHandle(handleRef);
63940
63878
  const decisions = handle.decisions;
63941
- const leverPayloads = useLeverPayloads(handleRef);
63879
+ const contract = useConstraintContract(handleRef);
63942
63880
  const railAffordances = getSomeorUndefined(value.affordances);
63943
63881
  const sliceHandle = getSomeorUndefined(value.slice) ?? null;
63944
63882
  useSliceReactivity(sliceHandle == null ? void 0 : sliceHandle.key);
@@ -63978,14 +63916,8 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
63978
63916
  const heading = getSomeorUndefined(value.heading) ?? "Decisions waiting";
63979
63917
  const onApply = useMemo(() => getSomeorUndefined(value.onApply), [value.onApply]);
63980
63918
  const onReject = useMemo(() => getSomeorUndefined(value.onReject), [value.onReject]);
63981
- const modify = useMemo(
63982
- () => getSomeorUndefined(value.modify),
63983
- [value.modify]
63984
- );
63985
- const evidence = useMemo(
63986
- () => getSomeorUndefined(value.evidence),
63987
- [value.evidence]
63988
- );
63919
+ const modify = useMemo(() => getSomeorUndefined(value.modify), [value.modify]);
63920
+ const evidence = useMemo(() => getSomeorUndefined(value.evidence), [value.evidence]);
63989
63921
  const defaultFacet = ((_a2 = getSomeorUndefined(value.defaultFacet)) == null ? void 0 : _a2.type) ?? "evidence";
63990
63922
  const facetInclude = useMemo(() => {
63991
63923
  const facets = getSomeorUndefined(value.facets);
@@ -64034,15 +63966,7 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
64034
63966
  for (const { decision } of exiting.values()) {
64035
63967
  if (!merged2.some((d2) => d2.id === decision.id)) merged2.push(decision);
64036
63968
  }
64037
- merged2.sort((a2, b2) => {
64038
- var _a3, _b2;
64039
- const r2 = URGENCY_RANK[a2.urgency.type] - URGENCY_RANK[b2.urgency.type];
64040
- if (r2 !== 0) return r2;
64041
- const da = ((_a3 = getSomeorUndefined(a2.deadline)) == null ? void 0 : _a3.getTime()) ?? Infinity;
64042
- const db = ((_b2 = getSomeorUndefined(b2.deadline)) == null ? void 0 : _b2.getTime()) ?? Infinity;
64043
- if (da !== db) return da - db;
64044
- return b2.value - a2.value;
64045
- });
63969
+ merged2.sort(compareByUrgency);
64046
63970
  return {
64047
63971
  merged: merged2,
64048
63972
  active: merged2.filter((d2) => d2.urgency.type !== "routine"),
@@ -64081,7 +64005,7 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
64081
64005
  handle,
64082
64006
  selected: selectedId === d2.id,
64083
64007
  narrow,
64084
- leverPayloads,
64008
+ contract,
64085
64009
  modify,
64086
64010
  evidence,
64087
64011
  defaultFacet,
@@ -64108,13 +64032,13 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
64108
64032
  ) }),
64109
64033
  /* @__PURE__ */ jsxs(Box, { css: es.meta, gap: "10px", children: [
64110
64034
  /* @__PURE__ */ jsxs(Box, { as: "span", children: [
64111
- /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg", fontWeight: "semibold", children: visible }),
64035
+ /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg", fontWeight: "semibold", children: words.number(visible) }),
64112
64036
  narrow ? "" : " decisions"
64113
64037
  ] }),
64114
64038
  pastSla > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
64115
64039
  /* @__PURE__ */ jsx$1(Box, { as: "span", css: es.sep, children: "·" }),
64116
64040
  /* @__PURE__ */ jsxs(Box, { as: "span", children: [
64117
- /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.danger", fontWeight: "semibold", children: pastSla }),
64041
+ /* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.danger", fontWeight: "semibold", children: words.number(pastSla) }),
64118
64042
  narrow ? " SLA" : " past SLA"
64119
64043
  ] })
64120
64044
  ] })
@@ -64176,34 +64100,24 @@ function verdictPresentation(verdict) {
64176
64100
  return { tone: "warning", verb: "handed off", detail: verdict.value !== "" ? verdict.value : null };
64177
64101
  }
64178
64102
  }
64179
- function formatResolvedAt(j2) {
64103
+ function formatResolvedAt(j2, words) {
64180
64104
  if (j2.resolvedAt.type !== "some") return null;
64181
64105
  const d2 = j2.resolvedAt.value;
64182
- const month = d2.toLocaleString("en", { month: "short" });
64183
- const time2 = `${String(d2.getHours()).padStart(2, "0")}:${String(d2.getMinutes()).padStart(2, "0")}`;
64184
- return `${month} ${d2.getDate()} · ${time2}`;
64106
+ return `${words.monthDay(d2)} · ${words.time(d2)}`;
64185
64107
  }
64186
64108
  const EastChakraDecisionJournal = memo(function EastChakraDecisionJournal2({ value }) {
64187
64109
  const eyebrow = useSlotRecipe({ key: "eyebrowRow" });
64188
64110
  const status = useSlotRecipe({ key: "status" });
64189
64111
  const es = eyebrow({});
64112
+ const words = useFormatters();
64190
64113
  const handle = useDecisionHandle(value.handle);
64191
64114
  const heading = getSomeorUndefined(value.heading) ?? "Decision journal";
64192
- const cache3 = getReactiveDatasetCache();
64193
- const workspace = cache3.getConfig().workspace ?? "";
64194
- const leverPayloads = useMemo(() => {
64195
- var _a2, _b2, _c2;
64196
- const judgements = getBindingTypes(workspace, value.handle.judgements.source);
64197
- if (!(judgements == null ? void 0 : judgements.sourceType)) return {};
64198
- const root2 = normalizeTypeValue(judgements.sourceType);
64199
- const constraint = (_c2 = (_b2 = (_a2 = root2.value) == null ? void 0 : _a2.fields) == null ? void 0 : _b2["constraints"]) == null ? void 0 : _c2.value;
64200
- return (constraint == null ? void 0 : constraint.type) === "Variant" ? constraint.cases ?? {} : {};
64201
- }, [workspace, value.handle]);
64115
+ const contract = useConstraintContract(value.handle);
64202
64116
  const entries = useMemo(() => handle.journal ?? [], [handle.journal]);
64203
64117
  return /* @__PURE__ */ jsxs(Box, { borderWidth: "1px", borderColor: "border.strong", borderRadius: "6px", background: "bg.canvas", overflow: "hidden", children: [
64204
64118
  /* @__PURE__ */ jsxs(Box, { css: es.root, children: [
64205
64119
  /* @__PURE__ */ jsx$1(Box, { css: es.lbl, children: heading }),
64206
- /* @__PURE__ */ jsx$1(Box, { css: es.meta, children: entries.length === 1 ? "1 entry" : `${entries.length} entries` })
64120
+ /* @__PURE__ */ jsx$1(Box, { css: es.meta, children: entries.length === 1 ? "1 entry" : `${words.number(entries.length)} entries` })
64207
64121
  ] }),
64208
64122
  /* @__PURE__ */ jsx$1(
64209
64123
  Box,
@@ -64215,7 +64129,7 @@ const EastChakraDecisionJournal = memo(function EastChakraDecisionJournal2({ val
64215
64129
  if (!verdict) return null;
64216
64130
  const { tone, verb, detail } = verdictPresentation(verdict);
64217
64131
  const st = status({ status: tone, size: "md" });
64218
- const when = formatResolvedAt(j2);
64132
+ const when = formatResolvedAt(j2, words);
64219
64133
  const knowledge = j2.knowledge.type === "some" && j2.knowledge.value !== "" ? j2.knowledge.value : null;
64220
64134
  return /* @__PURE__ */ jsxs(
64221
64135
  Box,
@@ -64254,8 +64168,7 @@ const EastChakraDecisionJournal = memo(function EastChakraDecisionJournal2({ val
64254
64168
  }
64255
64169
  ),
64256
64170
  j2.constraints.length > 0 && /* @__PURE__ */ jsx$1(Box, { display: "flex", gap: "12px", flexWrap: "wrap", children: j2.constraints.map((c2, k2) => {
64257
- const tag = c2.type;
64258
- const f2 = formatConstraint(c2, leverPayloads[tag]);
64171
+ const f2 = formatConstraint(c2, contract, void 0, words);
64259
64172
  return /* @__PURE__ */ jsx$1(ClauseChip, { field: f2.lever, op: f2.op, value: f2.value }, k2);
64260
64173
  }) })
64261
64174
  ]
@@ -64794,6 +64707,10 @@ function pagingDebug(...args) {
64794
64707
  console.info("[e3-paging]", ...args);
64795
64708
  }
64796
64709
  const PAGE_SIZE = 500;
64710
+ function servedPageSize(requested, page) {
64711
+ const trimmed = page.count < requested && page.offset + page.count < page.totalElements;
64712
+ return trimmed ? Math.max(1, page.count) : requested;
64713
+ }
64797
64714
  const MAX_RETAINED_PAGES = 8;
64798
64715
  function pageRows(type, decoded, offset) {
64799
64716
  if (type.type === "Array") {
@@ -64833,6 +64750,7 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64833
64750
  onDownload,
64834
64751
  onNotIndexed
64835
64752
  }) {
64753
+ const words = useFormatters();
64836
64754
  const queryClient = useQueryClient();
64837
64755
  const [pages, setPages] = useState(/* @__PURE__ */ new Map());
64838
64756
  const [totals, setTotals] = useState(null);
@@ -64841,6 +64759,8 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64841
64759
  const [jumpRow, setJumpRow] = useState(void 0);
64842
64760
  const inflightRef = useRef(/* @__PURE__ */ new Set());
64843
64761
  const shownRef = useRef({ path: path2, hash: hash2 });
64762
+ const [pageSize, setPageSize] = useState(PAGE_SIZE);
64763
+ const pageSizeRef = useRef(PAGE_SIZE);
64844
64764
  useEffect(() => {
64845
64765
  pagingDebug(`reset (path=${path2}, hash=${hash2.slice(0, 8)})`);
64846
64766
  shownRef.current = { path: path2, hash: hash2 };
@@ -64849,36 +64769,45 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64849
64769
  setError(null);
64850
64770
  setJumpRow(void 0);
64851
64771
  inflightRef.current = /* @__PURE__ */ new Set();
64772
+ pageSizeRef.current = PAGE_SIZE;
64773
+ setPageSize(PAGE_SIZE);
64852
64774
  }, [path2, hash2]);
64853
64775
  const loadPage = useCallback((pageIdx) => {
64854
64776
  const inflight = inflightRef.current;
64855
64777
  if (inflight.has(pageIdx)) return;
64856
64778
  inflight.add(pageIdx);
64857
64779
  const current = () => shownRef.current.path === path2 && shownRef.current.hash === hash2;
64780
+ const size3 = pageSizeRef.current;
64858
64781
  setLoadingCount((n2) => n2 + 1);
64859
- pagingDebug(`fetch p${pageIdx} (offset=${pageIdx * PAGE_SIZE}, limit=${PAGE_SIZE}, hash=${hash2.slice(0, 8)})`);
64782
+ pagingDebug(`fetch p${pageIdx} (offset=${pageIdx * size3}, limit=${size3}, hash=${hash2.slice(0, 8)})`);
64860
64783
  const pathParts2 = path2.split(".").filter(Boolean).map((v3) => variant("field", v3));
64861
64784
  const reqOpts = requestOptions ?? { token: null };
64862
64785
  queryClient.fetchQuery({
64863
- queryKey: ["datasetPage", apiUrl, repo, workspace, path2, hash2, `p${pageIdx}`],
64786
+ queryKey: ["datasetPage", apiUrl, repo, workspace, path2, hash2, `p${pageIdx}@${size3}`],
64864
64787
  // Hash-pinned: the URL is a pure function of the bytes, so any
64865
64788
  // HTTP cache between here and the server can hold it immutably.
64866
- queryFn: () => datasetGetPage(apiUrl, repo, workspace, pathParts2, { offset: pageIdx * PAGE_SIZE, limit: PAGE_SIZE, hash: hash2 }, reqOpts),
64789
+ queryFn: () => datasetGetPage(apiUrl, repo, workspace, pathParts2, { offset: pageIdx * size3, limit: size3, hash: hash2 }, reqOpts),
64867
64790
  staleTime: Infinity
64868
64791
  // pages of one content hash are immutable
64869
64792
  }).then((page) => {
64870
64793
  if (!current()) return;
64794
+ if (size3 !== pageSizeRef.current) return;
64871
64795
  const decoded = decodeBeast2For(type)(page.data);
64872
64796
  const rows = pageRows(type, decoded, page.offset);
64873
64797
  pagingDebug(
64874
64798
  `p${pageIdx} ok: count=${page.count} rows=${rows.length} offset=${page.offset} total=${page.totalElements} segs=${page.segmentCount}`,
64875
64799
  rows.length > 0 ? `first=${JSON.stringify(rows[0].label ?? "(derived)")}` : "(empty)"
64876
64800
  );
64877
- if (page.count < PAGE_SIZE && page.offset + page.count < page.totalElements) {
64878
- pagingDebug(`p${pageIdx} SHORT page: server clamped ${PAGE_SIZE} → ${page.count}`);
64879
- }
64880
64801
  setTotals({ elements: page.totalElements, bytes: page.totalBytes });
64881
- setPages((prev2) => new Map(prev2).set(pageIdx, rows));
64802
+ const served = servedPageSize(size3, page);
64803
+ if (served === size3) {
64804
+ setPages((prev2) => new Map(prev2).set(pageIdx, rows));
64805
+ return;
64806
+ }
64807
+ pagingDebug(`p${pageIdx} SHORT page: served ${page.count} of ${size3} — addressing pages by ${served}`);
64808
+ pageSizeRef.current = served;
64809
+ setPageSize(served);
64810
+ setPages(pageIdx === 0 ? /* @__PURE__ */ new Map([[0, rows]]) : /* @__PURE__ */ new Map());
64882
64811
  }).catch((err) => {
64883
64812
  pagingDebug(`p${pageIdx} FAILED:`, err);
64884
64813
  if (!current()) return;
@@ -64899,8 +64828,8 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64899
64828
  if (totals === null && error3 === null) loadPage(0);
64900
64829
  }, [totals, error3, loadPage]);
64901
64830
  const onNeedRows = useCallback((startRow, endRow) => {
64902
- const first2 = Math.max(0, Math.floor(startRow / PAGE_SIZE));
64903
- const last2 = Math.max(first2, Math.ceil(endRow / PAGE_SIZE) - 1);
64831
+ const first2 = Math.max(0, Math.floor(startRow / pageSize));
64832
+ const last2 = Math.max(first2, Math.ceil(endRow / pageSize) - 1);
64904
64833
  const missing = [];
64905
64834
  for (let p2 = first2; p2 <= last2; p2++) {
64906
64835
  if (!pages.has(p2)) missing.push(p2);
@@ -64908,7 +64837,7 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64908
64837
  pagingDebug(`need rows [${startRow}, ${endRow}) → pages ${first2}..${last2}, missing=[${missing.join(",")}], inflight=[${[...inflightRef.current].join(",")}]`);
64909
64838
  setPages((prev2) => pruneRetainedPages(prev2, first2, last2, MAX_RETAINED_PAGES));
64910
64839
  for (const p2 of missing) loadPage(p2);
64911
- }, [pages, loadPage]);
64840
+ }, [pages, loadPage, pageSize]);
64912
64841
  const keyType = useMemo(() => type.type === "Dict" ? type.value.key : type.type === "Set" ? type.value : null, [type]);
64913
64842
  const pathParts = useMemo(() => path2.split(".").filter(Boolean).map((v3) => variant("field", v3)), [path2]);
64914
64843
  const onFindKey = useCallback(async (query) => {
@@ -64945,11 +64874,11 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64945
64874
  }), [type]);
64946
64875
  const paging = useMemo(() => totals === null ? null : {
64947
64876
  totalRows: totals.elements,
64948
- pageSize: PAGE_SIZE,
64877
+ pageSize,
64949
64878
  pages,
64950
64879
  onNeedRows,
64951
64880
  scrollToRow: jumpRow
64952
- }, [totals, pages, onNeedRows, jumpRow]);
64881
+ }, [totals, pageSize, pages, onNeedRows, jumpRow]);
64953
64882
  if (error3 !== null) {
64954
64883
  if (error3 instanceof ApiError && error3.code === "dataset_too_large") {
64955
64884
  return /* @__PURE__ */ jsxs(Flex, { height: "100%", direction: "column", align: "center", justify: "center", gap: 3, p: 6, children: [
@@ -64967,11 +64896,11 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64967
64896
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", height: "100%", overflow: "hidden", children: [
64968
64897
  /* @__PURE__ */ jsxs(Flex, { px: 4, py: 2, gap: 2, align: "center", flexShrink: 0, borderBottom: "1px solid", borderColor: "border.subtle", children: [
64969
64898
  /* @__PURE__ */ jsxs(Text, { fontSize: "xs", color: "fg.muted", whiteSpace: "nowrap", children: [
64970
- totals.elements.toLocaleString(),
64899
+ words.number(totals.elements),
64971
64900
  " ",
64972
64901
  itemNoun,
64973
64902
  " · ",
64974
- formatSize(totals.bytes > 0 ? totals.bytes : sizeBytes)
64903
+ formatSize(totals.bytes > 0 ? totals.bytes : sizeBytes, words)
64975
64904
  ] }),
64976
64905
  loadingCount > 0 && /* @__PURE__ */ jsx$1(Text, { fontSize: "xs", color: "fg.muted", children: "Loading…" }),
64977
64906
  keyType !== null && /* @__PURE__ */ jsx$1(
@@ -64993,10 +64922,12 @@ const PagedDatasetPreview = memo(function PagedDatasetPreview2({
64993
64922
  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);
64994
64923
  });
64995
64924
  const DEFAULT_SIZE_LIMIT = 200 * 1024;
64996
- function formatSize(bytes) {
64997
- if (bytes < 1024) return `${bytes} B`;
64998
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
64999
- return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
64925
+ const KB_FORMAT = variant("number", { minimumFractionDigits: some(1n), maximumFractionDigits: some(1n), signDisplay: none$1 });
64926
+ const MB_FORMAT = variant("number", { minimumFractionDigits: some(2n), maximumFractionDigits: some(2n), signDisplay: none$1 });
64927
+ function formatSize(bytes, words = formatters()) {
64928
+ if (bytes < 1024) return `${words.number(bytes)} B`;
64929
+ if (bytes < 1024 * 1024) return `${words.value(bytes / 1024, KB_FORMAT)} KB`;
64930
+ return `${words.value(bytes / 1024 / 1024, MB_FORMAT)} MB`;
65000
64931
  }
65001
64932
  function DownloadButton({ onClick, label }) {
65002
64933
  const [downloading, setDownloading] = useState(false);
@@ -65024,6 +64955,7 @@ const DatasetPreview = memo(function DatasetPreview2({
65024
64955
  editable = false
65025
64956
  }) {
65026
64957
  var _a2;
64958
+ const words = useFormatters();
65027
64959
  const statusQuery = useDatasetStatus(apiUrl, repo, workspace, path2, {
65028
64960
  ...requestOptions != null && { requestOptions },
65029
64961
  ...pollInterval !== void 0 && { pollInterval }
@@ -65148,9 +65080,9 @@ const DatasetPreview = memo(function DatasetPreview2({
65148
65080
  /* @__PURE__ */ jsx$1(Text, { fontSize: "lg", color: "fg.warning", fontWeight: "bold", children: "Value too large to display" }),
65149
65081
  /* @__PURE__ */ jsxs(Text, { color: "fg.muted", fontSize: "sm", children: [
65150
65082
  "The data is ",
65151
- formatSize(sizeBytes),
65083
+ formatSize(sizeBytes, words),
65152
65084
  ", which exceeds the ",
65153
- formatSize(sizeLimit),
65085
+ formatSize(sizeLimit, words),
65154
65086
  " display limit."
65155
65087
  ] }),
65156
65088
  /* @__PURE__ */ jsx$1(DownloadButton, { onClick: download, label: "Download value" })
@@ -65162,7 +65094,7 @@ const DatasetPreview = memo(function DatasetPreview2({
65162
65094
  }
65163
65095
  if (valueQuery.isLoading || !valueQuery.data) return /* @__PURE__ */ jsx$1(StatusDisplay, { variant: "loading", title: "Loading..." });
65164
65096
  const count = type === void 0 || decoded === void 0 ? null : type.type === "Array" ? decoded.length : type.type === "Set" || type.type === "Dict" ? decoded.size : null;
65165
- const countText = count === null ? "" : `${count.toLocaleString()} ${(type == null ? void 0 : type.type) === "Dict" ? "entries" : "items"} · `;
65097
+ const countText = count === null ? "" : `${words.number(count)} ${(type == null ? void 0 : type.type) === "Dict" ? "entries" : "items"} · `;
65166
65098
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", height: "100%", overflow: "hidden", children: [
65167
65099
  /* @__PURE__ */ jsxs(Flex, { px: 4, py: 2, gap: 2, align: "center", flexShrink: 0, borderBottom: "1px solid", borderColor: "border.subtle", children: [
65168
65100
  keyType !== null && inlineKeys !== null && /* @__PURE__ */ jsx$1(
@@ -65178,7 +65110,7 @@ const DatasetPreview = memo(function DatasetPreview2({
65178
65110
  /* @__PURE__ */ jsxs(Flex, { flex: 1, justify: "flex-end", align: "center", gap: 2, children: [
65179
65111
  /* @__PURE__ */ jsxs(Text, { fontSize: "xs", color: "fg.muted", children: [
65180
65112
  countText,
65181
- formatSize(sizeBytes)
65113
+ formatSize(sizeBytes, words)
65182
65114
  ] }),
65183
65115
  /* @__PURE__ */ jsx$1(DownloadButton, { onClick: download })
65184
65116
  ] })
@@ -65848,31 +65780,11 @@ const TaskPreview = memo(function TaskPreview2({
65848
65780
  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);
65849
65781
  });
65850
65782
  function formatPrimitive(type, value) {
65851
- switch (type.type) {
65852
- case "Null":
65853
- return "null";
65854
- case "Boolean":
65855
- return value ? "true" : "false";
65856
- case "Integer":
65857
- return String(value);
65858
- case "Float": {
65859
- const num2 = value;
65860
- if (Number.isNaN(num2)) return "NaN";
65861
- if (!Number.isFinite(num2)) return num2 > 0 ? "Infinity" : "-Infinity";
65862
- return String(num2);
65863
- }
65864
- case "String":
65865
- return `"${value}"`;
65866
- case "DateTime":
65867
- return value.toISOString();
65868
- case "Blob":
65869
- return `Blob[${value.length} bytes]`;
65870
- default:
65871
- return String(value);
65872
- }
65783
+ if (type.type === "Blob") return `Blob[${value.length} bytes]`;
65784
+ return printFor(type)(value);
65873
65785
  }
65874
65786
  function isPrimitive(type) {
65875
- return ["Null", "Boolean", "Integer", "Float", "String", "DateTime", "Blob", "Never"].includes(type.type);
65787
+ return ["Null", "Boolean", "Integer", "Float", "String", "DateTime", "Blob"].includes(type.type);
65876
65788
  }
65877
65789
  function getTypeLabel(type, value) {
65878
65790
  switch (type.type) {
@@ -65994,8 +65906,8 @@ function ValueNode({
65994
65906
  }
65995
65907
  if (type.type === "Variant") {
65996
65908
  const cases = type.value;
65997
- const variant2 = value;
65998
- const activeCase = cases.find((c2) => c2.name === variant2.type);
65909
+ const chosen = value;
65910
+ const activeCase = cases.find((c2) => c2.name === chosen.type);
65999
65911
  if (!activeCase) {
66000
65912
  return /* @__PURE__ */ jsxs(Box, { py: 0.5, display: "flex", alignItems: "center", gap: 2, children: [
66001
65913
  label && /* @__PURE__ */ jsxs(Text, { as: "span", color: "accent.purple", fontWeight: "medium", children: [
@@ -66004,7 +65916,7 @@ function ValueNode({
66004
65916
  ] }),
66005
65917
  /* @__PURE__ */ jsxs(Text, { as: "span", color: "fg.danger", children: [
66006
65918
  "Unknown variant: ",
66007
- variant2.type
65919
+ chosen.type
66008
65920
  ] })
66009
65921
  ] });
66010
65922
  }
@@ -66016,7 +65928,7 @@ function ValueNode({
66016
65928
  ] }),
66017
65929
  /* @__PURE__ */ jsxs(Badge, { size: "xs", colorPalette: "brand", variant: "subtle", children: [
66018
65930
  ".",
66019
- variant2.type
65931
+ chosen.type
66020
65932
  ] })
66021
65933
  ] });
66022
65934
  }
@@ -66028,14 +65940,14 @@ function ValueNode({
66028
65940
  ] }),
66029
65941
  /* @__PURE__ */ jsxs(Badge, { size: "xs", colorPalette: "brand", variant: "subtle", children: [
66030
65942
  ".",
66031
- variant2.type
65943
+ chosen.type
66032
65944
  ] })
66033
65945
  ] }),
66034
65946
  /* @__PURE__ */ jsx$1(Box, { pl: 4, children: /* @__PURE__ */ jsx$1(
66035
65947
  ValueNode,
66036
65948
  {
66037
65949
  type: activeCase.type,
66038
- value: variant2.value,
65950
+ value: chosen.value,
66039
65951
  depth: depth + 1
66040
65952
  }
66041
65953
  ) })