@validation-os/dashboard 0.16.0 → 0.16.2
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.d.ts +3 -0
- package/dist/index.js +109 -23
- package/dist/index.js.map +1 -1
- package/dist/styles.css +176 -9
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -586,6 +586,9 @@ interface PipelineRow {
|
|
|
586
586
|
nextMove: string;
|
|
587
587
|
/** The assumption's Question Type (DEV-5890) — kind of claim. */
|
|
588
588
|
questionType: string | null;
|
|
589
|
+
/** The max ceiling for this question type (highest anchor across all
|
|
590
|
+
* rungs) — the Known meter fills relative to this, not the absolute 100. */
|
|
591
|
+
questionTypeCeiling: number | null;
|
|
589
592
|
/** The assumption's Stage (DEV-5890) — kind of response / threshold. */
|
|
590
593
|
stage: string | null;
|
|
591
594
|
/** The stage's Risk threshold (DEV-5890) — the stopping bar. */
|
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
|
|
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__ */
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
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,84 @@ 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 confPct = Math.min(100, Math.max(0, Math.abs(confidence2)));
|
|
1806
|
+
const confFloorPct = Math.min(100, confFloor);
|
|
1807
|
+
const riskBelow = risk <= threshold;
|
|
1808
|
+
const confAbove = confidence2 >= confFloor;
|
|
1809
|
+
const tone = cleared ? "good" : !riskBelow && !confAbove ? "crit" : "warn";
|
|
1810
|
+
return /* @__PURE__ */ jsxs4("div", { className: "vos-card vos-threshold-bar-card", children: [
|
|
1811
|
+
/* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-header", children: [
|
|
1812
|
+
/* @__PURE__ */ jsxs4("span", { className: "vos-threshold-bar-title", children: [
|
|
1813
|
+
"Evidence needed",
|
|
1814
|
+
/* @__PURE__ */ jsx4("span", { className: "vos-threshold-bar-stage-tag", children: stage })
|
|
1815
|
+
] }),
|
|
1816
|
+
/* @__PURE__ */ jsx4("span", { className: `vos-threshold-bar-status vos-threshold-bar-${tone}`, children: cleared ? "Cleared" : "Needs evidence" })
|
|
1817
|
+
] }),
|
|
1818
|
+
/* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-section", children: [
|
|
1819
|
+
/* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-section-label", children: [
|
|
1820
|
+
/* @__PURE__ */ jsx4("span", { children: "Confidence" }),
|
|
1821
|
+
/* @__PURE__ */ jsx4("span", { className: "vos-num vos-threshold-bar-section-val", children: formatSigned(confidence2) }),
|
|
1822
|
+
/* @__PURE__ */ jsxs4("span", { className: "vos-threshold-bar-section-target", children: [
|
|
1823
|
+
"need \u2265 ",
|
|
1824
|
+
confFloor,
|
|
1825
|
+
" ",
|
|
1826
|
+
cleared ? "\u2713" : ""
|
|
1827
|
+
] })
|
|
1828
|
+
] }),
|
|
1829
|
+
/* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-track vos-threshold-bar-track-tall", children: [
|
|
1830
|
+
/* @__PURE__ */ jsx4(
|
|
1831
|
+
"div",
|
|
1832
|
+
{
|
|
1833
|
+
className: "vos-threshold-bar-target-zone",
|
|
1834
|
+
style: { left: `${confFloorPct}%` }
|
|
1835
|
+
}
|
|
1836
|
+
),
|
|
1837
|
+
/* @__PURE__ */ jsx4(
|
|
1838
|
+
"div",
|
|
1839
|
+
{
|
|
1840
|
+
className: `vos-threshold-bar-fill vos-fill-${confAbove ? "good" : tone}`,
|
|
1841
|
+
style: { width: `${confPct}%` }
|
|
1842
|
+
}
|
|
1843
|
+
),
|
|
1844
|
+
/* @__PURE__ */ jsx4(
|
|
1845
|
+
"div",
|
|
1846
|
+
{
|
|
1847
|
+
className: "vos-threshold-bar-marker",
|
|
1848
|
+
style: { left: `${confFloorPct}%` },
|
|
1849
|
+
title: `Need Confidence \u2265 ${confFloor} for ${stage}`,
|
|
1850
|
+
children: /* @__PURE__ */ jsx4("span", { className: "vos-threshold-bar-marker-label vos-num", children: confFloor })
|
|
1851
|
+
}
|
|
1852
|
+
)
|
|
1853
|
+
] }),
|
|
1854
|
+
/* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-scale", children: [
|
|
1855
|
+
/* @__PURE__ */ jsx4("span", { className: "vos-num", children: "0" }),
|
|
1856
|
+
/* @__PURE__ */ jsx4("span", { className: "vos-num vos-threshold-bar-scale-mid", children: "50" }),
|
|
1857
|
+
/* @__PURE__ */ jsx4("span", { className: "vos-num", children: "100" })
|
|
1858
|
+
] })
|
|
1859
|
+
] }),
|
|
1860
|
+
/* @__PURE__ */ jsxs4("div", { className: "vos-threshold-bar-risk-summary", children: [
|
|
1861
|
+
/* @__PURE__ */ jsxs4("span", { className: `vos-threshold-bar-risk-val vos-text-${riskBelow ? "good" : "crit"}`, children: [
|
|
1862
|
+
"Risk ",
|
|
1863
|
+
Math.round(risk)
|
|
1864
|
+
] }),
|
|
1865
|
+
/* @__PURE__ */ jsxs4("span", { className: "vos-threshold-bar-risk-cap", children: [
|
|
1866
|
+
"max ",
|
|
1867
|
+
threshold,
|
|
1868
|
+
" for ",
|
|
1869
|
+
stage
|
|
1870
|
+
] })
|
|
1871
|
+
] }),
|
|
1872
|
+
/* @__PURE__ */ jsx4("div", { className: "vos-threshold-bar-hint", children: cleared ? `Confidence ${formatSigned(confidence2)} \u2265 ${confFloor} and Risk ${Math.round(risk)} \u2264 ${threshold} \u2014 cleared for ${stage}.` : `Need Confidence \u2265 ${confFloor}${!confAbove ? ` (now ${formatSigned(confidence2)})` : " \u2713"} and Risk \u2264 ${threshold}${!riskBelow ? ` (now ${Math.round(risk)})` : " \u2713"}.` })
|
|
1873
|
+
] });
|
|
1874
|
+
}
|
|
1803
1875
|
function riskTone(risk) {
|
|
1804
1876
|
if (risk >= 70) return "crit";
|
|
1805
1877
|
if (risk >= 40) return "warn";
|
|
@@ -2134,7 +2206,11 @@ import {
|
|
|
2134
2206
|
assumptionCompleteness,
|
|
2135
2207
|
readingBeliefInputs
|
|
2136
2208
|
} from "@validation-os/core";
|
|
2137
|
-
import {
|
|
2209
|
+
import {
|
|
2210
|
+
confidenceFloorForStage as confidenceFloorForStage2,
|
|
2211
|
+
riskThresholdForStage as riskThresholdForStage2,
|
|
2212
|
+
RUNG_ANCHOR as RUNG_ANCHOR3
|
|
2213
|
+
} from "@validation-os/core/derivation";
|
|
2138
2214
|
|
|
2139
2215
|
// src/stage-grid-model.ts
|
|
2140
2216
|
var STAGE_ORDER = [
|
|
@@ -2331,9 +2407,17 @@ function buildPipeline(assumptions, experiments) {
|
|
|
2331
2407
|
const framed = assumptionCompleteness(a);
|
|
2332
2408
|
const stage = deriveBeliefStage({ framed, confidence: d.confidence, test });
|
|
2333
2409
|
const questionType = str3(a["Question Type"]);
|
|
2410
|
+
let questionTypeCeiling = null;
|
|
2411
|
+
if (questionType && questionType in RUNG_ANCHOR3) {
|
|
2412
|
+
const subLadder = RUNG_ANCHOR3[questionType];
|
|
2413
|
+
questionTypeCeiling = Math.max(
|
|
2414
|
+
...Object.values(subLadder).map((r) => r.High)
|
|
2415
|
+
);
|
|
2416
|
+
}
|
|
2334
2417
|
const stageName = str3(a.Stage);
|
|
2335
2418
|
const stageKey = stageName && STAGE_ORDER.includes(stageName) ? stageName : null;
|
|
2336
2419
|
const riskThreshold = stageKey ? riskThresholdForStage2(stageKey) : null;
|
|
2420
|
+
const confFloor = stageKey ? confidenceFloorForStage2(stageKey) : null;
|
|
2337
2421
|
rows.push({
|
|
2338
2422
|
id: a.id,
|
|
2339
2423
|
statement: str3(a.Title),
|
|
@@ -2348,9 +2432,10 @@ function buildPipeline(assumptions, experiments) {
|
|
|
2348
2432
|
tested: stage.tested,
|
|
2349
2433
|
nextMove: nextMove(stage.stage, stage.killZone),
|
|
2350
2434
|
questionType,
|
|
2435
|
+
questionTypeCeiling,
|
|
2351
2436
|
stage: stageName,
|
|
2352
2437
|
riskThreshold,
|
|
2353
|
-
clearedThreshold: riskThreshold != null ? d.risk <= riskThreshold : null
|
|
2438
|
+
clearedThreshold: riskThreshold != null ? d.risk <= riskThreshold && (confFloor == null || stage.confidence >= confFloor) : null
|
|
2354
2439
|
});
|
|
2355
2440
|
}
|
|
2356
2441
|
rows.sort(
|
|
@@ -2842,7 +2927,8 @@ function PipelineBoard({
|
|
|
2842
2927
|
}
|
|
2843
2928
|
function PipelineRowView({ row, onOpen }) {
|
|
2844
2929
|
const stripeTone = row.riskTone;
|
|
2845
|
-
const
|
|
2930
|
+
const ceiling = row.questionTypeCeiling ?? 99;
|
|
2931
|
+
const knownPct = Math.max(0, Math.min(100, Math.abs(row.confidence) / ceiling * 100));
|
|
2846
2932
|
const knownSign = row.confSign;
|
|
2847
2933
|
return /* @__PURE__ */ jsxs5("div", { className: "vos-pipe-row vos-pipe-row-2seg", children: [
|
|
2848
2934
|
/* @__PURE__ */ jsx5("div", { className: `vos-pipe-stripe vos-fill-${stripeTone}` }),
|