@elaraai/e3-ui-components 1.0.30 → 1.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/decision/grouping.d.ts +23 -0
- package/dist/decision/grouping.d.ts.map +1 -0
- package/dist/decision/queue.d.ts.map +1 -1
- package/dist/experiment/charts.d.ts.map +1 -1
- package/dist/experiment/derive.d.ts +33 -1
- package/dist/experiment/derive.d.ts.map +1 -1
- package/dist/experiment/help-ui.d.ts +11 -0
- package/dist/experiment/help-ui.d.ts.map +1 -1
- package/dist/experiment/help.d.ts +2 -2
- package/dist/experiment/index.d.ts.map +1 -1
- package/dist/index.cjs +477 -111
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +478 -112
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import { jsx as jsx$1, Fragment, jsxs } from "react/jsx-runtime";
|
|
|
28
28
|
import * as React from "react";
|
|
29
29
|
import React__default, { useId, useMemo, useContext, createContext, useRef, useEffect, useState, useCallback, useSyncExternalStore, memo, forwardRef, useLayoutEffect, Fragment as Fragment$1, Component } from "react";
|
|
30
30
|
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, Badge, Button, Tabs, useTabs } from "@chakra-ui/react";
|
|
31
|
-
import { implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, NavImpl, SliceImpl, SliceApplyImpl, OverlayImpl, ClipboardImpl, DownloadImpl, ShareImpl, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
|
|
31
|
+
import { implementUIComponent, getSomeorUndefined, formatPredicate, SliceEditPopover, SlicePredicateBuilder, EastChakraSelect, EastChakraStringInput, EastChakraDateTimeInput, EastChakraFloatInput, EastChakraIntegerInput, formatTick, useSliceReactivity, usePersistedState, SliceRailCluster, EastChakraComponent, ClauseChip, StateImpl, NavImpl, SliceImpl, SliceApplyImpl, OverlayImpl, ClipboardImpl, DownloadImpl, ShareImpl, createUIStore, UIStoreProvider } from "@elaraai/east-ui-components";
|
|
32
32
|
import { createPortal } from "react-dom";
|
|
33
33
|
import { sliceMatches } from "@elaraai/east-ui/internal";
|
|
34
34
|
import { QueryClient as QueryClient$1, QueryClientProvider, useMutation, useQuery } from "@tanstack/react-query";
|
|
@@ -59920,7 +59920,7 @@ const HELP = {
|
|
|
59920
59920
|
},
|
|
59921
59921
|
// ── Tabs ────────────────────────────────────────────────────────────
|
|
59922
59922
|
tab_answer: {
|
|
59923
|
-
term: "
|
|
59923
|
+
term: "The answer",
|
|
59924
59924
|
gist: "The headline: did {treatment} move {outcome}, and by how much?",
|
|
59925
59925
|
detail: "Shows the raw gap, the fair like-for-like estimate, and an honest verdict."
|
|
59926
59926
|
},
|
|
@@ -60108,7 +60108,7 @@ const HELP = {
|
|
|
60108
60108
|
},
|
|
60109
60109
|
// ── Validate tab ────────────────────────────────────────────────────
|
|
60110
60110
|
tab_validate: {
|
|
60111
|
-
term: "
|
|
60111
|
+
term: "Prove it",
|
|
60112
60112
|
gist: "The real experiment you’d run to prove this — for sure.",
|
|
60113
60113
|
detail: "This analysis adjusted for what it could measure. A controlled trial — assigning {treatment} at random — removes any leftover doubt. This tab sizes that trial."
|
|
60114
60114
|
},
|
|
@@ -60197,6 +60197,12 @@ function Help({ id: id3, extraVars, children: children2, display = "inline", gap
|
|
|
60197
60197
|
)
|
|
60198
60198
|
) });
|
|
60199
60199
|
}
|
|
60200
|
+
function GuidanceGist({ id: id3, extraVars }) {
|
|
60201
|
+
const { on: on3, vars } = useContext(GuidanceContext);
|
|
60202
|
+
if (!on3) return null;
|
|
60203
|
+
const e3 = fillHelp(HELP[id3], { ...vars, ...extraVars });
|
|
60204
|
+
return /* @__PURE__ */ jsx$1(Text, { textStyle: "caption", color: "fg.muted", lineHeight: "1.45", mt: "-1.5", mb: "2.5", children: e3.gist });
|
|
60205
|
+
}
|
|
60200
60206
|
function GuidanceToggle({ on: on3, onToggle }) {
|
|
60201
60207
|
const iconButton = useRecipe({ key: "iconButton" });
|
|
60202
60208
|
return /* @__PURE__ */ jsx$1(Hover, { id: "guidance", trigger: /* @__PURE__ */ jsx$1(
|
|
@@ -60351,8 +60357,8 @@ function AreaRange({ lo: lo2, mid, hi, xTicks = [], yTicks = [], zero: zero2, to
|
|
|
60351
60357
|
const atEnd = m2.at >= mid.length - 2;
|
|
60352
60358
|
const atStart = m2.at <= 1;
|
|
60353
60359
|
const align = atEnd ? "right" : atStart ? "left" : "center";
|
|
60354
|
-
const labW = m2.label.length * 6 +
|
|
60355
|
-
const labX = atEnd ? -labW : atStart ?
|
|
60360
|
+
const labW = m2.label.length * 6.5 + 8;
|
|
60361
|
+
const labX = atEnd ? -labW - 5 : atStart ? 5 : -labW / 2;
|
|
60356
60362
|
return /* @__PURE__ */ jsxs(Group, { left: xScale(m2.at), children: [
|
|
60357
60363
|
/* @__PURE__ */ jsx$1(Line, { from: { x: 0, y: -2 }, to: { x: 0, y: innerH }, stroke: mc, strokeWidth: 1, strokeDasharray: "2 3" }),
|
|
60358
60364
|
/* @__PURE__ */ jsx$1(Circle, { cx: 0, cy: dotY, r: t4.dotRadius, fill: mc, stroke: t4.surface, strokeWidth: 1.5 }),
|
|
@@ -60423,6 +60429,10 @@ const unitOf = (meta3, col) => {
|
|
|
60423
60429
|
var _a2;
|
|
60424
60430
|
return getSomeorUndefined((_a2 = colMeta(meta3, col)) == null ? void 0 : _a2.unit) ?? "";
|
|
60425
60431
|
};
|
|
60432
|
+
const labelOf = (meta3, col) => {
|
|
60433
|
+
var _a2;
|
|
60434
|
+
return getSomeorUndefined((_a2 = colMeta(meta3, col)) == null ? void 0 : _a2.label) ?? col;
|
|
60435
|
+
};
|
|
60426
60436
|
const kindOf = (cols, name) => {
|
|
60427
60437
|
var _a2;
|
|
60428
60438
|
return (_a2 = cols.find((c2) => c2.name === name)) == null ? void 0 : _a2.kind;
|
|
@@ -60458,8 +60468,7 @@ function treatmentKind(cols, treatment) {
|
|
|
60458
60468
|
return "value";
|
|
60459
60469
|
}
|
|
60460
60470
|
}
|
|
60461
|
-
function deriveSpec(config2, cols, result, meta3, dataLen) {
|
|
60462
|
-
const tKind = kindOf(cols, config2.treatment);
|
|
60471
|
+
function deriveSpec(config2, cols, result, meta3, dataLen, subject) {
|
|
60463
60472
|
const outUnit = unitOf(meta3, config2.outcome);
|
|
60464
60473
|
const balByCol = /* @__PURE__ */ new Map();
|
|
60465
60474
|
for (const b2 of (result == null ? void 0 : result.balance) ?? []) {
|
|
@@ -60471,7 +60480,7 @@ function deriveSpec(config2, cols, result, meta3, dataLen) {
|
|
|
60471
60480
|
const absStd = b2 ? Math.abs(b2.std_diff) : 0;
|
|
60472
60481
|
const { level, tone } = band(absStd);
|
|
60473
60482
|
const dir = b2 ? b2.treated_mean < b2.control_mean ? "lower" : "higher" : "";
|
|
60474
|
-
const reason = b2 ? `the treated group ran ${dir} on ${col}` : "measured once you Run";
|
|
60483
|
+
const reason = b2 ? `the treated group ran ${dir} on ${labelOf(meta3, col)}` : "measured once you Run";
|
|
60475
60484
|
return { col, reason, imbalance: clamp01(absStd), level, tone };
|
|
60476
60485
|
});
|
|
60477
60486
|
const inPlay = /* @__PURE__ */ new Set([config2.treatment, config2.outcome, ...config2.common_causes]);
|
|
@@ -60483,15 +60492,21 @@ function deriveSpec(config2, cols, result, meta3, dataLen) {
|
|
|
60483
60492
|
const target = targetV && (targetV.type === "att" || targetV.type === "atc") ? "treated" : "all";
|
|
60484
60493
|
return {
|
|
60485
60494
|
treatment: config2.treatment,
|
|
60495
|
+
treatmentLabel: labelOf(meta3, config2.treatment),
|
|
60486
60496
|
treatmentKind: treatmentKind(cols, config2.treatment),
|
|
60487
60497
|
outcome: config2.outcome,
|
|
60498
|
+
outcomeLabel: labelOf(meta3, config2.outcome),
|
|
60488
60499
|
outcomeKind: outUnit ? `number · ${outUnit}` : "number",
|
|
60489
|
-
comparison:
|
|
60500
|
+
comparison: kindOf(cols, config2.treatment) === "boolean" ? "yes · vs no" : "high · vs low",
|
|
60490
60501
|
confounders,
|
|
60491
60502
|
suggestion,
|
|
60492
60503
|
method,
|
|
60493
60504
|
target,
|
|
60494
|
-
|
|
60505
|
+
// Always the CURRENT (filtered) dataset's row count — the result's own
|
|
60506
|
+
// n_total belongs to the Answer-tab counts strip; labelling the header
|
|
60507
|
+
// with it desyncs from the data after a population edit (and reads
|
|
60508
|
+
// wrong whenever the two legitimately differ).
|
|
60509
|
+
dataLabel: `${dataLen} ${subject.many}`
|
|
60495
60510
|
};
|
|
60496
60511
|
}
|
|
60497
60512
|
function balanceDisplay(b2, categorical) {
|
|
@@ -60503,7 +60518,9 @@ function deriveAnswer(config2, result, adj, meta3) {
|
|
|
60503
60518
|
const nci = getSomeorUndefined(result.naive_ci);
|
|
60504
60519
|
const categorical = new Set(getSomeorUndefined(config2.categorical) ?? []);
|
|
60505
60520
|
const balance = [...result.balance].sort((a2, b2) => Math.abs(b2.std_diff) - Math.abs(a2.std_diff)).map((b2) => ({
|
|
60521
|
+
// One-hot rows are `col=level` — label the BASE confounder, keep the level.
|
|
60506
60522
|
col: b2.column,
|
|
60523
|
+
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})`}`,
|
|
60507
60524
|
treated: b2.treated_mean,
|
|
60508
60525
|
control: b2.control_mean,
|
|
60509
60526
|
display: balanceDisplay(b2, categorical),
|
|
@@ -60517,8 +60534,8 @@ function deriveAnswer(config2, result, adj, meta3) {
|
|
|
60517
60534
|
const nDropped = Number(result.n_dropped);
|
|
60518
60535
|
const nTotal = Number(result.n_total);
|
|
60519
60536
|
return {
|
|
60520
|
-
treatment: config2.treatment,
|
|
60521
|
-
outcome: config2.outcome,
|
|
60537
|
+
treatment: labelOf(meta3, config2.treatment),
|
|
60538
|
+
outcome: labelOf(meta3, config2.outcome),
|
|
60522
60539
|
unit: unitOf(meta3, config2.outcome),
|
|
60523
60540
|
naive: result.naive,
|
|
60524
60541
|
naiveLo: (nci == null ? void 0 : nci.lower) ?? result.naive,
|
|
@@ -60537,18 +60554,63 @@ function deriveAnswer(config2, result, adj, meta3) {
|
|
|
60537
60554
|
balance
|
|
60538
60555
|
};
|
|
60539
60556
|
}
|
|
60540
|
-
function
|
|
60557
|
+
function deriveNarrative(result, a2, refute, higherBetter, subject) {
|
|
60558
|
+
if (a2 === null) return null;
|
|
60559
|
+
const unit2 = a2.unit ? ` ${a2.unit}` : "";
|
|
60560
|
+
const dirUp = a2.effect > 0;
|
|
60561
|
+
const verb = higherBetter === void 0 ? dirUp ? "raises" : "lowers" : dirUp === higherBetter ? "improves" : "worsens";
|
|
60562
|
+
const range = ` (likely between ${signed(a2.lo)} and ${signed(a2.hi)})`;
|
|
60563
|
+
const passed = (refute == null ? void 0 : refute.checks.filter((c2) => c2.passed).length) ?? 0;
|
|
60564
|
+
const total = (refute == null ? void 0 : refute.checks.length) ?? 0;
|
|
60565
|
+
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?”.`;
|
|
60566
|
+
switch (result.verdict.type) {
|
|
60567
|
+
case "causal":
|
|
60568
|
+
return {
|
|
60569
|
+
tone: "pos",
|
|
60570
|
+
segments: [
|
|
60571
|
+
{ text: "Yes — ", strong: true },
|
|
60572
|
+
{ text: `${a2.treatment} genuinely ${verb} ${a2.outcome}: about ` },
|
|
60573
|
+
{ text: `${signed(a2.effect)}${unit2}`, strong: true },
|
|
60574
|
+
{ text: ` per ${subject.one}${range}.${trustClause}` }
|
|
60575
|
+
]
|
|
60576
|
+
};
|
|
60577
|
+
case "modest": {
|
|
60578
|
+
const tags = new Set(result.verdict_reasons.map((v3) => v3.type));
|
|
60579
|
+
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.` : ".";
|
|
60580
|
+
return {
|
|
60581
|
+
tone: "warn",
|
|
60582
|
+
segments: [
|
|
60583
|
+
{ text: "Maybe — ", strong: true },
|
|
60584
|
+
{ text: `there may be an effect of ${a2.treatment} on ${a2.outcome}, but it’s too small or unclear to act on` },
|
|
60585
|
+
{ text: why }
|
|
60586
|
+
]
|
|
60587
|
+
};
|
|
60588
|
+
}
|
|
60589
|
+
case "adjustment_insufficient":
|
|
60590
|
+
return {
|
|
60591
|
+
tone: "warn",
|
|
60592
|
+
segments: [
|
|
60593
|
+
{ text: "Don’t act on this yet — ", strong: true },
|
|
60594
|
+
{ 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.` }
|
|
60595
|
+
]
|
|
60596
|
+
};
|
|
60597
|
+
default:
|
|
60598
|
+
return null;
|
|
60599
|
+
}
|
|
60600
|
+
}
|
|
60601
|
+
function deriveRefusal(config2, result, meta3, subject) {
|
|
60541
60602
|
const nT = Number(result.n_treated), nC = Number(result.n_control), nTot = Number(result.n_total);
|
|
60603
|
+
const treatment = labelOf(meta3, config2.treatment);
|
|
60542
60604
|
if (result.verdict.type === "not_estimable") {
|
|
60543
60605
|
const reason = result.verdict.value || "The treatment barely varies, so no comparison can be formed.";
|
|
60544
60606
|
return {
|
|
60545
60607
|
kind: "not_estimable",
|
|
60546
|
-
title: `Can’t estimate the effect of ${
|
|
60608
|
+
title: `Can’t estimate the effect of ${treatment}`,
|
|
60547
60609
|
body: reason,
|
|
60548
60610
|
evidence: [
|
|
60549
60611
|
{ label: "treated", value: String(nT) },
|
|
60550
60612
|
{ label: "untreated", value: String(nC) },
|
|
60551
|
-
{ label:
|
|
60613
|
+
{ label: subject.many, value: String(nTot) }
|
|
60552
60614
|
]
|
|
60553
60615
|
};
|
|
60554
60616
|
}
|
|
@@ -60567,12 +60629,12 @@ function deriveRefusal(config2, result) {
|
|
|
60567
60629
|
}
|
|
60568
60630
|
return {
|
|
60569
60631
|
kind: "not_estimable",
|
|
60570
|
-
title: `Can’t estimate the effect of ${
|
|
60632
|
+
title: `Can’t estimate the effect of ${treatment}`,
|
|
60571
60633
|
body: "The engine could not produce a like-for-like estimate for this configuration.",
|
|
60572
60634
|
evidence: [
|
|
60573
60635
|
{ label: "treated", value: String(nT) },
|
|
60574
60636
|
{ label: "untreated", value: String(nC) },
|
|
60575
|
-
{ label:
|
|
60637
|
+
{ label: subject.many, value: String(nTot) }
|
|
60576
60638
|
]
|
|
60577
60639
|
};
|
|
60578
60640
|
}
|
|
@@ -60596,17 +60658,21 @@ function zeroCrossing(xs, ys) {
|
|
|
60596
60658
|
}
|
|
60597
60659
|
return null;
|
|
60598
60660
|
}
|
|
60599
|
-
function deriveRefute(r2, adj) {
|
|
60661
|
+
function deriveRefute(r2, adj, meta3) {
|
|
60600
60662
|
const checks = [];
|
|
60601
60663
|
const est = (adj == null ? void 0 : adj.effect) ?? 0;
|
|
60602
60664
|
const placeboEffect = getSomeorUndefined(r2.placebo_effect);
|
|
60603
60665
|
const placeboPasses = getSomeorUndefined(r2.placebo_passes);
|
|
60604
60666
|
if (placeboEffect !== void 0 || placeboPasses !== void 0) {
|
|
60667
|
+
const passed = placeboPasses ?? (placeboEffect !== void 0 && Math.abs(placeboEffect) < Math.max(0.5, Math.abs(est) * 0.15));
|
|
60605
60668
|
checks.push({
|
|
60606
60669
|
name: "Shuffle test",
|
|
60670
|
+
short: "shuffle",
|
|
60607
60671
|
desc: "Shuffle which rows were treated; a real effect should collapse to zero.",
|
|
60608
|
-
|
|
60609
|
-
|
|
60672
|
+
// Speak the outcome, not the statistic: on fake labels the effect
|
|
60673
|
+
// should VANISH — say whether it did.
|
|
60674
|
+
value: placeboEffect !== void 0 ? passed ? `vanished (${signed(placeboEffect)})` : `didn’t vanish (${signed(placeboEffect)})` : passed ? "vanished" : "didn’t vanish",
|
|
60675
|
+
passed,
|
|
60610
60676
|
tip: some("Randomly re-label which rows were treated. A genuine effect should vanish."),
|
|
60611
60677
|
help: "check_shuffle"
|
|
60612
60678
|
});
|
|
@@ -60614,11 +60680,13 @@ function deriveRefute(r2, adj) {
|
|
|
60614
60680
|
const ds = getSomeorUndefined(r2.data_subset_effect);
|
|
60615
60681
|
if (ds !== void 0) {
|
|
60616
60682
|
const dstd = getSomeorUndefined(r2.data_subset_std) ?? 0;
|
|
60683
|
+
const passed = Math.abs(ds - est) < Math.max(0.5, Math.abs(est) * 0.2);
|
|
60617
60684
|
checks.push({
|
|
60618
60685
|
name: "Drop-some test",
|
|
60686
|
+
short: "drop-some",
|
|
60619
60687
|
desc: "Re-estimate on random subsamples; a trustworthy effect stays put.",
|
|
60620
|
-
value:
|
|
60621
|
-
passed
|
|
60688
|
+
value: passed ? `stayed at ${signed(ds)} ± ${fmt$1(dstd)}` : `moved to ${signed(ds)} ± ${fmt$1(dstd)}`,
|
|
60689
|
+
passed,
|
|
60622
60690
|
tip: none$1,
|
|
60623
60691
|
help: "check_dropsome"
|
|
60624
60692
|
});
|
|
@@ -60627,8 +60695,9 @@ function deriveRefute(r2, adj) {
|
|
|
60627
60695
|
if (rcc !== void 0) {
|
|
60628
60696
|
checks.push({
|
|
60629
60697
|
name: "Decoy cause",
|
|
60698
|
+
short: "decoy",
|
|
60630
60699
|
desc: "Add an irrelevant random factor; the answer should not move.",
|
|
60631
|
-
value: rcc ? "
|
|
60700
|
+
value: rcc ? "didn’t move" : "moved",
|
|
60632
60701
|
passed: rcc,
|
|
60633
60702
|
tip: none$1,
|
|
60634
60703
|
help: "check_decoy"
|
|
@@ -60636,14 +60705,18 @@ function deriveRefute(r2, adj) {
|
|
|
60636
60705
|
}
|
|
60637
60706
|
const sens = getSomeorUndefined(r2.sensitivity);
|
|
60638
60707
|
const evalue = getSomeorUndefined(r2.robustness_value);
|
|
60708
|
+
const benchmarks = sens ? [...sens.benchmarks].sort((a2, b2) => b2.strength - a2.strength) : [];
|
|
60639
60709
|
if (sens !== void 0 || evalue !== void 0) {
|
|
60640
60710
|
const strengths = sens ? arr(sens.strengths) : [];
|
|
60641
60711
|
const effects = sens ? arr(sens.effects) : [];
|
|
60642
60712
|
const tip = sens ? zeroCrossing(strengths, effects) : null;
|
|
60643
|
-
const
|
|
60713
|
+
const strongest = benchmarks[0];
|
|
60714
|
+
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";
|
|
60715
|
+
const scaleNote = strongest !== void 0 ? ` For scale, your strongest known factor (${labelOf(meta3, strongest.column)}) sits at ${fmt$1(strongest.strength)} on this axis.` : "";
|
|
60644
60716
|
checks.push({
|
|
60645
60717
|
name: "Hidden cause",
|
|
60646
|
-
|
|
60718
|
+
short: "hidden cause",
|
|
60719
|
+
desc: `How strong an unrecorded common cause would need to be to overturn the result.${scaleNote}`,
|
|
60647
60720
|
value,
|
|
60648
60721
|
passed: tip === null,
|
|
60649
60722
|
tip: some("Something unrecorded could drive both the treatment choice and the outcome."),
|
|
@@ -60659,7 +60732,23 @@ function deriveRefute(r2, adj) {
|
|
|
60659
60732
|
const lo2 = mid.map((m2) => m2 - half);
|
|
60660
60733
|
const hi = mid.map((m2) => m2 + half);
|
|
60661
60734
|
const yLo = Math.min(0, ...lo2), yHi = Math.max(...hi, 0);
|
|
60662
|
-
|
|
60735
|
+
const strengths = arr(sens.strengths);
|
|
60736
|
+
const atOf = (s2) => {
|
|
60737
|
+
if (strengths.length < 2) return null;
|
|
60738
|
+
if (s2 <= strengths[0]) return 0;
|
|
60739
|
+
for (let i = 1; i < strengths.length; i++) {
|
|
60740
|
+
if (s2 <= strengths[i]) {
|
|
60741
|
+
const span = strengths[i] - strengths[i - 1];
|
|
60742
|
+
return span > 0 ? i - 1 + (s2 - strengths[i - 1]) / span : i;
|
|
60743
|
+
}
|
|
60744
|
+
}
|
|
60745
|
+
return strengths.length - 1;
|
|
60746
|
+
};
|
|
60747
|
+
const marks = benchmarks.slice(0, 2).flatMap((b2) => {
|
|
60748
|
+
const at = atOf(b2.strength);
|
|
60749
|
+
return at === null ? [] : [{ at, label: `as strong as ${labelOf(meta3, b2.column)}`, tone: "muted", help: "sensitivity" }];
|
|
60750
|
+
});
|
|
60751
|
+
sensVM = { lo: lo2, mid, hi, xTicks: ["none", "", "stronger"], yTicks: [fmt$1(yLo), fmt$1((yLo + yHi) / 2), fmt$1(yHi)], marks };
|
|
60663
60752
|
}
|
|
60664
60753
|
}
|
|
60665
60754
|
return { checks, sens: sensVM };
|
|
@@ -60696,21 +60785,26 @@ function deriveDose(dose, config2, meta3) {
|
|
|
60696
60785
|
const marks = [];
|
|
60697
60786
|
if (sizes.length) marks.push({ at: here, label: "you are here", tone: "muted", help: "dose_here" });
|
|
60698
60787
|
marks.push({ at: sweet, label: "sweet spot", tone: "pos", help: "dose_sweet" });
|
|
60788
|
+
const featureLabel = labelOf(meta3, dose.feature);
|
|
60789
|
+
const outcomeLabel = labelOf(meta3, config2.outcome);
|
|
60699
60790
|
return {
|
|
60700
|
-
feature:
|
|
60701
|
-
outcome:
|
|
60791
|
+
feature: featureLabel,
|
|
60792
|
+
outcome: outcomeLabel,
|
|
60702
60793
|
lo: lo2,
|
|
60703
60794
|
mid,
|
|
60704
60795
|
hi,
|
|
60705
60796
|
xTicks,
|
|
60706
60797
|
yTicks,
|
|
60707
60798
|
marks,
|
|
60708
|
-
|
|
60799
|
+
// Name the feature in the recommendation — a bare "≈ 5.5" doesn't say
|
|
60800
|
+
// 5.5 of WHAT.
|
|
60801
|
+
recoLabel: `aim for ${featureLabel} ≈ ${fmt$1(grid[sweet] ?? 0)}${featureUnit ? " " + featureUnit : ""}`,
|
|
60709
60802
|
recoEffect: mid[sweet] ?? 0,
|
|
60710
60803
|
recoLo: lo2[sweet] ?? 0,
|
|
60711
60804
|
recoHi: hi[sweet] ?? 0,
|
|
60712
60805
|
tradeoff,
|
|
60713
|
-
marginal
|
|
60806
|
+
marginal,
|
|
60807
|
+
framing: `A different question from the headline: how ${outcomeLabel} responds as ${featureLabel} itself moves.`
|
|
60714
60808
|
};
|
|
60715
60809
|
}
|
|
60716
60810
|
function relTime(d2, now2) {
|
|
@@ -60727,12 +60821,12 @@ const VERDICT_WORD = {
|
|
|
60727
60821
|
non_identifiable_positivity: "no overlap",
|
|
60728
60822
|
not_estimable: "n/a"
|
|
60729
60823
|
};
|
|
60730
|
-
function deriveJournalRow(row, now2) {
|
|
60824
|
+
function deriveJournalRow(row, now2, meta3) {
|
|
60731
60825
|
const adj = getSomeorUndefined(row.adjusted);
|
|
60732
60826
|
return {
|
|
60733
|
-
treatment: row.config.treatment,
|
|
60734
|
-
outcome: row.config.outcome,
|
|
60735
|
-
confounders: row.config.common_causes.join(", "),
|
|
60827
|
+
treatment: labelOf(meta3, row.config.treatment),
|
|
60828
|
+
outcome: labelOf(meta3, row.config.outcome),
|
|
60829
|
+
confounders: row.config.common_causes.map((c2) => labelOf(meta3, c2)).join(", "),
|
|
60736
60830
|
effect: adj !== void 0 ? signed(adj) : signed(row.naive),
|
|
60737
60831
|
verdict: VERDICT_WORD[row.verdict.type],
|
|
60738
60832
|
verdictTone: VERDICT_TONE[row.verdict.type],
|
|
@@ -60743,22 +60837,27 @@ function deriveJournalRow(row, now2) {
|
|
|
60743
60837
|
preset: row.preset
|
|
60744
60838
|
};
|
|
60745
60839
|
}
|
|
60746
|
-
function deriveView(config2, ranConfig, cols, result, journal, meta3, dataLen, now2) {
|
|
60840
|
+
function deriveView(config2, ranConfig, cols, result, journal, meta3, dataLen, now2, subject = { one: "record", many: "records" }) {
|
|
60841
|
+
var _a2;
|
|
60747
60842
|
const adj = result ? getSomeorUndefined(result.adjusted) : void 0;
|
|
60748
60843
|
const refutation = result ? getSomeorUndefined(result.refutation) : void 0;
|
|
60749
60844
|
const doseR = result ? getSomeorUndefined(result.dose_response) : void 0;
|
|
60845
|
+
const answer = result && adj ? deriveAnswer(ranConfig, result, adj, meta3) : null;
|
|
60846
|
+
const refute = refutation ? deriveRefute(refutation, adj, meta3) : null;
|
|
60847
|
+
const higherBetter = getSomeorUndefined((_a2 = colMeta(meta3, ranConfig.outcome)) == null ? void 0 : _a2.higherIsBetter);
|
|
60750
60848
|
return {
|
|
60751
60849
|
// The set-up rail reflects the LIVE config (the editor); the result deck
|
|
60752
60850
|
// reflects RANCONFIG — the config that produced `result` — so the result
|
|
60753
60851
|
// strings never drift ahead of the numbers on a live picker edit.
|
|
60754
|
-
spec: deriveSpec(config2, cols, result, meta3, dataLen),
|
|
60852
|
+
spec: deriveSpec(config2, cols, result, meta3, dataLen, subject),
|
|
60755
60853
|
verdict: result ? deriveVerdict(result.verdict) : null,
|
|
60756
|
-
|
|
60757
|
-
|
|
60854
|
+
narrative: result ? deriveNarrative(result, answer, refute, higherBetter, subject) : null,
|
|
60855
|
+
answer,
|
|
60856
|
+
refusal: result && !adj ? deriveRefusal(ranConfig, result, meta3, subject) : null,
|
|
60758
60857
|
overlap: result ? deriveOverlap(result.overlap) : null,
|
|
60759
|
-
refute
|
|
60858
|
+
refute,
|
|
60760
60859
|
dose: doseR && doseR.effect.length ? deriveDose(doseR, ranConfig, meta3) : null,
|
|
60761
|
-
journal: journal ? journal.map((r2) => deriveJournalRow(r2, now2)) : null
|
|
60860
|
+
journal: journal ? journal.map((r2) => deriveJournalRow(r2, now2, meta3)) : null
|
|
60762
60861
|
};
|
|
60763
60862
|
}
|
|
60764
60863
|
const DESIGN_HEADLINE = {
|
|
@@ -60840,8 +60939,7 @@ function deriveDesign(d2, result, ranConfig, meta3) {
|
|
|
60840
60939
|
faint
|
|
60841
60940
|
};
|
|
60842
60941
|
}
|
|
60843
|
-
const
|
|
60844
|
-
const SUBJECT_MANY = "records";
|
|
60942
|
+
const SUBJECT_DEFAULT = { one: "record", many: "records" };
|
|
60845
60943
|
const AUTORUN_MAX_ROWS = 5e4;
|
|
60846
60944
|
const TONE_TOKEN = {
|
|
60847
60945
|
neg: "fg.danger",
|
|
@@ -60910,7 +61008,10 @@ function rowMatchesAll(row, preds) {
|
|
|
60910
61008
|
}
|
|
60911
61009
|
const num = (x2) => typeof x2 === "number" ? x2 : typeof x2 === "bigint" ? Number(x2) : null;
|
|
60912
61010
|
function Cap({ children: children2, help }) {
|
|
60913
|
-
return /* @__PURE__ */
|
|
61011
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
61012
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "caption.eyebrow", fontSize: "9px", mb: "2.5", children: help ? /* @__PURE__ */ jsx$1(Help, { id: help, children: children2 }) : children2 }),
|
|
61013
|
+
help && /* @__PURE__ */ jsx$1(GuidanceGist, { id: help })
|
|
61014
|
+
] });
|
|
60914
61015
|
}
|
|
60915
61016
|
function Card({ children: children2, mt = "3" }) {
|
|
60916
61017
|
return /* @__PURE__ */ jsx$1(Box, { layerStyle: "card", p: "3.5", borderRadius: "lg", mt, children: children2 });
|
|
@@ -61032,6 +61133,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61032
61133
|
const data4 = useBindingValue(v3.data);
|
|
61033
61134
|
const journalBind = useBindingValue(v3.journal.type === "some" ? v3.journal.value : null);
|
|
61034
61135
|
const meta3 = getSomeorUndefined(v3.columnMeta);
|
|
61136
|
+
const subject = getSomeorUndefined(v3.subject) ?? SUBJECT_DEFAULT;
|
|
61035
61137
|
const readonly = getSomeorUndefined(v3.readonly) ?? false;
|
|
61036
61138
|
const configsBind = useBindingValue(v3.configs);
|
|
61037
61139
|
const configs = useMemo(() => configsBind.value ?? [], [configsBind.value]);
|
|
@@ -61168,16 +61270,16 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61168
61270
|
const nRows = (filteredRows == null ? void 0 : filteredRows.length) ?? 0;
|
|
61169
61271
|
const helpVars = useMemo(() => {
|
|
61170
61272
|
const rc = ranConfig ?? config2;
|
|
61171
|
-
const
|
|
61273
|
+
const labelOf2 = (col) => {
|
|
61172
61274
|
var _a3;
|
|
61173
61275
|
return col ? getSomeorUndefined((_a3 = meta3 == null ? void 0 : meta3.get(col)) == null ? void 0 : _a3.label) ?? col : "";
|
|
61174
61276
|
};
|
|
61175
|
-
return { treatment:
|
|
61176
|
-
}, [ranConfig, config2, meta3]);
|
|
61277
|
+
return { treatment: labelOf2(rc == null ? void 0 : rc.treatment), outcome: labelOf2(rc == null ? void 0 : rc.outcome), subject: subject.one, subjects: subject.many };
|
|
61278
|
+
}, [ranConfig, config2, meta3, subject]);
|
|
61177
61279
|
const view = useMemo(() => {
|
|
61178
61280
|
if (!config2) return null;
|
|
61179
|
-
return deriveView(config2, ranConfig ?? config2, columns, shownResult, journalBind.value, meta3, nRows, now2);
|
|
61180
|
-
}, [config2, ranConfig, columns, shownResult, journalBind.value, meta3, nRows, now2]);
|
|
61281
|
+
return deriveView(config2, ranConfig ?? config2, columns, shownResult, journalBind.value, meta3, nRows, now2, subject);
|
|
61282
|
+
}, [config2, ranConfig, columns, shownResult, journalBind.value, meta3, nRows, now2, subject]);
|
|
61181
61283
|
const designConfigValue = useMemo(() => ({
|
|
61182
61284
|
alpha: none$1,
|
|
61183
61285
|
target_power: none$1,
|
|
@@ -61232,16 +61334,18 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61232
61334
|
const showResult = shownResult !== null && !experiment.pending && !failed;
|
|
61233
61335
|
const anyPrecomputedDesign = configs.some((c2) => c2.design.type === "some");
|
|
61234
61336
|
const showValidate = hasDesign || anyPrecomputedDesign;
|
|
61235
|
-
const
|
|
61337
|
+
const showDose = getSomeorUndefined(config2.dose_feature) !== void 0 || (shownResult == null ? void 0 : shownResult.dose_response.type) === "some";
|
|
61338
|
+
const tabKeys = [...["answer", "trust"], ...showDose ? ["dose"] : [], ...showValidate ? ["validate"] : []];
|
|
61339
|
+
const activeTab = tabKeys.includes(tab) ? tab : "answer";
|
|
61236
61340
|
return /* @__PURE__ */ jsx$1(GuidanceProvider, { on: guidance, vars: helpVars, children: /* @__PURE__ */ jsxs(Box, { layerStyle: "surface.frameless", overflow: "visible", children: [
|
|
61237
61341
|
/* @__PURE__ */ jsxs(Box, { layerStyle: "header.bar", display: "flex", alignItems: "center", gap: "3.5", children: [
|
|
61238
61342
|
configs.length > 1 ? /* @__PURE__ */ jsxs(Menu.Root, { children: [
|
|
61239
61343
|
/* @__PURE__ */ jsx$1(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(Box, { as: "button", bg: "transparent", border: "0", p: "0", cursor: "pointer", display: "inline-flex", alignItems: "center", gap: "2", textAlign: "start", children: [
|
|
61240
61344
|
/* @__PURE__ */ jsxs(Text, { textStyle: "title.card", color: "fg.muted", children: [
|
|
61241
61345
|
"Does ",
|
|
61242
|
-
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.
|
|
61346
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.treatmentLabel }),
|
|
61243
61347
|
" change ",
|
|
61244
|
-
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.
|
|
61348
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.outcomeLabel }),
|
|
61245
61349
|
"?"
|
|
61246
61350
|
] }),
|
|
61247
61351
|
/* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.subtle", fontSize: "11px", lineHeight: "1", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faChevronDown }) })
|
|
@@ -61255,9 +61359,9 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61255
61359
|
] }, g2.label)) }) }) })
|
|
61256
61360
|
] }) : /* @__PURE__ */ jsx$1(Text, { textStyle: "title.card", color: "fg.muted", children: /* @__PURE__ */ jsxs(Help, { id: "header", children: [
|
|
61257
61361
|
"Does ",
|
|
61258
|
-
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.
|
|
61362
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.treatmentLabel }),
|
|
61259
61363
|
" change ",
|
|
61260
|
-
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.
|
|
61364
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "brand.solid", fontWeight: "bold", children: vs.outcomeLabel }),
|
|
61261
61365
|
"?"
|
|
61262
61366
|
] }) }),
|
|
61263
61367
|
/* @__PURE__ */ jsx$1(Box, { flex: "1" }),
|
|
@@ -61297,7 +61401,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61297
61401
|
"add another"
|
|
61298
61402
|
] }) })
|
|
61299
61403
|
] }) }),
|
|
61300
|
-
/* @__PURE__ */ jsx$1(Step, { n: 4, title: `Which ${
|
|
61404
|
+
/* @__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 }) }),
|
|
61301
61405
|
/* @__PURE__ */ jsxs(Box, { as: "details", borderTopWidth: "1px", borderColor: "border.subtle", children: [
|
|
61302
61406
|
/* @__PURE__ */ jsxs(
|
|
61303
61407
|
Box,
|
|
@@ -61348,7 +61452,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61348
61452
|
"aria-label": "Result views",
|
|
61349
61453
|
onKeyDown: (e3) => {
|
|
61350
61454
|
var _a3;
|
|
61351
|
-
const i = tabKeys.indexOf(
|
|
61455
|
+
const i = tabKeys.indexOf(activeTab);
|
|
61352
61456
|
let j2 = i;
|
|
61353
61457
|
if (e3.key === "ArrowRight") j2 = (i + 1) % tabKeys.length;
|
|
61354
61458
|
else if (e3.key === "ArrowLeft") j2 = (i - 1 + tabKeys.length) % tabKeys.length;
|
|
@@ -61362,9 +61466,9 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61362
61466
|
},
|
|
61363
61467
|
children: [
|
|
61364
61468
|
tabKeys.map((tk) => {
|
|
61365
|
-
const on3 =
|
|
61469
|
+
const on3 = activeTab === tk;
|
|
61366
61470
|
const tabHelp = tk === "answer" ? "tab_answer" : tk === "trust" ? "tab_trust" : tk === "dose" ? "tab_dose" : "tab_validate";
|
|
61367
|
-
const tabLabel = tk === "answer" ? "
|
|
61471
|
+
const tabLabel = tk === "answer" ? "The answer" : tk === "trust" ? "Can we trust it?" : tk === "dose" ? "How much?" : "Prove it";
|
|
61368
61472
|
return /* @__PURE__ */ jsx$1(
|
|
61369
61473
|
Box,
|
|
61370
61474
|
{
|
|
@@ -61396,7 +61500,7 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61396
61500
|
]
|
|
61397
61501
|
}
|
|
61398
61502
|
),
|
|
61399
|
-
failed ? /* @__PURE__ */ jsx$1(Box, { px: "4.5", pt: "4.5", children: /* @__PURE__ */ jsx$1(RunError, { error: experiment.error }) }) : !showResult ? /* @__PURE__ */ jsx$1(DeckSkeleton, { tab }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
61503
|
+
failed ? /* @__PURE__ */ jsx$1(Box, { px: "4.5", pt: "4.5", children: /* @__PURE__ */ jsx$1(RunError, { error: experiment.error }) }) : !showResult ? /* @__PURE__ */ jsx$1(DeckSkeleton, { tab: activeTab }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
61400
61504
|
stale && /* @__PURE__ */ jsxs(Box, { layerStyle: "banner.stale", display: "flex", alignItems: "center", gap: "2", mx: "4.5", mt: "4.5", children: [
|
|
61401
61505
|
/* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.warning", flexShrink: "0", fontSize: "12px", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation }) }),
|
|
61402
61506
|
/* @__PURE__ */ jsxs(Text, { textStyle: "body.sm", color: "fg.default", children: [
|
|
@@ -61404,9 +61508,22 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61404
61508
|
" Hit Run to update these results for your edits."
|
|
61405
61509
|
] })
|
|
61406
61510
|
] }),
|
|
61407
|
-
|
|
61408
|
-
|
|
61409
|
-
|
|
61511
|
+
activeTab === "answer" && a2 && /* @__PURE__ */ jsx$1(
|
|
61512
|
+
AnswerNumeric,
|
|
61513
|
+
{
|
|
61514
|
+
a: a2,
|
|
61515
|
+
verdict,
|
|
61516
|
+
narrative: view.narrative,
|
|
61517
|
+
checks: (vr == null ? void 0 : vr.checks) ?? null,
|
|
61518
|
+
onGoTrust: () => setTab("trust"),
|
|
61519
|
+
subjectMany: subject.many,
|
|
61520
|
+
higherBetter,
|
|
61521
|
+
badge,
|
|
61522
|
+
barList
|
|
61523
|
+
}
|
|
61524
|
+
),
|
|
61525
|
+
activeTab === "answer" && !a2 && ref && /* @__PURE__ */ jsx$1(RefusalZone, { refusal: ref, overlap: ov, naiveValue: (shownResult == null ? void 0 : shownResult.naive) ?? 0, outcome: vs.outcomeLabel }),
|
|
61526
|
+
activeTab === "trust" && vr && /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
|
|
61410
61527
|
/* @__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." }) }),
|
|
61411
61528
|
/* @__PURE__ */ jsx$1(Box, { layerStyle: "frame.flat", children: vr.checks.map((c2, i) => {
|
|
61412
61529
|
const cs = statusR({ status: c2.passed ? "success" : "warning", size: "sm" });
|
|
@@ -61424,10 +61541,34 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61424
61541
|
}) }),
|
|
61425
61542
|
vr.sens && /* @__PURE__ */ jsxs(Card, { children: [
|
|
61426
61543
|
/* @__PURE__ */ jsx$1(Cap, { help: "sensitivity", children: "Effect as a hidden cause is made stronger" }),
|
|
61427
|
-
/* @__PURE__ */ jsx$1(
|
|
61544
|
+
/* @__PURE__ */ jsx$1(
|
|
61545
|
+
AreaRange,
|
|
61546
|
+
{
|
|
61547
|
+
lo: vr.sens.lo,
|
|
61548
|
+
mid: vr.sens.mid,
|
|
61549
|
+
hi: vr.sens.hi,
|
|
61550
|
+
zero: 0,
|
|
61551
|
+
tone: "brand",
|
|
61552
|
+
xTicks: vr.sens.xTicks,
|
|
61553
|
+
yTicks: vr.sens.yTicks,
|
|
61554
|
+
marks: vr.sens.marks,
|
|
61555
|
+
height: vr.sens.marks.length ? 148 : 132
|
|
61556
|
+
}
|
|
61557
|
+
)
|
|
61428
61558
|
] })
|
|
61429
61559
|
] }),
|
|
61430
|
-
|
|
61560
|
+
activeTab === "trust" && !vr && // Two distinct reasons the checklist is absent: the engine REFUSED
|
|
61561
|
+
// (no adjusted estimate to break) vs. the answer landed WITHOUT a
|
|
61562
|
+
// robustness summary (e.g. a precomputed result whose stress tests
|
|
61563
|
+
// were never run). Conflating them asserted a refusal that didn't
|
|
61564
|
+
// happen.
|
|
61565
|
+
((shownResult == null ? void 0 : shownResult.adjusted.type) === "some" ? /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
|
|
61566
|
+
/* @__PURE__ */ jsxs(Box, { display: "inline-flex", alignItems: "center", gap: "2", mb: "2", color: "fg.muted", children: [
|
|
61567
|
+
/* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation, style: { fontSize: "13px" } }),
|
|
61568
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", fontWeight: "semibold", color: "fg.default", children: "Stress tests not run" })
|
|
61569
|
+
] }),
|
|
61570
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", lineHeight: "1.5", children: "This answer came without a robustness summary — the stress tests weren’t run for this question, so there’s nothing to report here." })
|
|
61571
|
+
] }) : /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
|
|
61431
61572
|
/* @__PURE__ */ jsxs(Box, { display: "inline-flex", alignItems: "center", gap: "2", mb: "2", color: "fg.muted", children: [
|
|
61432
61573
|
/* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation, style: { fontSize: "13px" } }),
|
|
61433
61574
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", fontWeight: "semibold", color: "fg.default", children: "Nothing to stress-test" })
|
|
@@ -61437,8 +61578,9 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61437
61578
|
/* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", color: "fg.default", children: "Answer" }),
|
|
61438
61579
|
" tab for why)."
|
|
61439
61580
|
] })
|
|
61440
|
-
] }),
|
|
61441
|
-
|
|
61581
|
+
] })),
|
|
61582
|
+
activeTab === "dose" && vd && /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
|
|
61583
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", mb: "3.5", children: /* @__PURE__ */ jsx$1(Help, { id: "tab_dose", children: vd.framing }) }),
|
|
61442
61584
|
/* @__PURE__ */ jsxs(Card, { mt: "0", children: [
|
|
61443
61585
|
/* @__PURE__ */ jsxs(Cap, { help: "dose_curve", children: [
|
|
61444
61586
|
vd.outcome,
|
|
@@ -61475,7 +61617,27 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61475
61617
|
] })
|
|
61476
61618
|
] })
|
|
61477
61619
|
] }),
|
|
61478
|
-
|
|
61620
|
+
activeTab === "dose" && !vd && // The tab is reachable (a dose feature is configured) but the shown
|
|
61621
|
+
// result has no curve — e.g. a refusal verdict, or the engine
|
|
61622
|
+
// returned no dose-response for this setup. Say so; never a blank pane.
|
|
61623
|
+
/* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
|
|
61624
|
+
/* @__PURE__ */ jsxs(Box, { display: "inline-flex", alignItems: "center", gap: "2", mb: "2", color: "fg.muted", children: [
|
|
61625
|
+
/* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation, style: { fontSize: "13px" } }),
|
|
61626
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", fontWeight: "semibold", color: "fg.default", children: "No dose-response to show" })
|
|
61627
|
+
] }),
|
|
61628
|
+
(shownResult == null ? void 0 : shownResult.adjusted.type) === "some" ? /* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", lineHeight: "1.5", children: "The experiment didn’t return a how-much curve for this setup." }) : /* @__PURE__ */ jsxs(Text, { textStyle: "body.sm", color: "fg.muted", lineHeight: "1.5", children: [
|
|
61629
|
+
"A how-much curve needs a like-for-like estimate, and the experiment couldn’t produce one (see the ",
|
|
61630
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", color: "fg.default", children: "Answer" }),
|
|
61631
|
+
" tab for why)."
|
|
61632
|
+
] })
|
|
61633
|
+
] }),
|
|
61634
|
+
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: [
|
|
61635
|
+
/* @__PURE__ */ jsxs(Box, { display: "inline-flex", alignItems: "center", gap: "2", mb: "2", color: "fg.muted", children: [
|
|
61636
|
+
/* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation, style: { fontSize: "13px" } }),
|
|
61637
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", fontWeight: "semibold", color: "fg.default", children: "No trial recipe for this question" })
|
|
61638
|
+
] }),
|
|
61639
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", color: "fg.muted", lineHeight: "1.5", children: "This question doesn’t include a validation-trial recipe, and no design function is bound to size one." })
|
|
61640
|
+
] }) : /* @__PURE__ */ jsxs(Box, { p: "4.5", display: "inline-flex", alignItems: "center", gap: "2", color: "fg.muted", children: [
|
|
61479
61641
|
/* @__PURE__ */ jsx$1(Spinner, { size: "xs", borderWidth: "1.5px", color: "brand.solid" }),
|
|
61480
61642
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "body.sm", children: "Sizing the trial that would confirm this…" })
|
|
61481
61643
|
] }))
|
|
@@ -61485,11 +61647,11 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61485
61647
|
journal && journal.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
61486
61648
|
/* @__PURE__ */ jsxs(Box, { css: es.root, bg: "bg.canvas", borderTopWidth: "1px", borderColor: "border.subtle", children: [
|
|
61487
61649
|
/* @__PURE__ */ jsx$1(Box, { css: es.lbl, children: /* @__PURE__ */ jsx$1(Help, { id: "journal", children: "Committed experiments" }) }),
|
|
61488
|
-
/* @__PURE__ */
|
|
61650
|
+
/* @__PURE__ */ jsx$1(Box, { css: es.meta, children: /* @__PURE__ */ jsxs(Text, { as: "span", children: [
|
|
61489
61651
|
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: journal.length }),
|
|
61490
61652
|
" on record",
|
|
61491
61653
|
journal.length > 50 ? " · showing newest 50" : ""
|
|
61492
|
-
] })
|
|
61654
|
+
] }) })
|
|
61493
61655
|
] }),
|
|
61494
61656
|
journal.slice(0, 50).map((r2, i) => /* @__PURE__ */ jsxs(Box, { display: "grid", gridTemplateColumns: "2fr 1fr 1fr 1fr", gap: "3", alignItems: "center", px: "4.5", py: "2.5", borderTopWidth: "1px", borderColor: "border.subtle", children: [
|
|
61495
61657
|
/* @__PURE__ */ jsxs(Text, { textStyle: "body.sm", children: [
|
|
@@ -61528,24 +61690,31 @@ const EastChakraExperiment = memo(function EastChakraExperiment2({ value }) {
|
|
|
61528
61690
|
] })
|
|
61529
61691
|
] }) });
|
|
61530
61692
|
}, (prev2, next2) => experimentValueEqual(prev2.value, next2.value) && prev2.storageKey === next2.storageKey);
|
|
61531
|
-
function AnswerNumeric({ a: a2, verdict, higherBetter, badge, barList }) {
|
|
61693
|
+
function AnswerNumeric({ a: a2, verdict, narrative, checks, onGoTrust, subjectMany, higherBetter, badge, barList }) {
|
|
61532
61694
|
const dirUp = a2.effect > 0;
|
|
61533
61695
|
const statusWord = higherBetter === void 0 ? dirUp ? "Higher" : "Lower" : dirUp === higherBetter ? "Better" : "Worse";
|
|
61534
61696
|
const lowerWord = a2.naive < 0 ? "lower" : "higher";
|
|
61535
|
-
const top = a2.balance[0] ?? {
|
|
61697
|
+
const top = a2.balance[0] ?? { label: "", display: "" };
|
|
61536
61698
|
const kpiColor = a2.clear && !a2.cautious ? "fg.success" : "fg.warning";
|
|
61537
61699
|
const badgeOk = a2.clear && !a2.cautious;
|
|
61538
61700
|
const badgeText = a2.cautious ? (verdict == null ? void 0 : verdict.label) ?? "Not trustworthy yet" : a2.clear ? `${statusWord} with ${a2.treatment}` : "No clear effect";
|
|
61539
61701
|
return /* @__PURE__ */ jsxs(Box, { p: "4.5", children: [
|
|
61702
|
+
narrative && /* @__PURE__ */ jsx$1(Text, { textStyle: "body.md", color: "fg.default", lineHeight: "1.6", mb: "3.5", children: narrative.segments.map((s2, i) => s2.strong ? /* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "bold", color: toneToken(narrative.tone), children: s2.text }, i) : /* @__PURE__ */ jsx$1(Text, { as: "span", children: s2.text }, i)) }),
|
|
61540
61703
|
/* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "4.5", flexWrap: "wrap", children: [
|
|
61541
61704
|
/* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", gap: "0.5", children: [
|
|
61542
61705
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "mono.sm", color: "fg.muted", children: a2.outcome }),
|
|
61543
61706
|
/* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "baseline", gap: "2.5", children: [
|
|
61544
|
-
/* @__PURE__ */ jsx$1(Text, { textStyle: "mono-kpi", fontFamily: "heading", fontSize: "32px", color: kpiColor, children: /* @__PURE__ */
|
|
61707
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "mono-kpi", fontFamily: "heading", fontSize: "32px", color: kpiColor, children: /* @__PURE__ */ jsxs(Help, { id: "answer_effect", children: [
|
|
61708
|
+
signed(a2.effect),
|
|
61709
|
+
a2.unit ? /* @__PURE__ */ jsxs(Text, { as: "span", fontSize: "16px", color: "fg.muted", children: [
|
|
61710
|
+
" ",
|
|
61711
|
+
a2.unit
|
|
61712
|
+
] }) : null
|
|
61713
|
+
] }) }),
|
|
61545
61714
|
/* @__PURE__ */ jsx$1(Text, { textStyle: "mono.sm", color: "fg.muted", children: /* @__PURE__ */ jsxs(Help, { id: "answer_ci", children: [
|
|
61546
|
-
"
|
|
61715
|
+
"likely between ",
|
|
61547
61716
|
signed(a2.lo),
|
|
61548
|
-
"
|
|
61717
|
+
" and ",
|
|
61549
61718
|
signed(a2.hi)
|
|
61550
61719
|
] }) })
|
|
61551
61720
|
] })
|
|
@@ -61555,6 +61724,42 @@ function AnswerNumeric({ a: a2, verdict, higherBetter, badge, barList }) {
|
|
|
61555
61724
|
/* @__PURE__ */ jsx$1(Help, { id: `verdict_${(verdict == null ? void 0 : verdict.tag) ?? "modest"}`, children: badgeText })
|
|
61556
61725
|
] })
|
|
61557
61726
|
] }),
|
|
61727
|
+
checks && checks.length > 0 && /* @__PURE__ */ jsxs(
|
|
61728
|
+
Box,
|
|
61729
|
+
{
|
|
61730
|
+
as: "button",
|
|
61731
|
+
onClick: onGoTrust,
|
|
61732
|
+
display: "inline-flex",
|
|
61733
|
+
alignItems: "center",
|
|
61734
|
+
gap: "2",
|
|
61735
|
+
flexWrap: "wrap",
|
|
61736
|
+
mt: "2.5",
|
|
61737
|
+
bg: "transparent",
|
|
61738
|
+
border: "0",
|
|
61739
|
+
p: "0",
|
|
61740
|
+
cursor: "pointer",
|
|
61741
|
+
title: "See the full stress-test checklist",
|
|
61742
|
+
children: [
|
|
61743
|
+
/* @__PURE__ */ jsx$1(Text, { textStyle: "caption", color: "fg.muted", children: "Stress tests:" }),
|
|
61744
|
+
checks.map((c2, i) => /* @__PURE__ */ jsxs(
|
|
61745
|
+
Box,
|
|
61746
|
+
{
|
|
61747
|
+
as: "span",
|
|
61748
|
+
display: "inline-flex",
|
|
61749
|
+
alignItems: "center",
|
|
61750
|
+
gap: "1.5",
|
|
61751
|
+
color: c2.passed ? "fg.success" : "fg.warning",
|
|
61752
|
+
children: [
|
|
61753
|
+
/* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: c2.passed ? faCheck : faTriangleExclamation, style: { fontSize: "10px" } }),
|
|
61754
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", textStyle: "caption", color: "fg.default", children: c2.short }),
|
|
61755
|
+
i < checks.length - 1 && /* @__PURE__ */ jsx$1(Text, { as: "span", textStyle: "caption", color: "fg.subtle", children: "·" })
|
|
61756
|
+
]
|
|
61757
|
+
},
|
|
61758
|
+
i
|
|
61759
|
+
))
|
|
61760
|
+
]
|
|
61761
|
+
}
|
|
61762
|
+
),
|
|
61558
61763
|
a2.cautious && /* @__PURE__ */ jsxs(Box, { layerStyle: "banner.stale", display: "flex", alignItems: "flex-start", gap: "2", mt: "3", children: [
|
|
61559
61764
|
/* @__PURE__ */ jsx$1(Box, { as: "span", color: "fg.warning", flexShrink: "0", mt: "0.5", fontSize: "12px", children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faTriangleExclamation }) }),
|
|
61560
61765
|
/* @__PURE__ */ jsxs(Text, { textStyle: "body.sm", color: "fg.default", children: [
|
|
@@ -61568,15 +61773,15 @@ function AnswerNumeric({ a: a2, verdict, higherBetter, badge, barList }) {
|
|
|
61568
61773
|
/* @__PURE__ */ jsxs(Text, { textStyle: "body.sm", color: "fg.default", children: [
|
|
61569
61774
|
/* @__PURE__ */ jsx$1(Help, { id: "answer_flip", children: /* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "bold", children: "Raw and like-for-like disagree." }) }),
|
|
61570
61775
|
" In the plain average, the ",
|
|
61571
|
-
/* @__PURE__ */ jsx$1(Text, { as: "span",
|
|
61776
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", children: a2.treatment }),
|
|
61572
61777
|
" group sits ",
|
|
61573
61778
|
/* @__PURE__ */ jsx$1(Text, { as: "span", fontStyle: "italic", children: lowerWord }),
|
|
61574
61779
|
" on ",
|
|
61575
|
-
/* @__PURE__ */ jsx$1(Text, { as: "span",
|
|
61780
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", children: a2.outcome }),
|
|
61576
61781
|
" (",
|
|
61577
61782
|
signed(a2.naive),
|
|
61578
61783
|
") — but they also differ most on ",
|
|
61579
|
-
/* @__PURE__ */ jsx$1(Text, { as: "span",
|
|
61784
|
+
/* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", children: top.label }),
|
|
61580
61785
|
" (",
|
|
61581
61786
|
top.display,
|
|
61582
61787
|
"). Adjusting for it reverses the result."
|
|
@@ -61599,11 +61804,40 @@ function AnswerNumeric({ a: a2, verdict, higherBetter, badge, barList }) {
|
|
|
61599
61804
|
}
|
|
61600
61805
|
)
|
|
61601
61806
|
] }),
|
|
61602
|
-
/* @__PURE__ */ jsxs(
|
|
61603
|
-
/* @__PURE__ */
|
|
61604
|
-
|
|
61807
|
+
/* @__PURE__ */ jsxs(Box, { as: "details", layerStyle: "card", borderRadius: "lg", mt: "3", children: [
|
|
61808
|
+
/* @__PURE__ */ jsxs(
|
|
61809
|
+
Box,
|
|
61810
|
+
{
|
|
61811
|
+
as: "summary",
|
|
61812
|
+
textStyle: "caption.eyebrow",
|
|
61813
|
+
fontSize: "9px",
|
|
61814
|
+
cursor: "pointer",
|
|
61815
|
+
p: "3.5",
|
|
61816
|
+
display: "flex",
|
|
61817
|
+
alignItems: "center",
|
|
61818
|
+
gap: "1.5",
|
|
61819
|
+
css: { listStyle: "none", "&::-webkit-details-marker": { display: "none" } },
|
|
61820
|
+
children: [
|
|
61821
|
+
/* @__PURE__ */ jsx$1(
|
|
61822
|
+
Box,
|
|
61823
|
+
{
|
|
61824
|
+
as: "span",
|
|
61825
|
+
display: "inline-flex",
|
|
61826
|
+
color: "fg.subtle",
|
|
61827
|
+
fontSize: "10px",
|
|
61828
|
+
transition: "transform 180ms ease",
|
|
61829
|
+
transform: "rotate(-90deg)",
|
|
61830
|
+
css: { "details[open] > summary > &": { transform: "rotate(0deg)" } },
|
|
61831
|
+
children: /* @__PURE__ */ jsx$1(FontAwesomeIcon, { icon: faChevronDown })
|
|
61832
|
+
}
|
|
61833
|
+
),
|
|
61834
|
+
/* @__PURE__ */ jsx$1(Help, { id: "balance", children: "How we levelled the playing field" })
|
|
61835
|
+
]
|
|
61836
|
+
}
|
|
61837
|
+
),
|
|
61838
|
+
/* @__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 }))) })
|
|
61605
61839
|
] }),
|
|
61606
|
-
/* @__PURE__ */ jsx$1(Box, { mt: "3.5", children: /* @__PURE__ */ jsx$1(Help, { id: "counts", display: "inline-flex", gap: "4", children: [[a2.nTotal,
|
|
61840
|
+
/* @__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: [
|
|
61607
61841
|
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.default", fontWeight: "semibold", children: Number(n2) }),
|
|
61608
61842
|
" ",
|
|
61609
61843
|
label
|
|
@@ -61707,7 +61941,7 @@ function ValidatePanel({ vm, barList }) {
|
|
|
61707
61941
|
] }, i)) })
|
|
61708
61942
|
] });
|
|
61709
61943
|
}
|
|
61710
|
-
function FilterRail({ fields, population, onChange: onChange2, chip, button, readonly }) {
|
|
61944
|
+
function FilterRail({ fields, population, onChange: onChange2, chip, button, readonly, subjectMany }) {
|
|
61711
61945
|
const [open, setOpen] = useState(null);
|
|
61712
61946
|
const replaceAt = (i, p2) => onChange2(population.map((f2, j2) => j2 === i ? p2 : f2));
|
|
61713
61947
|
const removeAt = (i) => onChange2(population.filter((_2, j2) => j2 !== i));
|
|
@@ -61715,7 +61949,7 @@ function FilterRail({ fields, population, onChange: onChange2, chip, button, rea
|
|
|
61715
61949
|
if (readonly) {
|
|
61716
61950
|
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: [
|
|
61717
61951
|
"all ",
|
|
61718
|
-
|
|
61952
|
+
subjectMany
|
|
61719
61953
|
] }) : 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)) });
|
|
61720
61954
|
}
|
|
61721
61955
|
return /* @__PURE__ */ jsxs(Box, { display: "flex", flexWrap: "wrap", gap: "1.5", alignItems: "center", children: [
|
|
@@ -62676,6 +62910,39 @@ const URGENCY_RANK = {
|
|
|
62676
62910
|
due: 1,
|
|
62677
62911
|
routine: 2
|
|
62678
62912
|
};
|
|
62913
|
+
const URGENCY_GROUP_LABEL = {
|
|
62914
|
+
overdue: "Overdue",
|
|
62915
|
+
due: "Due today",
|
|
62916
|
+
routine: "Routine"
|
|
62917
|
+
};
|
|
62918
|
+
function buildGroups(rows, option) {
|
|
62919
|
+
if (option.key === "none") {
|
|
62920
|
+
return [{ label: "", decisions: rows, pastSla: 0, total: 0, bulk: false }];
|
|
62921
|
+
}
|
|
62922
|
+
const labelFor = (d2) => {
|
|
62923
|
+
var _a2;
|
|
62924
|
+
return option.key === "urgency" ? URGENCY_GROUP_LABEL[d2.urgency.type] : option.key === "kind" ? d2.kind : ((_a2 = option.accessor) == null ? void 0 : _a2.call(option, d2)) ?? "";
|
|
62925
|
+
};
|
|
62926
|
+
const out = /* @__PURE__ */ new Map();
|
|
62927
|
+
for (const d2 of rows) {
|
|
62928
|
+
const label = labelFor(d2);
|
|
62929
|
+
let group2 = out.get(label);
|
|
62930
|
+
if (group2 === void 0) {
|
|
62931
|
+
group2 = {
|
|
62932
|
+
label,
|
|
62933
|
+
decisions: [],
|
|
62934
|
+
pastSla: 0,
|
|
62935
|
+
total: 0,
|
|
62936
|
+
bulk: option.key === "urgency" && d2.urgency.type === "routine"
|
|
62937
|
+
};
|
|
62938
|
+
out.set(label, group2);
|
|
62939
|
+
}
|
|
62940
|
+
group2.decisions.push(d2);
|
|
62941
|
+
group2.total += d2.value;
|
|
62942
|
+
if (d2.urgency.type === "overdue") group2.pastSla += 1;
|
|
62943
|
+
}
|
|
62944
|
+
return [...out.values()];
|
|
62945
|
+
}
|
|
62679
62946
|
const FACETS = [
|
|
62680
62947
|
{ key: "evidence", label: "Evidence" },
|
|
62681
62948
|
{ key: "options", label: "Options" },
|
|
@@ -62792,7 +63059,8 @@ const Row = memo(function Row2({ decision, handle, selected: selected2, narrow,
|
|
|
62792
63059
|
),
|
|
62793
63060
|
/* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "ghost", size: "xs" }), onClick: handleReject, children: "Reject" })
|
|
62794
63061
|
] });
|
|
62795
|
-
const
|
|
63062
|
+
const fullTitle = `${decision.kind} · ${decision.title}${summary !== void 0 ? ` · ${summary}` : ""}`;
|
|
63063
|
+
const title = /* @__PURE__ */ jsxs(Box, { css: rs.titleText, title: fullTitle, cursor: selected2 ? void 0 : "pointer", onClick: handleSelect, children: [
|
|
62796
63064
|
/* @__PURE__ */ jsx$1(Text, { as: "span", fontWeight: "semibold", children: decision.kind }),
|
|
62797
63065
|
/* @__PURE__ */ jsx$1(Text, { as: "span", color: "fg.subtle", children: " · " }),
|
|
62798
63066
|
/* @__PURE__ */ jsx$1(Text, { as: "span", children: decision.title }),
|
|
@@ -62877,10 +63145,39 @@ const RoutineGroup = memo(function RoutineGroup2({ routine, acceptAll, leaving,
|
|
|
62877
63145
|
] })
|
|
62878
63146
|
] });
|
|
62879
63147
|
});
|
|
63148
|
+
const GroupHead = memo(function GroupHead2({ group: group2, collapsible, collapsed, onToggle, acceptAll }) {
|
|
63149
|
+
const dq = useSlotRecipe({ key: "decisionQueue" });
|
|
63150
|
+
const button = useRecipe({ key: "button" });
|
|
63151
|
+
const rs = dq({});
|
|
63152
|
+
const format2 = group2.decisions[0] ? getSomeorUndefined(group2.decisions[0].format) : void 0;
|
|
63153
|
+
const handleToggle = useCallback(() => {
|
|
63154
|
+
if (collapsible) onToggle(group2.label);
|
|
63155
|
+
}, [collapsible, onToggle, group2.label]);
|
|
63156
|
+
const handleAcceptAll = useCallback((e3) => {
|
|
63157
|
+
e3.stopPropagation();
|
|
63158
|
+
if (acceptAll) acceptAll(group2.decisions);
|
|
63159
|
+
}, [acceptAll, group2.decisions]);
|
|
63160
|
+
return /* @__PURE__ */ jsxs(Box, { css: rs.groupHead, ...collapsible ? { "data-collapsible": "" } : {}, onClick: handleToggle, children: [
|
|
63161
|
+
collapsible && /* @__PURE__ */ jsx$1(Box, { as: "span", css: rs.groupCaret, children: collapsed ? "▸" : "▾" }),
|
|
63162
|
+
/* @__PURE__ */ jsxs(Box, { as: "span", css: rs.groupLabel, children: [
|
|
63163
|
+
group2.label,
|
|
63164
|
+
" · ",
|
|
63165
|
+
group2.decisions.length
|
|
63166
|
+
] }),
|
|
63167
|
+
/* @__PURE__ */ jsxs(Box, { as: "span", css: rs.groupSummary, children: [
|
|
63168
|
+
formatTick(group2.total, format2),
|
|
63169
|
+
group2.pastSla > 0 ? ` · ${group2.pastSla} past SLA` : ""
|
|
63170
|
+
] }),
|
|
63171
|
+
acceptAll && /* @__PURE__ */ jsx$1(Box, { as: "button", css: button({ variant: "solid", size: "xs" }), onClick: handleAcceptAll, children: "Accept all" })
|
|
63172
|
+
] });
|
|
63173
|
+
});
|
|
62880
63174
|
const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value, storageKey }) {
|
|
62881
63175
|
var _a2;
|
|
62882
63176
|
const eyebrow = useSlotRecipe({ key: "eyebrowRow" });
|
|
62883
63177
|
const es = eyebrow({});
|
|
63178
|
+
const dq = useSlotRecipe({ key: "decisionQueue" });
|
|
63179
|
+
const qs = dq({});
|
|
63180
|
+
const chip = useRecipe({ key: "chip" });
|
|
62884
63181
|
const handleRef = value.handle;
|
|
62885
63182
|
const handle = useDecisionHandle(handleRef);
|
|
62886
63183
|
const decisions = handle.decisions;
|
|
@@ -62949,6 +63246,25 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
|
|
|
62949
63246
|
return facets === void 0 ? null : new Set(facets.map((f2) => f2.type));
|
|
62950
63247
|
}, [value.facets]);
|
|
62951
63248
|
const defaultExpanded = getSomeorUndefined(value.defaultExpanded);
|
|
63249
|
+
const groupDefs = useMemo(
|
|
63250
|
+
() => getSomeorUndefined(value.groups) ?? [],
|
|
63251
|
+
[value.groups]
|
|
63252
|
+
);
|
|
63253
|
+
const defaultGroupKey = getSomeorUndefined(value.groupBy);
|
|
63254
|
+
const grouped = defaultGroupKey !== void 0;
|
|
63255
|
+
const collapsible = grouped && (getSomeorUndefined(value.collapsible) ?? true);
|
|
63256
|
+
const groupOptions = useMemo(() => [
|
|
63257
|
+
{ key: "urgency", label: "Urgency" },
|
|
63258
|
+
{ key: "kind", label: "Kind" },
|
|
63259
|
+
...groupDefs.map((g2) => ({ key: g2.label, label: g2.label, accessor: g2.value })),
|
|
63260
|
+
{ key: "none", label: "None" }
|
|
63261
|
+
], [groupDefs]);
|
|
63262
|
+
const { state: toolbar, setState: setToolbar } = usePersistedState(`${storageKey}.toolbar`, {
|
|
63263
|
+
groupKey: defaultGroupKey ?? "urgency",
|
|
63264
|
+
// The urgency grouping's routine tail ships collapsed.
|
|
63265
|
+
collapsed: [URGENCY_GROUP_LABEL.routine]
|
|
63266
|
+
});
|
|
63267
|
+
const activeOption = groupOptions.find((o2) => o2.key === toolbar.groupKey) ?? groupOptions[0];
|
|
62952
63268
|
const selectedId = handle.selected ?? (defaultExpanded == null ? void 0 : defaultExpanded.id) ?? null;
|
|
62953
63269
|
const resolve2 = useCallback((ds, hook2, reason) => {
|
|
62954
63270
|
if (hook2) for (const d2 of ds) {
|
|
@@ -62963,15 +63279,15 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
|
|
|
62963
63279
|
const apply2 = useCallback((d2) => resolve2([d2], onApply, "apply"), [resolve2, onApply]);
|
|
62964
63280
|
const reject2 = useCallback((d2) => resolve2([d2], onReject, "reject"), [resolve2, onReject]);
|
|
62965
63281
|
const acceptAll = useCallback((ds) => resolve2(ds, onApply, "apply"), [resolve2, onApply]);
|
|
62966
|
-
const { active, routine, pastSla, visible } = useMemo(() => {
|
|
63282
|
+
const { merged, active, routine, pastSla, visible } = useMemo(() => {
|
|
62967
63283
|
const scoped = decisions ?? [];
|
|
62968
63284
|
const now2 = /* @__PURE__ */ new Date();
|
|
62969
63285
|
const live = sliceState !== null ? scoped.filter((d2) => sliceMatches(sliceState, DECISION_SLICE_CONFIG, d2, now2)) : scoped;
|
|
62970
|
-
const
|
|
63286
|
+
const merged2 = [...live];
|
|
62971
63287
|
for (const { decision } of exiting.values()) {
|
|
62972
|
-
if (!
|
|
63288
|
+
if (!merged2.some((d2) => d2.id === decision.id)) merged2.push(decision);
|
|
62973
63289
|
}
|
|
62974
|
-
|
|
63290
|
+
merged2.sort((a2, b2) => {
|
|
62975
63291
|
var _a3, _b2;
|
|
62976
63292
|
const r2 = URGENCY_RANK[a2.urgency.type] - URGENCY_RANK[b2.urgency.type];
|
|
62977
63293
|
if (r2 !== 0) return r2;
|
|
@@ -62981,17 +63297,55 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
|
|
|
62981
63297
|
return b2.value - a2.value;
|
|
62982
63298
|
});
|
|
62983
63299
|
return {
|
|
62984
|
-
|
|
62985
|
-
|
|
62986
|
-
|
|
63300
|
+
merged: merged2,
|
|
63301
|
+
active: merged2.filter((d2) => d2.urgency.type !== "routine"),
|
|
63302
|
+
routine: merged2.filter((d2) => d2.urgency.type === "routine"),
|
|
63303
|
+
pastSla: merged2.filter((d2) => d2.urgency.type === "overdue").length,
|
|
62987
63304
|
visible: live.length
|
|
62988
63305
|
};
|
|
62989
63306
|
}, [decisions, exiting, sliceState]);
|
|
63307
|
+
const groups = useMemo(
|
|
63308
|
+
() => grouped ? buildGroups(merged, activeOption) : [],
|
|
63309
|
+
[grouped, merged, activeOption]
|
|
63310
|
+
);
|
|
63311
|
+
const allCollapsed = groups.length > 0 && groups.every((g2) => g2.label === "" || toolbar.collapsed.includes(g2.label));
|
|
63312
|
+
const toggleGroup = useCallback((label) => {
|
|
63313
|
+
setToolbar((prev2) => ({
|
|
63314
|
+
...prev2,
|
|
63315
|
+
collapsed: prev2.collapsed.includes(label) ? prev2.collapsed.filter((l2) => l2 !== label) : [...prev2.collapsed, label]
|
|
63316
|
+
}));
|
|
63317
|
+
}, [setToolbar]);
|
|
63318
|
+
const toggleAll = useCallback(() => {
|
|
63319
|
+
const next2 = allCollapsed ? [] : groups.map((g2) => g2.label).filter((l2) => l2 !== "");
|
|
63320
|
+
setToolbar((prev2) => ({ ...prev2, collapsed: next2 }));
|
|
63321
|
+
}, [setToolbar, allCollapsed, groups]);
|
|
63322
|
+
const setGroupKey = useCallback((key) => {
|
|
63323
|
+
setToolbar((prev2) => prev2.groupKey === key ? prev2 : { ...prev2, groupKey: key });
|
|
63324
|
+
}, [setToolbar]);
|
|
62990
63325
|
const exitingReasons = useMemo(() => {
|
|
62991
63326
|
const m2 = /* @__PURE__ */ new Map();
|
|
62992
63327
|
for (const [id3, e3] of exiting) m2.set(id3, e3.reason);
|
|
62993
63328
|
return m2;
|
|
62994
63329
|
}, [exiting]);
|
|
63330
|
+
const renderRow = (d2) => /* @__PURE__ */ jsx$1(
|
|
63331
|
+
Row,
|
|
63332
|
+
{
|
|
63333
|
+
decision: d2,
|
|
63334
|
+
handle,
|
|
63335
|
+
selected: selectedId === d2.id,
|
|
63336
|
+
narrow,
|
|
63337
|
+
leverPayloads,
|
|
63338
|
+
modify,
|
|
63339
|
+
evidence,
|
|
63340
|
+
defaultFacet,
|
|
63341
|
+
facetInclude,
|
|
63342
|
+
apply: apply2,
|
|
63343
|
+
reject: reject2,
|
|
63344
|
+
leaving: exitingReasons.get(d2.id),
|
|
63345
|
+
storageKey
|
|
63346
|
+
},
|
|
63347
|
+
d2.id
|
|
63348
|
+
);
|
|
62995
63349
|
if (decisions === null) {
|
|
62996
63350
|
return /* @__PURE__ */ jsx$1(Box, { layerStyle: "surface.frameless", p: "16px", children: /* @__PURE__ */ jsx$1(Text, { color: "fg.muted", fontSize: "13px", children: "Loading decisions…" }) });
|
|
62997
63351
|
}
|
|
@@ -63019,33 +63373,45 @@ const EastChakraDecisionQueue = memo(function EastChakraDecisionQueue2({ value,
|
|
|
63019
63373
|
] })
|
|
63020
63374
|
] })
|
|
63021
63375
|
] }),
|
|
63022
|
-
/* @__PURE__ */ jsxs(
|
|
63376
|
+
grouped && /* @__PURE__ */ jsxs(Box, { css: qs.toolbar, children: [
|
|
63377
|
+
/* @__PURE__ */ jsx$1(Box, { as: "span", css: qs.segLabel, children: "Group by" }),
|
|
63378
|
+
groupOptions.map((o2) => /* @__PURE__ */ jsx$1(
|
|
63379
|
+
Box,
|
|
63380
|
+
{
|
|
63381
|
+
as: "button",
|
|
63382
|
+
css: { ...chip({ tone: toolbar.groupKey === o2.key ? "brand" : "neutral", size: "sm" }), cursor: "pointer" },
|
|
63383
|
+
"aria-pressed": toolbar.groupKey === o2.key,
|
|
63384
|
+
onClick: () => setGroupKey(o2.key),
|
|
63385
|
+
children: o2.label
|
|
63386
|
+
},
|
|
63387
|
+
o2.key
|
|
63388
|
+
)),
|
|
63389
|
+
collapsible && /* @__PURE__ */ jsx$1(Box, { as: "button", css: qs.collapseAll, onClick: toggleAll, children: allCollapsed ? "Expand all" : "Collapse all" })
|
|
63390
|
+
] }),
|
|
63391
|
+
/* @__PURE__ */ jsx$1(
|
|
63023
63392
|
Box,
|
|
63024
63393
|
{
|
|
63025
63394
|
maxHeight: getSomeorUndefined(value.maxHeight),
|
|
63026
63395
|
overflowY: value.maxHeight.type === "some" ? "auto" : void 0,
|
|
63027
|
-
children:
|
|
63028
|
-
|
|
63029
|
-
|
|
63030
|
-
|
|
63031
|
-
|
|
63032
|
-
|
|
63033
|
-
|
|
63034
|
-
|
|
63035
|
-
|
|
63036
|
-
|
|
63037
|
-
|
|
63038
|
-
|
|
63039
|
-
|
|
63040
|
-
|
|
63041
|
-
|
|
63042
|
-
|
|
63043
|
-
|
|
63044
|
-
},
|
|
63045
|
-
d2.id
|
|
63046
|
-
)),
|
|
63396
|
+
children: grouped ? groups.map((g2) => {
|
|
63397
|
+
const isCollapsed = collapsible && g2.label !== "" && toolbar.collapsed.includes(g2.label);
|
|
63398
|
+
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
63399
|
+
g2.label !== "" && /* @__PURE__ */ jsx$1(
|
|
63400
|
+
GroupHead,
|
|
63401
|
+
{
|
|
63402
|
+
group: g2,
|
|
63403
|
+
collapsible,
|
|
63404
|
+
collapsed: isCollapsed,
|
|
63405
|
+
onToggle: toggleGroup,
|
|
63406
|
+
acceptAll: g2.bulk ? acceptAll : void 0
|
|
63407
|
+
}
|
|
63408
|
+
),
|
|
63409
|
+
!isCollapsed && g2.decisions.map(renderRow)
|
|
63410
|
+
] }, g2.label || "_flat");
|
|
63411
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
63412
|
+
active.map(renderRow),
|
|
63047
63413
|
/* @__PURE__ */ jsx$1(RoutineGroup, { routine, acceptAll, leaving: exitingReasons, narrow })
|
|
63048
|
-
]
|
|
63414
|
+
] })
|
|
63049
63415
|
}
|
|
63050
63416
|
)
|
|
63051
63417
|
] });
|