@validation-os/dashboard 0.16.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -59,7 +59,7 @@ import {
59
59
  QUESTION_TYPES,
60
60
  STAGES
61
61
  } from "@validation-os/core";
62
- import { isNonEvidence, riskThresholdForStage } from "@validation-os/core/derivation";
62
+ import { confidenceFloorForStage, isNonEvidence, riskThresholdForStage } from "@validation-os/core/derivation";
63
63
 
64
64
  // src/breadcrumb.tsx
65
65
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1518,7 +1518,8 @@ function AssumptionDetail({
1518
1518
  const framed = derived.completeness ?? 0;
1519
1519
  const stageKey = STAGES.find((s) => s === stage);
1520
1520
  const riskThreshold = stageKey ? riskThresholdForStage(stageKey) : null;
1521
- const clearedThreshold = riskThreshold != null ? risk <= riskThreshold : null;
1521
+ const confFloor = stageKey ? confidenceFloorForStage(stageKey) : null;
1522
+ const clearedThreshold = riskThreshold != null && confFloor != null ? risk <= riskThreshold && confidence2 >= confFloor : null;
1522
1523
  const nextMove2 = nextMoveFor(record, experiments.records ?? []);
1523
1524
  const linkedExperiments = liveExperiments(experiments.records ?? []).filter((e) => {
1524
1525
  const ids = Array.isArray(e.barLineAssumptionIds) ? e.barLineAssumptionIds : [];
@@ -1560,24 +1561,17 @@ function AssumptionDetail({
1560
1561
  /* @__PURE__ */ jsx4(ScoreCard, { label: "Confidence", value: formatSigned(confidence2) }),
1561
1562
  /* @__PURE__ */ jsx4(ScoreCard, { label: "Framed", value: `${Math.round(framed)}%` })
1562
1563
  ] }),
1563
- riskThreshold != null ? /* @__PURE__ */ jsxs4("div", { className: "vos-card vos-threshold-indicator", children: [
1564
- /* @__PURE__ */ jsx4("div", { className: "vos-threshold-label", children: "Stage threshold" }),
1565
- /* @__PURE__ */ jsxs4("div", { className: "vos-threshold-row", children: [
1566
- /* @__PURE__ */ jsxs4("span", { className: "vos-num", children: [
1567
- "Risk ",
1568
- Math.round(risk)
1569
- ] }),
1570
- /* @__PURE__ */ jsx4("span", { className: "vos-threshold-bar vos-num", children: riskThreshold }),
1571
- /* @__PURE__ */ jsx4(
1572
- "span",
1573
- {
1574
- className: `vos-threshold-status ${clearedThreshold ? "vos-threshold-cleared" : "vos-threshold-needs"}`,
1575
- children: clearedThreshold ? "Cleared for this stage" : "Needs evidence"
1576
- }
1577
- )
1578
- ] }),
1579
- /* @__PURE__ */ jsx4("div", { className: "vos-threshold-hint", children: clearedThreshold ? `Risk at or below the ${stage} threshold \u2014 de-prioritized.` : `Risk above the ${stage} threshold \u2014 testing-priority.` })
1580
- ] }) : null,
1564
+ riskThreshold != null ? /* @__PURE__ */ jsx4(
1565
+ ThresholdBar,
1566
+ {
1567
+ risk,
1568
+ threshold: riskThreshold,
1569
+ confidence: confidence2,
1570
+ confFloor: confFloor ?? 0,
1571
+ stage,
1572
+ cleared: clearedThreshold ?? false
1573
+ }
1574
+ ) : null,
1581
1575
  /* @__PURE__ */ jsx4(EvidenceCompositionView, { assumption: record, readings: readings.records ?? [] }),
1582
1576
  /* @__PURE__ */ jsx4(ConfidenceExplainerView, { assumption: record, readings: readings.records ?? [] }),
1583
1577
  statement ? /* @__PURE__ */ jsxs4("div", { className: "vos-card vos-detail-section", children: [
@@ -1800,6 +1794,88 @@ function ScoreCard({
1800
1794
  /* @__PURE__ */ jsx4("div", { className: "vos-score-label", children: label })
1801
1795
  ] });
1802
1796
  }
1797
+ function ThresholdBar({
1798
+ risk,
1799
+ threshold,
1800
+ confidence: confidence2,
1801
+ confFloor,
1802
+ stage,
1803
+ cleared
1804
+ }) {
1805
+ const riskTrackMax = Math.max(risk, threshold) * 1.25;
1806
+ const riskPct = Math.min(100, risk / riskTrackMax * 100);
1807
+ const thresholdPct = Math.min(100, threshold / riskTrackMax * 100);
1808
+ const confPct = Math.min(100, Math.abs(confidence2));
1809
+ const confFloorPct = Math.min(100, confFloor);
1810
+ const riskBelow = risk <= threshold;
1811
+ const confAbove = confidence2 >= confFloor;
1812
+ const tone = cleared ? "good" : !riskBelow && !confAbove ? "crit" : "warn";
1813
+ return /* @__PURE__ */ jsxs4("div", { className: "vos-card vos-threshold-bar-card", children: [
1814
+ /* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-header", children: [
1815
+ /* @__PURE__ */ jsxs4("span", { className: "vos-threshold-bar-title", children: [
1816
+ stage,
1817
+ " evidence bar",
1818
+ /* @__PURE__ */ jsx4("span", { className: "vos-threshold-bar-stage-tag", children: stage })
1819
+ ] }),
1820
+ /* @__PURE__ */ jsx4("span", { className: `vos-threshold-bar-status vos-threshold-bar-${tone}`, children: cleared ? "Cleared" : "Needs evidence" })
1821
+ ] }),
1822
+ /* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-section", children: [
1823
+ /* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-section-label", children: [
1824
+ /* @__PURE__ */ jsx4("span", { children: "Risk" }),
1825
+ /* @__PURE__ */ jsx4("span", { className: "vos-num vos-threshold-bar-section-val", children: Math.round(risk) }),
1826
+ /* @__PURE__ */ jsxs4("span", { className: "vos-threshold-bar-section-target", children: [
1827
+ "bar \u2264 ",
1828
+ threshold
1829
+ ] })
1830
+ ] }),
1831
+ /* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-track", children: [
1832
+ /* @__PURE__ */ jsx4(
1833
+ "div",
1834
+ {
1835
+ className: `vos-threshold-bar-fill vos-fill-${riskBelow ? "good" : tone}`,
1836
+ style: { width: `${riskPct}%` }
1837
+ }
1838
+ ),
1839
+ /* @__PURE__ */ jsx4(
1840
+ "div",
1841
+ {
1842
+ className: "vos-threshold-bar-marker",
1843
+ style: { left: `${thresholdPct}%` },
1844
+ title: `Risk threshold: ${threshold}`
1845
+ }
1846
+ )
1847
+ ] })
1848
+ ] }),
1849
+ /* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-section", children: [
1850
+ /* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-section-label", children: [
1851
+ /* @__PURE__ */ jsx4("span", { children: "Confidence" }),
1852
+ /* @__PURE__ */ jsx4("span", { className: "vos-num vos-threshold-bar-section-val", children: formatSigned(confidence2) }),
1853
+ /* @__PURE__ */ jsxs4("span", { className: "vos-threshold-bar-section-target", children: [
1854
+ "floor \u2265 ",
1855
+ confFloor
1856
+ ] })
1857
+ ] }),
1858
+ /* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-track vos-threshold-bar-track-conf", children: [
1859
+ /* @__PURE__ */ jsx4(
1860
+ "div",
1861
+ {
1862
+ className: `vos-threshold-bar-fill vos-fill-${confAbove ? "good" : tone}`,
1863
+ style: { width: `${confPct}%` }
1864
+ }
1865
+ ),
1866
+ /* @__PURE__ */ jsx4(
1867
+ "div",
1868
+ {
1869
+ className: "vos-threshold-bar-marker vos-threshold-bar-marker-conf",
1870
+ style: { left: `${confFloorPct}%` },
1871
+ title: `Confidence floor: ${confFloor}`
1872
+ }
1873
+ )
1874
+ ] })
1875
+ ] }),
1876
+ /* @__PURE__ */ jsx4("div", { className: "vos-threshold-bar-hint", children: cleared ? `Risk ${Math.round(risk)} \u2264 ${threshold} and Confidence ${formatSigned(confidence2)} \u2265 ${confFloor} \u2014 cleared for ${stage}.` : `Risk ${Math.round(risk)} ${riskBelow ? "\u2264" : ">"} ${threshold}, Confidence ${formatSigned(confidence2)} ${confAbove ? "\u2265" : "<"} ${confFloor} \u2014 needs ${!riskBelow ? "lower Risk" : ""}${!riskBelow && !confAbove ? " + " : ""}${!confAbove ? "higher Confidence" : ""}.` })
1877
+ ] });
1878
+ }
1803
1879
  function riskTone(risk) {
1804
1880
  if (risk >= 70) return "crit";
1805
1881
  if (risk >= 40) return "warn";
@@ -2134,7 +2210,7 @@ import {
2134
2210
  assumptionCompleteness,
2135
2211
  readingBeliefInputs
2136
2212
  } from "@validation-os/core";
2137
- import { riskThresholdForStage as riskThresholdForStage2 } from "@validation-os/core/derivation";
2213
+ import { confidenceFloorForStage as confidenceFloorForStage2, riskThresholdForStage as riskThresholdForStage2 } from "@validation-os/core/derivation";
2138
2214
 
2139
2215
  // src/stage-grid-model.ts
2140
2216
  var STAGE_ORDER = [
@@ -2334,6 +2410,7 @@ function buildPipeline(assumptions, experiments) {
2334
2410
  const stageName = str3(a.Stage);
2335
2411
  const stageKey = stageName && STAGE_ORDER.includes(stageName) ? stageName : null;
2336
2412
  const riskThreshold = stageKey ? riskThresholdForStage2(stageKey) : null;
2413
+ const confFloor = stageKey ? confidenceFloorForStage2(stageKey) : null;
2337
2414
  rows.push({
2338
2415
  id: a.id,
2339
2416
  statement: str3(a.Title),
@@ -2350,7 +2427,7 @@ function buildPipeline(assumptions, experiments) {
2350
2427
  questionType,
2351
2428
  stage: stageName,
2352
2429
  riskThreshold,
2353
- clearedThreshold: riskThreshold != null ? d.risk <= riskThreshold : null
2430
+ clearedThreshold: riskThreshold != null ? d.risk <= riskThreshold && (confFloor == null || stage.confidence >= confFloor) : null
2354
2431
  });
2355
2432
  }
2356
2433
  rows.sort(