@validation-os/dashboard 0.9.0 → 0.10.0

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
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/dashboard-app.tsx
4
- import { useCallback as useCallback5, useEffect as useEffect6, useState as useState13 } from "react";
4
+ import { useCallback as useCallback5, useEffect as useEffect6, useState as useState14 } from "react";
5
5
 
6
6
  // src/labels.ts
7
7
  var REGISTER_LABEL = {
@@ -49,7 +49,8 @@ var REGISTER_GROUPS = [
49
49
  ];
50
50
  var WORKFLOW_NAV = [
51
51
  { route: "next", label: "Next move", icon: "\u25C8", isDefault: true },
52
- { route: "pipeline", label: "Pipeline", icon: "\u25A6" }
52
+ { route: "stage-grid", label: "Lens \xD7 Stage", icon: "\u25A6" },
53
+ { route: "pipeline", label: "Pipeline", icon: "\u25A4" }
53
54
  ];
54
55
 
55
56
  // src/next-move.ts
@@ -5420,6 +5421,290 @@ function StageStepper({ move }) {
5420
5421
  )) });
5421
5422
  }
5422
5423
 
5424
+ // src/stage-grid-surface.tsx
5425
+ import { useMemo as useMemo6, useState as useState12 } from "react";
5426
+
5427
+ // src/stage-grid-model.ts
5428
+ var STAGE_ORDER = [
5429
+ "Discovery",
5430
+ "Validation",
5431
+ "Scale",
5432
+ "Maturity"
5433
+ ];
5434
+ var STAGE_GLOSS = {
5435
+ Discovery: "Problem-solution fit \u2014 will they engage, care, disclose?",
5436
+ Validation: "Product-market fit \u2014 will they pay, sign, stay?",
5437
+ Scale: "Growth \u2014 can we acquire efficiently, does CAC<LTV hold at volume?",
5438
+ Maturity: "Defense \u2014 will incumbents respond, will regulators accept?"
5439
+ };
5440
+ var NO_LENS = "\u2014";
5441
+ var NO_STAGE = "\u2014";
5442
+ function stageOf(record) {
5443
+ const v = str(record.Stage);
5444
+ if (!v) return null;
5445
+ return STAGE_ORDER.includes(v) ? v : null;
5446
+ }
5447
+ function rankByRisk(records) {
5448
+ return [...records].map((r) => ({ r, risk: derivedNum(r, "risk") ?? 0 })).sort(
5449
+ (a, b) => a.risk !== b.risk ? b.risk - a.risk : a.r.id.localeCompare(b.r.id)
5450
+ ).map((x) => x.r);
5451
+ }
5452
+ function buildStageGrid(assumptions) {
5453
+ const lensOrder = [];
5454
+ const seenLens = /* @__PURE__ */ new Set();
5455
+ const pushLens = (lens) => {
5456
+ if (!seenLens.has(lens)) {
5457
+ seenLens.add(lens);
5458
+ lensOrder.push(lens);
5459
+ }
5460
+ };
5461
+ const buckets = /* @__PURE__ */ new Map();
5462
+ const ensureLens = (lens) => {
5463
+ let m = buckets.get(lens);
5464
+ if (!m) {
5465
+ m = /* @__PURE__ */ new Map();
5466
+ buckets.set(lens, m);
5467
+ }
5468
+ return m;
5469
+ };
5470
+ let hasNoLens = false;
5471
+ let hasNoStage = false;
5472
+ for (const a of assumptions) {
5473
+ const lens = str(a.Lens) ?? NO_LENS;
5474
+ const stage = stageOf(a) ?? NO_STAGE;
5475
+ if (lens === NO_LENS) hasNoLens = true;
5476
+ if (stage === NO_STAGE) hasNoStage = true;
5477
+ pushLens(lens);
5478
+ const byStage = ensureLens(lens);
5479
+ let list = byStage.get(stage);
5480
+ if (!list) {
5481
+ list = [];
5482
+ byStage.set(stage, list);
5483
+ }
5484
+ list.push(a);
5485
+ }
5486
+ if (hasNoLens) {
5487
+ lensOrder.splice(lensOrder.indexOf(NO_LENS), 1);
5488
+ lensOrder.push(NO_LENS);
5489
+ } else {
5490
+ const idx = lensOrder.indexOf(NO_LENS);
5491
+ if (idx >= 0) lensOrder.splice(idx, 1);
5492
+ }
5493
+ const stageOrder = [...STAGE_ORDER];
5494
+ if (hasNoStage) stageOrder.push(NO_STAGE);
5495
+ const cells = [];
5496
+ let maxCellCount = 0;
5497
+ let total = 0;
5498
+ for (const lens of lensOrder) {
5499
+ const byStage = buckets.get(lens) ?? /* @__PURE__ */ new Map();
5500
+ for (const stage of stageOrder) {
5501
+ const records = byStage.get(stage) ?? [];
5502
+ const ranked = rankByRisk(records);
5503
+ const count = ranked.length;
5504
+ maxCellCount = Math.max(maxCellCount, count);
5505
+ total += count;
5506
+ cells.push({
5507
+ lens,
5508
+ stage,
5509
+ count,
5510
+ assumptions: ranked,
5511
+ // density filled in a second pass once maxCellCount is known.
5512
+ density: 0
5513
+ });
5514
+ }
5515
+ }
5516
+ const norm2 = maxCellCount > 0 ? 1 / maxCellCount : 0;
5517
+ for (const cell of cells) {
5518
+ cell.density = cell.count * norm2;
5519
+ }
5520
+ return {
5521
+ lenses: lensOrder,
5522
+ stages: [...STAGE_ORDER],
5523
+ cells,
5524
+ maxCellCount,
5525
+ total
5526
+ };
5527
+ }
5528
+ function cellAt(view, lens, stage) {
5529
+ return view.cells.find((c) => c.lens === lens && c.stage === stage) ?? null;
5530
+ }
5531
+
5532
+ // src/stage-grid-surface.tsx
5533
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
5534
+ function StageGridSurface({ basePath, onNavigate }) {
5535
+ const assumptions = useList("assumptions", basePath);
5536
+ const loading = assumptions.loading;
5537
+ const error = assumptions.error;
5538
+ const [open, setOpen] = useState12(null);
5539
+ const view = useMemo6(
5540
+ () => buildStageGrid(assumptions.records ?? []),
5541
+ [assumptions.records]
5542
+ );
5543
+ const refresh = () => assumptions.refresh();
5544
+ const openRecord = (id) => onNavigate({ name: "record", id });
5545
+ if (loading && !assumptions.records) {
5546
+ return /* @__PURE__ */ jsx18(StageGridFrame, { children: /* @__PURE__ */ jsx18("div", { className: "vos-empty", children: "Reading where your bets cluster\u2026" }) });
5547
+ }
5548
+ if (error) {
5549
+ return /* @__PURE__ */ jsx18(StageGridFrame, { children: /* @__PURE__ */ jsx18("div", { className: "vos-banner vos-banner-crit", children: /* @__PURE__ */ jsxs17("div", { className: "vos-banner-body", children: [
5550
+ /* @__PURE__ */ jsx18("b", { children: "Couldn't load the grid." }),
5551
+ /* @__PURE__ */ jsx18("span", { children: error })
5552
+ ] }) }) });
5553
+ }
5554
+ const cold = coldStartFor({
5555
+ assumptions: assumptions.records ?? [],
5556
+ experiments: [],
5557
+ readings: [],
5558
+ decisions: []
5559
+ });
5560
+ if (cold.cold) {
5561
+ return /* @__PURE__ */ jsxs17(StageGridFrame, { children: [
5562
+ /* @__PURE__ */ jsx18("div", { className: "vos-firstrun", children: FIRST_RUN_LINE }),
5563
+ /* @__PURE__ */ jsxs17("div", { className: "vos-card vos-cold vos-cold-stage-grid", children: [
5564
+ /* @__PURE__ */ jsx18("span", { className: "vos-cold-eyebrow", children: "No bets yet" }),
5565
+ /* @__PURE__ */ jsx18("p", { className: "vos-cold-body", children: "The Lens \xD7 Stage grid reads your business state off where your bets cluster. Write your first belief and the grid fills in \u2014 the densest cell per row is where that part of the business is." }),
5566
+ /* @__PURE__ */ jsx18(
5567
+ "button",
5568
+ {
5569
+ type: "button",
5570
+ className: "vos-btn",
5571
+ onClick: () => onNavigate({ name: "records", register: "assumptions" }),
5572
+ children: "Write your first bet"
5573
+ }
5574
+ )
5575
+ ] })
5576
+ ] });
5577
+ }
5578
+ return /* @__PURE__ */ jsxs17(StageGridFrame, { total: view.total, onRefresh: refresh, children: [
5579
+ /* @__PURE__ */ jsxs17("div", { className: "vos-card vos-stage-grid-card", children: [
5580
+ /* @__PURE__ */ jsx18("div", { className: "vos-stage-grid-scroll", children: /* @__PURE__ */ jsxs17("table", { className: "vos-stage-grid", role: "grid", "aria-label": "Lens \xD7 Stage heatmap", children: [
5581
+ /* @__PURE__ */ jsx18("thead", { children: /* @__PURE__ */ jsxs17("tr", { children: [
5582
+ /* @__PURE__ */ jsx18("th", { scope: "col", className: "vos-stage-grid-corner", children: "Lens \u2193 / Stage \u2192" }),
5583
+ view.stages.map((stage) => /* @__PURE__ */ jsxs17("th", { scope: "col", className: "vos-stage-grid-col", children: [
5584
+ /* @__PURE__ */ jsx18("span", { className: "vos-stage-grid-stagename", children: stage }),
5585
+ /* @__PURE__ */ jsx18("span", { className: "vos-stage-grid-stagegloss", children: STAGE_GLOSS[stage] })
5586
+ ] }, stage))
5587
+ ] }) }),
5588
+ /* @__PURE__ */ jsx18("tbody", { children: view.lenses.map((lens) => /* @__PURE__ */ jsxs17("tr", { children: [
5589
+ /* @__PURE__ */ jsx18("th", { scope: "row", className: "vos-stage-grid-rowhead", children: lens }),
5590
+ view.stages.map((stage) => {
5591
+ const cell = cellAt(view, lens, stage);
5592
+ return /* @__PURE__ */ jsx18(
5593
+ StageCell,
5594
+ {
5595
+ cell,
5596
+ onClick: () => setOpen(cell)
5597
+ },
5598
+ stage
5599
+ );
5600
+ })
5601
+ ] }, lens)) })
5602
+ ] }) }),
5603
+ /* @__PURE__ */ jsx18("p", { className: "vos-hint vos-stage-grid-foot", children: "The densest cell per row is where that part of the business is \u2014 no flag, no declaration, the density tells you. Click a cell to drill into its assumptions, ranked by Risk. Thin/empty cells are gaps: Consumer \xD7 Maturity is honestly 0 (consumers don't drive defense bets); a thin Commercial \xD7 Scale row is under-tracking scale." })
5604
+ ] }),
5605
+ /* @__PURE__ */ jsx18(
5606
+ CellDrawer,
5607
+ {
5608
+ cell: open,
5609
+ onClose: () => setOpen(null),
5610
+ onOpenRecord: openRecord
5611
+ }
5612
+ )
5613
+ ] });
5614
+ }
5615
+ function StageGridFrame({
5616
+ total,
5617
+ onRefresh,
5618
+ children
5619
+ }) {
5620
+ return /* @__PURE__ */ jsxs17("div", { children: [
5621
+ /* @__PURE__ */ jsxs17("div", { className: "vos-head", children: [
5622
+ /* @__PURE__ */ jsxs17("div", { children: [
5623
+ /* @__PURE__ */ jsx18("h1", { children: "Lens \xD7 Stage \u2014 where your bets cluster" }),
5624
+ /* @__PURE__ */ jsx18("p", { children: "Every belief cross-tabbed by the actor it's about (Lens) and the kind of response it tests (Stage). The grid is the filter; Risk is the rank." })
5625
+ ] }),
5626
+ /* @__PURE__ */ jsx18("div", { className: "vos-spacer" }),
5627
+ total !== void 0 ? /* @__PURE__ */ jsxs17("span", { className: "vos-hint vos-stage-grid-total", children: [
5628
+ total,
5629
+ " ",
5630
+ total === 1 ? "belief" : "beliefs"
5631
+ ] }) : null,
5632
+ onRefresh ? /* @__PURE__ */ jsx18(
5633
+ "button",
5634
+ {
5635
+ type: "button",
5636
+ className: "vos-btn vos-btn-ghost",
5637
+ onClick: onRefresh,
5638
+ children: "\u21BB Refresh"
5639
+ }
5640
+ ) : null
5641
+ ] }),
5642
+ /* @__PURE__ */ jsx18("div", { className: "vos-stage-grid-host", children })
5643
+ ] });
5644
+ }
5645
+ function StageCell({
5646
+ cell,
5647
+ onClick
5648
+ }) {
5649
+ const empty = cell.count === 0;
5650
+ const style = empty ? void 0 : {
5651
+ // Heatmap fill: opacity 0.08 → 0.92 across the density range, on the
5652
+ // accent token. Keeps the grid readable in both themes.
5653
+ "--vos-cell-alpha": (0.08 + cell.density * 0.84).toFixed(3)
5654
+ };
5655
+ return /* @__PURE__ */ jsx18(
5656
+ "td",
5657
+ {
5658
+ className: `vos-stage-grid-cell${empty ? " vos-stage-grid-cell-empty" : ""}`,
5659
+ style,
5660
+ children: /* @__PURE__ */ jsx18(
5661
+ "button",
5662
+ {
5663
+ type: "button",
5664
+ className: "vos-stage-grid-btn",
5665
+ onClick,
5666
+ "aria-label": `${cell.lens} \xD7 ${cell.stage}: ${cell.count} ${cell.count === 1 ? "belief" : "beliefs"}`,
5667
+ title: empty ? "No beliefs in this cell" : `Riskiest: ${cell.assumptions[0]?.Title ?? "\u2014"}`,
5668
+ children: /* @__PURE__ */ jsx18("span", { className: "vos-stage-grid-count vos-num", children: cell.count })
5669
+ }
5670
+ )
5671
+ }
5672
+ );
5673
+ }
5674
+ function CellDrawer({
5675
+ cell,
5676
+ onClose,
5677
+ onOpenRecord
5678
+ }) {
5679
+ return /* @__PURE__ */ jsxs17(
5680
+ DrawerShell,
5681
+ {
5682
+ open: cell !== null,
5683
+ onClose,
5684
+ ariaLabel: cell ? `${cell.lens} \xD7 ${cell.stage} \u2014 ${cell.count} ${cell.count === 1 ? "belief" : "beliefs"}` : "Cell drill-through",
5685
+ children: [
5686
+ /* @__PURE__ */ jsx18("header", { className: "vos-drawer-header", children: /* @__PURE__ */ jsxs17("div", { children: [
5687
+ /* @__PURE__ */ jsx18("p", { className: "vos-drawer-eyebrow", children: "Lens \xD7 Stage" }),
5688
+ /* @__PURE__ */ jsxs17("h2", { className: "vos-drawer-title", children: [
5689
+ cell?.lens,
5690
+ " \xD7 ",
5691
+ cell?.stage
5692
+ ] }),
5693
+ /* @__PURE__ */ jsx18("p", { className: "vos-hint", children: cell && cell.count > 0 ? `${cell.count} ${cell.count === 1 ? "belief" : "beliefs"}, ranked by Risk \u2014 riskiest first.` : "No beliefs in this cell." })
5694
+ ] }) }),
5695
+ cell && cell.count > 0 ? /* @__PURE__ */ jsx18("div", { className: "vos-stage-grid-drawer-body", children: /* @__PURE__ */ jsx18(
5696
+ RegisterTable,
5697
+ {
5698
+ register: "assumptions",
5699
+ records: cell.assumptions,
5700
+ onRowClick: onOpenRecord
5701
+ }
5702
+ ) }) : cell ? /* @__PURE__ */ jsx18("p", { className: "vos-empty", style: { margin: 16 }, children: "No beliefs in this cell \u2014 a gap, not a bug." }) : null
5703
+ ]
5704
+ }
5705
+ );
5706
+ }
5707
+
5423
5708
  // src/route.ts
5424
5709
  var DEFAULT_ROUTE = { name: "next" };
5425
5710
  function parseRoute(hash, registers) {
@@ -5429,6 +5714,7 @@ function parseRoute(hash, registers) {
5429
5714
  const head = parts[0] ?? "";
5430
5715
  if (head === "next") return { name: "next" };
5431
5716
  if (head === "pipeline") return { name: "pipeline" };
5717
+ if (head === "stage-grid") return { name: "stage-grid" };
5432
5718
  if (head === "record") {
5433
5719
  const id = parts.slice(1).join("/");
5434
5720
  return id ? { name: "record", id } : DEFAULT_ROUTE;
@@ -5450,7 +5736,7 @@ function formatRoute(route) {
5450
5736
  }
5451
5737
 
5452
5738
  // src/sidebar-nav.tsx
5453
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
5739
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
5454
5740
  function SidebarNav({
5455
5741
  route,
5456
5742
  onNavigate,
@@ -5459,12 +5745,12 @@ function SidebarNav({
5459
5745
  registers
5460
5746
  }) {
5461
5747
  const activeRegister = route.name === "records" ? route.register : null;
5462
- return /* @__PURE__ */ jsxs17("nav", { className: "vos-nav", "aria-label": "Navigation", children: [
5463
- /* @__PURE__ */ jsxs17("div", { children: [
5464
- /* @__PURE__ */ jsx18("div", { className: "vos-nav-group", children: "Workflow" }),
5748
+ return /* @__PURE__ */ jsxs18("nav", { className: "vos-nav", "aria-label": "Navigation", children: [
5749
+ /* @__PURE__ */ jsxs18("div", { children: [
5750
+ /* @__PURE__ */ jsx19("div", { className: "vos-nav-group", children: "Workflow" }),
5465
5751
  WORKFLOW_NAV.map((item) => {
5466
5752
  const active = route.name === item.route;
5467
- return /* @__PURE__ */ jsxs17(
5753
+ return /* @__PURE__ */ jsxs18(
5468
5754
  "button",
5469
5755
  {
5470
5756
  type: "button",
@@ -5472,20 +5758,20 @@ function SidebarNav({
5472
5758
  "aria-current": active ? "page" : void 0,
5473
5759
  onClick: () => onNavigate({ name: item.route }),
5474
5760
  children: [
5475
- /* @__PURE__ */ jsx18("span", { className: "vos-nav-ic", "aria-hidden": "true", children: item.icon }),
5761
+ /* @__PURE__ */ jsx19("span", { className: "vos-nav-ic", "aria-hidden": "true", children: item.icon }),
5476
5762
  item.label,
5477
- item.isDefault ? /* @__PURE__ */ jsx18("span", { className: "vos-nav-default", children: "home" }) : null
5763
+ item.isDefault ? /* @__PURE__ */ jsx19("span", { className: "vos-nav-default", children: "home" }) : null
5478
5764
  ]
5479
5765
  },
5480
5766
  item.route
5481
5767
  );
5482
5768
  })
5483
5769
  ] }),
5484
- /* @__PURE__ */ jsxs17("div", { children: [
5485
- /* @__PURE__ */ jsx18("div", { className: "vos-nav-group", children: "Records" }),
5770
+ /* @__PURE__ */ jsxs18("div", { children: [
5771
+ /* @__PURE__ */ jsx19("div", { className: "vos-nav-group", children: "Records" }),
5486
5772
  registers.map((register) => {
5487
5773
  const active = register === activeRegister;
5488
- return /* @__PURE__ */ jsxs17(
5774
+ return /* @__PURE__ */ jsxs18(
5489
5775
  "button",
5490
5776
  {
5491
5777
  type: "button",
@@ -5493,9 +5779,9 @@ function SidebarNav({
5493
5779
  "aria-current": active ? "page" : void 0,
5494
5780
  onClick: () => onNavigate({ name: "records", register }),
5495
5781
  children: [
5496
- /* @__PURE__ */ jsx18("span", { className: "vos-nav-ic", "aria-hidden": "true", children: REGISTER_ICON[register] }),
5782
+ /* @__PURE__ */ jsx19("span", { className: "vos-nav-ic", "aria-hidden": "true", children: REGISTER_ICON[register] }),
5497
5783
  REGISTER_LABEL[register],
5498
- needsHuman?.[register] ? /* @__PURE__ */ jsx18(
5784
+ needsHuman?.[register] ? /* @__PURE__ */ jsx19(
5499
5785
  "span",
5500
5786
  {
5501
5787
  className: "vos-nav-alert",
@@ -5503,7 +5789,7 @@ function SidebarNav({
5503
5789
  children: formatCount(needsHuman[register] ?? 0)
5504
5790
  }
5505
5791
  ) : null,
5506
- /* @__PURE__ */ jsx18("span", { className: "vos-nav-count vos-num", children: counts?.[register] !== void 0 ? formatCount(counts[register] ?? 0) : "\xB7" })
5792
+ /* @__PURE__ */ jsx19("span", { className: "vos-nav-count vos-num", children: counts?.[register] !== void 0 ? formatCount(counts[register] ?? 0) : "\xB7" })
5507
5793
  ]
5508
5794
  },
5509
5795
  register
@@ -5514,12 +5800,12 @@ function SidebarNav({
5514
5800
  }
5515
5801
 
5516
5802
  // src/use-counts.ts
5517
- import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo6, useState as useState12 } from "react";
5803
+ import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo7, useState as useState13 } from "react";
5518
5804
  function useCounts(basePath = "/api") {
5519
- const [counts, setCounts] = useState12(null);
5520
- const [loading, setLoading] = useState12(true);
5521
- const [error, setError] = useState12(null);
5522
- const [tick, setTick] = useState12(0);
5805
+ const [counts, setCounts] = useState13(null);
5806
+ const [loading, setLoading] = useState13(true);
5807
+ const [error, setError] = useState13(null);
5808
+ const [tick, setTick] = useState13(0);
5523
5809
  useEffect5(() => {
5524
5810
  let live = true;
5525
5811
  setLoading(true);
@@ -5547,8 +5833,8 @@ function useNeedsHuman(basePath = "/api") {
5547
5833
  const assumptions = useList("assumptions", basePath);
5548
5834
  const experiments = useList("experiments", basePath);
5549
5835
  const decisions = useList("decisions", basePath);
5550
- const [asOf] = useState12(() => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
5551
- return useMemo6(() => {
5836
+ const [asOf] = useState13(() => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
5837
+ return useMemo7(() => {
5552
5838
  const counts = needsHumanCounts({
5553
5839
  asOf,
5554
5840
  assumptions: assumptions.records ?? [],
@@ -5564,7 +5850,7 @@ function useNeedsHuman(basePath = "/api") {
5564
5850
  }
5565
5851
 
5566
5852
  // src/dashboard-app.tsx
5567
- import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
5853
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
5568
5854
  function initialsOf(name) {
5569
5855
  const parts = name.trim().split(/\s+/);
5570
5856
  const first = parts[0]?.[0] ?? "";
@@ -5580,7 +5866,7 @@ function ValidationOSDashboard({ config = {} }) {
5580
5866
  user,
5581
5867
  registers = REGISTER_ORDER
5582
5868
  } = config;
5583
- const [route, setRoute] = useState13(
5869
+ const [route, setRoute] = useState14(
5584
5870
  () => typeof window === "undefined" ? { name: "next" } : parseRoute(window.location.hash, registers)
5585
5871
  );
5586
5872
  const { counts } = useCounts(basePath);
@@ -5606,33 +5892,33 @@ function ValidationOSDashboard({ config = {} }) {
5606
5892
  }, []);
5607
5893
  const brandName = branding?.name ?? "Validation-OS";
5608
5894
  const brandMark = branding?.initials ?? "V";
5609
- return /* @__PURE__ */ jsxs18("div", { className: "vos-app", children: [
5610
- /* @__PURE__ */ jsxs18("div", { className: "vos-brand", children: [
5611
- /* @__PURE__ */ jsx19("span", { className: "vos-brand-dot", children: branding?.logoUrl ? /* @__PURE__ */ jsx19("img", { src: branding.logoUrl, alt: "" }) : brandMark }),
5895
+ return /* @__PURE__ */ jsxs19("div", { className: "vos-app", children: [
5896
+ /* @__PURE__ */ jsxs19("div", { className: "vos-brand", children: [
5897
+ /* @__PURE__ */ jsx20("span", { className: "vos-brand-dot", children: branding?.logoUrl ? /* @__PURE__ */ jsx20("img", { src: branding.logoUrl, alt: "" }) : brandMark }),
5612
5898
  " ",
5613
5899
  brandName
5614
5900
  ] }),
5615
- /* @__PURE__ */ jsxs18("div", { className: "vos-topbar", children: [
5616
- backendLabel ? /* @__PURE__ */ jsxs18("div", { className: "vos-backend", children: [
5617
- /* @__PURE__ */ jsx19("span", { className: "vos-live-dot" }),
5901
+ /* @__PURE__ */ jsxs19("div", { className: "vos-topbar", children: [
5902
+ backendLabel ? /* @__PURE__ */ jsxs19("div", { className: "vos-backend", children: [
5903
+ /* @__PURE__ */ jsx20("span", { className: "vos-live-dot" }),
5618
5904
  " Backend: ",
5619
- /* @__PURE__ */ jsx19("b", { children: backendLabel })
5905
+ /* @__PURE__ */ jsx20("b", { children: backendLabel })
5620
5906
  ] }) : null,
5621
- agentLabel ? /* @__PURE__ */ jsxs18("span", { className: "vos-hint", children: [
5907
+ agentLabel ? /* @__PURE__ */ jsxs19("span", { className: "vos-hint", children: [
5622
5908
  "Agent: ",
5623
- /* @__PURE__ */ jsx19("b", { style: { color: "var(--vos-text)" }, children: agentLabel })
5909
+ /* @__PURE__ */ jsx20("b", { style: { color: "var(--vos-text)" }, children: agentLabel })
5624
5910
  ] }) : null,
5625
- /* @__PURE__ */ jsx19("div", { className: "vos-spacer" }),
5626
- /* @__PURE__ */ jsx19("button", { type: "button", className: "vos-iconbtn", onClick: toggleTheme, children: "\u25D0 Theme" }),
5627
- user?.name ? /* @__PURE__ */ jsxs18("div", { className: "vos-user", children: [
5628
- /* @__PURE__ */ jsx19("span", { className: "vos-avatar", children: initialsOf(user.name) }),
5629
- /* @__PURE__ */ jsxs18("div", { children: [
5630
- /* @__PURE__ */ jsx19("span", { className: "vos-user-name", children: user.name }),
5631
- user.caption ? /* @__PURE__ */ jsx19("small", { children: user.caption }) : null
5911
+ /* @__PURE__ */ jsx20("div", { className: "vos-spacer" }),
5912
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "vos-iconbtn", onClick: toggleTheme, children: "\u25D0 Theme" }),
5913
+ user?.name ? /* @__PURE__ */ jsxs19("div", { className: "vos-user", children: [
5914
+ /* @__PURE__ */ jsx20("span", { className: "vos-avatar", children: initialsOf(user.name) }),
5915
+ /* @__PURE__ */ jsxs19("div", { children: [
5916
+ /* @__PURE__ */ jsx20("span", { className: "vos-user-name", children: user.name }),
5917
+ user.caption ? /* @__PURE__ */ jsx20("small", { children: user.caption }) : null
5632
5918
  ] })
5633
5919
  ] }) : null
5634
5920
  ] }),
5635
- /* @__PURE__ */ jsx19(
5921
+ /* @__PURE__ */ jsx20(
5636
5922
  SidebarNav,
5637
5923
  {
5638
5924
  route,
@@ -5642,7 +5928,7 @@ function ValidationOSDashboard({ config = {} }) {
5642
5928
  registers
5643
5929
  }
5644
5930
  ),
5645
- /* @__PURE__ */ jsx19("main", { className: "vos-main", children: route.name === "records" ? /* @__PURE__ */ jsx19(
5931
+ /* @__PURE__ */ jsx20("main", { className: "vos-main", children: route.name === "records" ? /* @__PURE__ */ jsx20(
5646
5932
  RegisterBrowser,
5647
5933
  {
5648
5934
  register: route.register,
@@ -5651,7 +5937,7 @@ function ValidationOSDashboard({ config = {} }) {
5651
5937
  onOpenRecord: (id) => navigate({ name: "record", id })
5652
5938
  },
5653
5939
  route.register
5654
- ) : route.name === "record" ? /* @__PURE__ */ jsx19(
5940
+ ) : route.name === "record" ? /* @__PURE__ */ jsx20(
5655
5941
  RecordPage,
5656
5942
  {
5657
5943
  recordId: route.id,
@@ -5660,7 +5946,7 @@ function ValidationOSDashboard({ config = {} }) {
5660
5946
  basePath
5661
5947
  },
5662
5948
  route.id
5663
- ) : route.name === "pipeline" ? /* @__PURE__ */ jsx19(PipelineSurface, { basePath, onNavigate: navigate }, "pipeline") : /* @__PURE__ */ jsx19(NextMoveSurface, { basePath, onNavigate: navigate }, "next") })
5949
+ ) : route.name === "pipeline" ? /* @__PURE__ */ jsx20(PipelineSurface, { basePath, onNavigate: navigate }, "pipeline") : route.name === "stage-grid" ? /* @__PURE__ */ jsx20(StageGridSurface, { basePath, onNavigate: navigate }, "stage-grid") : /* @__PURE__ */ jsx20(NextMoveSurface, { basePath, onNavigate: navigate }, "next") })
5664
5950
  ] });
5665
5951
  }
5666
5952
 
@@ -5690,15 +5976,15 @@ function composeConnectCommand(input) {
5690
5976
  }
5691
5977
 
5692
5978
  // src/connect-claude-code.tsx
5693
- import { useState as useState14 } from "react";
5694
- import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
5979
+ import { useState as useState15 } from "react";
5980
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
5695
5981
  function ConnectClaudeCode({
5696
5982
  apiBaseUrl,
5697
5983
  tokenEnv,
5698
5984
  mintToken
5699
5985
  }) {
5700
- const [state, setState] = useState14({ phase: "idle" });
5701
- const [copied, setCopied] = useState14(false);
5986
+ const [state, setState] = useState15({ phase: "idle" });
5987
+ const [copied, setCopied] = useState15(false);
5702
5988
  async function generate() {
5703
5989
  setState({ phase: "minting" });
5704
5990
  setCopied(false);
@@ -5720,21 +6006,21 @@ function ConnectClaudeCode({
5720
6006
  } catch {
5721
6007
  }
5722
6008
  }
5723
- return /* @__PURE__ */ jsxs19("div", { children: [
5724
- /* @__PURE__ */ jsx20("div", { className: "vos-head", children: /* @__PURE__ */ jsxs19("div", { children: [
5725
- /* @__PURE__ */ jsx20("h1", { children: "Connect Claude Code" }),
5726
- /* @__PURE__ */ jsx20("p", { children: "Run the validation skills against this register from your own Claude Code \u2014 no repo, no keys to hunt down." })
6009
+ return /* @__PURE__ */ jsxs20("div", { children: [
6010
+ /* @__PURE__ */ jsx21("div", { className: "vos-head", children: /* @__PURE__ */ jsxs20("div", { children: [
6011
+ /* @__PURE__ */ jsx21("h1", { children: "Connect Claude Code" }),
6012
+ /* @__PURE__ */ jsx21("p", { children: "Run the validation skills against this register from your own Claude Code \u2014 no repo, no keys to hunt down." })
5727
6013
  ] }) }),
5728
- /* @__PURE__ */ jsxs19("ol", { className: "vos-hint", style: { lineHeight: 1.8 }, children: [
5729
- /* @__PURE__ */ jsx20("li", { children: "Generate your personal connection command below." }),
5730
- /* @__PURE__ */ jsx20("li", { children: "Paste it into a terminal in the workspace you'll run the skills in." }),
5731
- /* @__PURE__ */ jsxs19("li", { children: [
6014
+ /* @__PURE__ */ jsxs20("ol", { className: "vos-hint", style: { lineHeight: 1.8 }, children: [
6015
+ /* @__PURE__ */ jsx21("li", { children: "Generate your personal connection command below." }),
6016
+ /* @__PURE__ */ jsx21("li", { children: "Paste it into a terminal in the workspace you'll run the skills in." }),
6017
+ /* @__PURE__ */ jsxs20("li", { children: [
5732
6018
  "The command carries a token tied to ",
5733
- /* @__PURE__ */ jsx20("strong", { children: "you" }),
6019
+ /* @__PURE__ */ jsx21("strong", { children: "you" }),
5734
6020
  " \u2014 anything you write lands under your name. Don't share it."
5735
6021
  ] })
5736
6022
  ] }),
5737
- state.phase !== "ready" ? /* @__PURE__ */ jsx20(
6023
+ state.phase !== "ready" ? /* @__PURE__ */ jsx21(
5738
6024
  "button",
5739
6025
  {
5740
6026
  type: "button",
@@ -5744,11 +6030,11 @@ function ConnectClaudeCode({
5744
6030
  children: state.phase === "minting" ? "Generating\u2026" : "Generate connection command"
5745
6031
  }
5746
6032
  ) : null,
5747
- state.phase === "error" ? /* @__PURE__ */ jsx20("p", { className: "vos-hint", role: "alert", children: state.message }) : null,
5748
- state.phase === "ready" ? /* @__PURE__ */ jsxs19("div", { children: [
5749
- /* @__PURE__ */ jsx20("pre", { className: "vos-code", "aria-label": "Connection command", children: state.command }),
5750
- /* @__PURE__ */ jsxs19("div", { style: { display: "flex", gap: 8 }, children: [
5751
- /* @__PURE__ */ jsx20(
6033
+ state.phase === "error" ? /* @__PURE__ */ jsx21("p", { className: "vos-hint", role: "alert", children: state.message }) : null,
6034
+ state.phase === "ready" ? /* @__PURE__ */ jsxs20("div", { children: [
6035
+ /* @__PURE__ */ jsx21("pre", { className: "vos-code", "aria-label": "Connection command", children: state.command }),
6036
+ /* @__PURE__ */ jsxs20("div", { style: { display: "flex", gap: 8 }, children: [
6037
+ /* @__PURE__ */ jsx21(
5752
6038
  "button",
5753
6039
  {
5754
6040
  type: "button",
@@ -5757,31 +6043,31 @@ function ConnectClaudeCode({
5757
6043
  children: copied ? "Copied" : "Copy command"
5758
6044
  }
5759
6045
  ),
5760
- /* @__PURE__ */ jsx20("button", { type: "button", className: "vos-btn-ghost", onClick: generate, children: "Regenerate" })
6046
+ /* @__PURE__ */ jsx21("button", { type: "button", className: "vos-btn-ghost", onClick: generate, children: "Regenerate" })
5761
6047
  ] }),
5762
- /* @__PURE__ */ jsx20("p", { className: "vos-hint", style: { marginTop: 12 }, children: "Generating again revokes nothing on its own \u2014 remove old keys from your account settings when you rotate." })
6048
+ /* @__PURE__ */ jsx21("p", { className: "vos-hint", style: { marginTop: 12 }, children: "Generating again revokes nothing on its own \u2014 remove old keys from your account settings when you rotate." })
5763
6049
  ] }) : null
5764
6050
  ] });
5765
6051
  }
5766
6052
 
5767
6053
  // src/surface-placeholder.tsx
5768
- import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
6054
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
5769
6055
  function SurfacePlaceholder({
5770
6056
  title,
5771
6057
  subtitle,
5772
6058
  detail
5773
6059
  }) {
5774
- return /* @__PURE__ */ jsxs20("div", { children: [
5775
- /* @__PURE__ */ jsx21("div", { className: "vos-head", children: /* @__PURE__ */ jsxs20("div", { children: [
5776
- /* @__PURE__ */ jsx21("h1", { children: title }),
5777
- /* @__PURE__ */ jsx21("p", { children: subtitle })
6060
+ return /* @__PURE__ */ jsxs21("div", { children: [
6061
+ /* @__PURE__ */ jsx22("div", { className: "vos-head", children: /* @__PURE__ */ jsxs21("div", { children: [
6062
+ /* @__PURE__ */ jsx22("h1", { children: title }),
6063
+ /* @__PURE__ */ jsx22("p", { children: subtitle })
5778
6064
  ] }) }),
5779
- /* @__PURE__ */ jsx21("div", { className: "vos-empty", children: detail })
6065
+ /* @__PURE__ */ jsx22("div", { className: "vos-empty", children: detail })
5780
6066
  ] });
5781
6067
  }
5782
6068
 
5783
6069
  // src/register-counts.tsx
5784
- import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
6070
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
5785
6071
  function RegisterCounts({
5786
6072
  counts,
5787
6073
  caption,
@@ -5791,8 +6077,8 @@ function RegisterCounts({
5791
6077
  const registers = REGISTER_ORDER.filter(
5792
6078
  (r) => counts[r] !== void 0
5793
6079
  );
5794
- return /* @__PURE__ */ jsxs21("section", { "aria-label": "Register counts", children: [
5795
- /* @__PURE__ */ jsx22("div", { className: "vos-tile-grid", children: registers.map((register) => /* @__PURE__ */ jsx22(
6080
+ return /* @__PURE__ */ jsxs22("section", { "aria-label": "Register counts", children: [
6081
+ /* @__PURE__ */ jsx23("div", { className: "vos-tile-grid", children: registers.map((register) => /* @__PURE__ */ jsx23(
5796
6082
  StatTile,
5797
6083
  {
5798
6084
  label: REGISTER_LABEL[register],
@@ -5802,7 +6088,7 @@ function RegisterCounts({
5802
6088
  },
5803
6089
  register
5804
6090
  )) }),
5805
- caption ? /* @__PURE__ */ jsx22("p", { className: "vos-hint", style: { marginTop: 16 }, children: caption }) : null
6091
+ caption ? /* @__PURE__ */ jsx23("p", { className: "vos-hint", style: { marginTop: 16 }, children: caption }) : null
5806
6092
  ] });
5807
6093
  }
5808
6094
  export {
@@ -5819,6 +6105,8 @@ export {
5819
6105
  FieldInput,
5820
6106
  GlossaryText,
5821
6107
  Markdown,
6108
+ NO_LENS,
6109
+ NO_STAGE,
5822
6110
  NextMoveSurface,
5823
6111
  PipelineSurface,
5824
6112
  REGISTER_GROUPS,
@@ -5837,9 +6125,12 @@ export {
5837
6125
  RegisterTable,
5838
6126
  RelationEditor,
5839
6127
  RiskBar,
6128
+ STAGE_GLOSS,
6129
+ STAGE_ORDER,
5840
6130
  ScoreImpactForm,
5841
6131
  SidebarNav,
5842
6132
  Sparkline,
6133
+ StageGridSurface,
5843
6134
  StatTile,
5844
6135
  StatusPill,
5845
6136
  SurfacePlaceholder,
@@ -5853,7 +6144,9 @@ export {
5853
6144
  buildPatch,
5854
6145
  buildPipeline,
5855
6146
  buildRecordPage,
6147
+ buildStageGrid,
5856
6148
  buildUnderstanding,
6149
+ cellAt,
5857
6150
  cellValue,
5858
6151
  coldStartFor,
5859
6152
  columnsFor,
@@ -5891,6 +6184,7 @@ export {
5891
6184
  ownerNames,
5892
6185
  parseRoute,
5893
6186
  primaryLabel,
6187
+ rankByRisk,
5894
6188
  readingAssumptionChips,
5895
6189
  readingBeliefVerdicts,
5896
6190
  resolveBarLines,
@@ -5902,6 +6196,7 @@ export {
5902
6196
  sortRecords,
5903
6197
  sparklinePath,
5904
6198
  stageMeters,
6199
+ stageOf,
5905
6200
  statusTone,
5906
6201
  tabsFor,
5907
6202
  toCreatePayload,