@validation-os/dashboard 0.7.1 → 0.9.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
@@ -56,7 +56,55 @@ var WORKFLOW_NAV = [
56
56
  import {
57
57
  isConcluded
58
58
  } from "@validation-os/core/derivation";
59
- function str(record, key) {
59
+
60
+ // src/derived-views.ts
61
+ var KILL_ZONE = -50;
62
+ function readingBeliefs(r) {
63
+ return Array.isArray(r.beliefs) ? r.beliefs : [];
64
+ }
65
+ function readingBeliefFor(r, assumptionId) {
66
+ return readingBeliefs(r).find((b) => b.assumptionId === assumptionId);
67
+ }
68
+ function readingGrades(r, assumptionId) {
69
+ return readingBeliefFor(r, assumptionId) !== void 0;
70
+ }
71
+ function isArchivedExperiment(e) {
72
+ return str(e.Status) === "Archived";
73
+ }
74
+ function liveExperiments(experiments) {
75
+ return experiments.filter((e) => !isArchivedExperiment(e));
76
+ }
77
+ function str(v) {
78
+ return typeof v === "string" && v !== "" ? v : null;
79
+ }
80
+ function derivedNum(r, key) {
81
+ const v = r.derived?.[key];
82
+ return typeof v === "number" ? v : null;
83
+ }
84
+ function strList(v) {
85
+ return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
86
+ }
87
+ function testsAssumption(exp, assumptionId) {
88
+ const bars = exp.barLines;
89
+ if (bars?.some((b) => b.assumptionId === assumptionId)) return true;
90
+ return strList(exp.barLineAssumptionIds).includes(assumptionId);
91
+ }
92
+ function hasOpenBarOn(exp, assumptionId) {
93
+ const bars = exp.barLines;
94
+ return bars?.some((b) => b.assumptionId === assumptionId && b.barVerdict == null) ?? false;
95
+ }
96
+ function inKillLane(a) {
97
+ return str(a.Status) === "Live" && (derivedNum(a, "confidence") ?? 0) <= KILL_ZONE;
98
+ }
99
+ function isTesting(a, experiments) {
100
+ if (str(a.Status) !== "Live") return false;
101
+ return experiments.some(
102
+ (e) => str(e.Status) === "Running" && hasOpenBarOn(e, a.id)
103
+ );
104
+ }
105
+
106
+ // src/next-move.ts
107
+ function str2(record, key) {
60
108
  const v = record[key];
61
109
  return typeof v === "string" ? v : null;
62
110
  }
@@ -71,13 +119,11 @@ function idList(record, key) {
71
119
  function toNextMoveInput(records) {
72
120
  const concludedByAssumption = /* @__PURE__ */ new Map();
73
121
  for (const r of records.readings) {
74
- const assumptionId = str(r, "assumptionId");
75
- if (!assumptionId) continue;
76
- const result = str(r, "Result");
77
- if (result && isConcluded(result)) {
122
+ for (const b of readingBeliefs(r)) {
123
+ if (!b.assumptionId || !isConcluded(b.Result)) continue;
78
124
  concludedByAssumption.set(
79
- assumptionId,
80
- (concludedByAssumption.get(assumptionId) ?? 0) + 1
125
+ b.assumptionId,
126
+ (concludedByAssumption.get(b.assumptionId) ?? 0) + 1
81
127
  );
82
128
  }
83
129
  }
@@ -86,8 +132,8 @@ function toNextMoveInput(records) {
86
132
  const derived = a.derived && typeof a.derived === "object" ? a.derived : {};
87
133
  return {
88
134
  id: a.id,
89
- title: str(a, "Title") ?? a.id,
90
- status: str(a, "Status") ?? "",
135
+ title: str2(a, "Title") ?? a.id,
136
+ status: str2(a, "Status") ?? "",
91
137
  impact: numOrNull(a, "Impact"),
92
138
  moot: a.moot === true,
93
139
  risk: typeof derived.risk === "number" ? derived.risk : 0,
@@ -96,12 +142,12 @@ function toNextMoveInput(records) {
96
142
  };
97
143
  }),
98
144
  experiments: records.experiments.map((e) => ({
99
- status: str(e, "Status") ?? "",
100
- feasibility: str(e, "Feasibility") ?? null,
145
+ status: str2(e, "Status") ?? "",
146
+ feasibility: str2(e, "Feasibility") ?? null,
101
147
  assumptionIds: idList(e, "barLineAssumptionIds")
102
148
  })),
103
149
  decisions: records.decisions.map((d) => ({
104
- status: str(d, "Status") ?? "",
150
+ status: str2(d, "Status") ?? "",
105
151
  assumptionIds: [...idList(d, "basedOnIds"), ...idList(d, "resolvesIds")]
106
152
  }))
107
153
  };
@@ -292,7 +338,7 @@ function sparklineY(value, height, lo, hi) {
292
338
  // src/pipeline.ts
293
339
  import {
294
340
  assumptionCompleteness,
295
- toReadingInput
341
+ readingBeliefInputs
296
342
  } from "@validation-os/core";
297
343
  import {
298
344
  beliefRisk,
@@ -306,7 +352,7 @@ function num(v) {
306
352
  const n = Number(v);
307
353
  return Number.isFinite(n) ? n : 0;
308
354
  }
309
- function str2(v) {
355
+ function str3(v) {
310
356
  return typeof v === "string" ? v : "";
311
357
  }
312
358
  function derivedOf(rec) {
@@ -346,7 +392,9 @@ function nextMove(stage, killZone) {
346
392
  }
347
393
  }
348
394
  function buildPipeline(assumptions, experiments) {
349
- const tests = beliefTestMeters(experiments.map(toStageExperimentInput));
395
+ const tests = beliefTestMeters(
396
+ liveExperiments(experiments).map(toStageExperimentInput)
397
+ );
350
398
  const rows = [];
351
399
  const resolved = [];
352
400
  const portfolioInput = [];
@@ -367,7 +415,7 @@ function buildPipeline(assumptions, experiments) {
367
415
  resolvedRetired += retired;
368
416
  resolved.push({
369
417
  id: a.id,
370
- statement: str2(a.Title),
418
+ statement: str3(a.Title),
371
419
  kind,
372
420
  retired
373
421
  });
@@ -382,7 +430,7 @@ function buildPipeline(assumptions, experiments) {
382
430
  const stage = deriveBeliefStage({ framed, confidence: d.confidence, test });
383
431
  rows.push({
384
432
  id: a.id,
385
- statement: str2(a.Title),
433
+ statement: str3(a.Title),
386
434
  impact: d.derivedImpact,
387
435
  risk: d.risk,
388
436
  riskTone: riskLevel(d.risk),
@@ -407,28 +455,27 @@ function buildPipeline(assumptions, experiments) {
407
455
  }
408
456
  function weekOverWeekDelta(assumptions, readings, now) {
409
457
  const anyDated = readings.some((r) => {
410
- const t2 = Date.parse(str2(r.Date));
458
+ const t2 = Date.parse(str3(r.Date));
411
459
  return !Number.isNaN(t2);
412
460
  });
413
461
  if (!anyDated) return null;
414
462
  const cutoff = now.getTime() - 7 * 24 * 60 * 60 * 1e3;
415
463
  const byAssumption = /* @__PURE__ */ new Map();
416
- for (const r of readings) {
417
- const id = str2(r.assumptionId);
418
- if (!id) continue;
419
- const arr = byAssumption.get(id);
420
- if (arr) arr.push(r);
421
- else byAssumption.set(id, [r]);
464
+ for (const input of readings.flatMap(readingBeliefInputs)) {
465
+ if (!input.assumptionId) continue;
466
+ const arr = byAssumption.get(input.assumptionId);
467
+ if (arr) arr.push(input);
468
+ else byAssumption.set(input.assumptionId, [input]);
422
469
  }
423
470
  const percentAsOf = (limit) => {
424
471
  const inputs = assumptions.map((a) => {
425
472
  const d = derivedOf(a);
426
- const mine = (byAssumption.get(a.id) ?? []).filter((r) => {
473
+ const mine = (byAssumption.get(a.id) ?? []).filter((i) => {
427
474
  if (limit === null) return true;
428
- const t2 = Date.parse(str2(r.Date));
475
+ const t2 = Date.parse(i.date ?? "");
429
476
  return !Number.isNaN(t2) && t2 <= limit;
430
477
  });
431
- const conf = confidence(mine.map(toReadingInput));
478
+ const conf = confidence(mine);
432
479
  return {
433
480
  id: a.id,
434
481
  derivedImpact: d.derivedImpact,
@@ -506,29 +553,24 @@ var area = (key, label) => ({
506
553
  label,
507
554
  kind: "textarea"
508
555
  });
509
- var num2 = (key, label) => ({
556
+ var num2 = (key, label, range = {}) => ({
510
557
  key,
511
558
  label,
512
559
  kind: "number",
513
- nullable: true
560
+ nullable: true,
561
+ ...range
514
562
  });
515
563
  var sel = (key, label, options, nullable = false) => ({ key, label, kind: "select", options, nullable });
516
- var READING_RUNGS = [
517
- "Opinion",
518
- "Pitch-deck reaction",
519
- "Anecdotal",
520
- "Desk research",
521
- "Survey at scale",
522
- "Prototype usage",
523
- "Signed intent",
524
- "Paying users"
525
- ];
526
564
  var SOURCE_QUALITY = ["1", "0.7", "0.5"];
527
565
  var EDITORS = {
528
566
  assumptions: [
529
567
  t("Title", "Assumption"),
530
568
  area("Description", "Description"),
531
- num2("Impact", "Impact"),
569
+ // The only hand-scored number in the registry (`registry-schema.md`) — a
570
+ // 0–100 severity-if-false seed. Every other number (Confidence, Derived
571
+ // Impact, Risk, Strength, Source quality, Completeness %) is computed on
572
+ // write and deliberately absent from this list.
573
+ num2("Impact", "Impact", { min: 0, max: 100 }),
532
574
  sel("Status", "Status", ["Draft", "Live", "Invalidated"]),
533
575
  t("Lens", "Lens"),
534
576
  area("Scoring justification", "Scoring justification")
@@ -557,12 +599,14 @@ var EDITORS = {
557
599
  readings: [
558
600
  t("Title", "Reading"),
559
601
  t("Source", "Source"),
560
- sel("Rung", "Rung", READING_RUNGS),
561
- sel("Result", "Result", ["Validated", "Invalidated", "Inconclusive"]),
602
+ // Rung / Result / Magnitude band / Grading justification are PER BELIEF now
603
+ // (OPS-1305) they live in each entry of `beliefs[]`, not on the row, so
604
+ // they are deliberately absent here rather than writing dead row-level
605
+ // fields. Editing a reading's per-belief scores is a deferred follow-up (a
606
+ // `beliefs[]` editor); this form edits only the row-level fields that remain.
562
607
  sel("Representativeness", "Representativeness", SOURCE_QUALITY),
563
608
  sel("Credibility", "Credibility", SOURCE_QUALITY),
564
- sel("magnitudeBand", "Magnitude band", ["Low", "Typical", "High"], true),
565
- area("Grading justification", "Grading justification"),
609
+ area("body", "Quote"),
566
610
  t("Date", "Date")
567
611
  ],
568
612
  decisions: [
@@ -601,6 +645,28 @@ function coerce(field, raw) {
601
645
  function norm(value) {
602
646
  return value === void 0 || value === "" ? null : value;
603
647
  }
648
+ function fieldError(field, raw) {
649
+ if (field.kind !== "number") return null;
650
+ const str5 = String(raw ?? "").trim();
651
+ if (str5 === "") return null;
652
+ const n = Number(str5);
653
+ if (Number.isNaN(n)) return `${field.label} must be a number.`;
654
+ if (field.min !== void 0 && n < field.min) {
655
+ return `${field.label} must be at least ${field.min}.`;
656
+ }
657
+ if (field.max !== void 0 && n > field.max) {
658
+ return `${field.label} must be at most ${field.max}.`;
659
+ }
660
+ return null;
661
+ }
662
+ function draftErrors(register, draft) {
663
+ const errors = {};
664
+ for (const field of editableFields(register)) {
665
+ const message = fieldError(field, draft[field.key] ?? "");
666
+ if (message) errors[field.key] = message;
667
+ }
668
+ return errors;
669
+ }
604
670
  function buildPatch(register, original, draft) {
605
671
  const patch = { version: original.version };
606
672
  for (const field of editableFields(register)) {
@@ -1035,14 +1101,16 @@ var COLUMNS = {
1035
1101
  ],
1036
1102
  readings: [
1037
1103
  { key: "Title", header: "Reading" },
1038
- { key: "Result", header: "Result" },
1039
- { key: "Rung", header: "Rung" },
1104
+ { key: "Source", header: "Source" },
1105
+ { key: "Date", header: "Date" },
1106
+ // The row's per-belief Result / Rung / Strength are gone (OPS-1305) — they
1107
+ // live in the reading detail's per-belief verdict list. The table instead
1108
+ // previews the quote (`body`) so a row is legible at a glance; assumption
1109
+ // chips (see `readingAssumptionChips`) disambiguate same-titled readings.
1040
1110
  {
1041
- key: "strength",
1042
- header: "Strength",
1043
- align: "right",
1044
- derived: true,
1045
- accessor: derivedField("strength")
1111
+ key: "body",
1112
+ header: "Quote",
1113
+ accessor: (r) => bodyPreview(r.body)
1046
1114
  }
1047
1115
  ],
1048
1116
  decisions: [
@@ -1057,6 +1125,16 @@ var COLUMNS = {
1057
1125
  function columnsFor(register) {
1058
1126
  return COLUMNS[register];
1059
1127
  }
1128
+ function bodyPreview(value, max = 80) {
1129
+ if (typeof value !== "string") return "";
1130
+ const oneLine = value.replace(/\s+/g, " ").trim();
1131
+ if (oneLine.length <= max) return oneLine;
1132
+ return `${oneLine.slice(0, max - 1).trimEnd()}\u2026`;
1133
+ }
1134
+ function readingAssumptionChips(record, titleById = /* @__PURE__ */ new Map()) {
1135
+ const ids = Array.isArray(record.assumptionIds) ? record.assumptionIds.filter((x) => typeof x === "string") : [];
1136
+ return ids.map((id) => titleById.get(id) ?? id);
1137
+ }
1060
1138
  function cellValue(column, record) {
1061
1139
  return column.accessor ? column.accessor(record) : record[column.key];
1062
1140
  }
@@ -1093,7 +1171,9 @@ var FIELD_LABEL = {
1093
1171
  contradictsIds: "Contradicts",
1094
1172
  readingIds: "Readings",
1095
1173
  assumptionId: "Assumption",
1096
- experimentId: "Experiment",
1174
+ assumptionIds: "Beliefs",
1175
+ experimentId: "Evidence plan",
1176
+ body: "Quote",
1097
1177
  contextLinks: "Context links",
1098
1178
  basedOnIds: "Based on",
1099
1179
  resolvesIds: "Resolves",
@@ -1113,6 +1193,169 @@ function derivedLabel(key) {
1113
1193
  return DERIVED_LABEL[key] ?? fieldLabel(key);
1114
1194
  }
1115
1195
 
1196
+ // src/detail-fields.ts
1197
+ var META_FIELDS = /* @__PURE__ */ new Set([
1198
+ "id",
1199
+ "version",
1200
+ "createdAt",
1201
+ "updatedAt",
1202
+ "derived"
1203
+ ]);
1204
+ var SUPPRESSED_FIELDS = /* @__PURE__ */ new Set([
1205
+ "barLineAssumptionIds",
1206
+ // A reading's `beliefs[]` is rendered as the richer per-belief verdict list
1207
+ // (OPS-1305), never as raw JSON in the generic row list.
1208
+ "beliefs",
1209
+ // `body` (a reading's quote / an experiment's narrative) renders as Markdown
1210
+ // in its own block, not as a raw-text row.
1211
+ "body"
1212
+ ]);
1213
+ var RELATION_TARGET = {
1214
+ dependsOnIds: "assumptions",
1215
+ enablesIds: "assumptions",
1216
+ contradictsIds: "assumptions",
1217
+ readingIds: "readings",
1218
+ assumptionId: "assumptions",
1219
+ assumptionIds: "assumptions",
1220
+ experimentId: "experiments",
1221
+ basedOnIds: "assumptions",
1222
+ resolvesIds: "assumptions"
1223
+ };
1224
+ var OWNER_FIELDS = /* @__PURE__ */ new Set(["Owner", "Agreed by"]);
1225
+ function relatedList(related, register) {
1226
+ return related[register] ?? [];
1227
+ }
1228
+ function resolveItem(related, register, id) {
1229
+ const hit = relatedList(related, register).find((r) => r.id === id);
1230
+ return { id, register, title: hit ? primaryLabel(hit) : id };
1231
+ }
1232
+ function idsOf(value) {
1233
+ if (Array.isArray(value)) {
1234
+ return value.filter((v) => typeof v === "string");
1235
+ }
1236
+ return typeof value === "string" && value ? [value] : [];
1237
+ }
1238
+ function ownerNames(value) {
1239
+ if (!Array.isArray(value)) return [];
1240
+ return value.map((v) => {
1241
+ if (v && typeof v === "object") {
1242
+ const name = v.name;
1243
+ if (typeof name === "string" && name) return name;
1244
+ const id = v.id;
1245
+ return typeof id === "string" ? id : "\u2014";
1246
+ }
1247
+ return typeof v === "string" ? v : "\u2014";
1248
+ });
1249
+ }
1250
+ function resolveBarLines(bars, related) {
1251
+ return bars.map((b) => ({
1252
+ rightIf: b.rightIf ?? "",
1253
+ wrongIf: b.wrongIf ?? null,
1254
+ plannedRung: b.plannedRung ?? "",
1255
+ barVerdict: b.barVerdict ?? null,
1256
+ assumption: b.assumptionId ? resolveItem(related, "assumptions", b.assumptionId) : null
1257
+ }));
1258
+ }
1259
+ function detailRows(register, record, related = {}) {
1260
+ const keys = Object.keys(record).filter(
1261
+ (k) => !META_FIELDS.has(k) && !SUPPRESSED_FIELDS.has(k)
1262
+ );
1263
+ return keys.map((key) => {
1264
+ const value = record[key];
1265
+ const label = fieldLabel(key);
1266
+ const target = RELATION_TARGET[key];
1267
+ if (target) {
1268
+ let items = idsOf(value).map((id) => resolveItem(related, target, id));
1269
+ if (target === "experiments") {
1270
+ const archived = new Set(
1271
+ (related.experiments ?? []).filter((e) => isArchivedExperiment(e)).map((e) => e.id)
1272
+ );
1273
+ items = items.filter((it) => !archived.has(it.id));
1274
+ }
1275
+ return { key, label, kind: "relation", items };
1276
+ }
1277
+ if (OWNER_FIELDS.has(key)) {
1278
+ return { key, label, kind: "owner", names: ownerNames(value) };
1279
+ }
1280
+ if (key === "barLines" && Array.isArray(value)) {
1281
+ return {
1282
+ key,
1283
+ label,
1284
+ kind: "bar-lines",
1285
+ bars: resolveBarLines(value, related)
1286
+ };
1287
+ }
1288
+ return { key, label, kind: "text", text: formatValue(value) };
1289
+ });
1290
+ }
1291
+
1292
+ // src/edit-fields.tsx
1293
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1294
+ function EditFields({
1295
+ register,
1296
+ draft,
1297
+ errors,
1298
+ onField
1299
+ }) {
1300
+ return /* @__PURE__ */ jsx2("div", { className: "vos-field-stack", children: editableFields(register).map((field) => /* @__PURE__ */ jsx2(
1301
+ FieldInput,
1302
+ {
1303
+ field,
1304
+ value: draft[field.key],
1305
+ error: errors?.[field.key],
1306
+ onChange: (v) => onField(field.key, v)
1307
+ },
1308
+ field.key
1309
+ )) });
1310
+ }
1311
+ function FieldInput({
1312
+ field,
1313
+ value,
1314
+ error,
1315
+ onChange
1316
+ }) {
1317
+ const id = `field-${field.key.replace(/\s+/g, "-")}`;
1318
+ return /* @__PURE__ */ jsxs2("div", { className: "vos-field", children: [
1319
+ /* @__PURE__ */ jsx2("label", { htmlFor: id, children: field.label }),
1320
+ field.kind === "textarea" ? /* @__PURE__ */ jsx2(
1321
+ "textarea",
1322
+ {
1323
+ id,
1324
+ value: String(value ?? ""),
1325
+ onChange: (e) => onChange(e.target.value),
1326
+ rows: 3,
1327
+ className: "vos-input",
1328
+ "aria-invalid": error ? true : void 0
1329
+ }
1330
+ ) : field.kind === "select" ? /* @__PURE__ */ jsxs2(
1331
+ "select",
1332
+ {
1333
+ id,
1334
+ value: String(value ?? ""),
1335
+ onChange: (e) => onChange(e.target.value),
1336
+ className: "vos-input",
1337
+ children: [
1338
+ field.nullable ? /* @__PURE__ */ jsx2("option", { value: "", children: "\u2014" }) : null,
1339
+ field.options?.map((opt) => /* @__PURE__ */ jsx2("option", { value: opt, children: opt }, opt))
1340
+ ]
1341
+ }
1342
+ ) : /* @__PURE__ */ jsx2(
1343
+ "input",
1344
+ {
1345
+ id,
1346
+ type: field.kind === "number" ? "number" : "text",
1347
+ min: field.kind === "number" ? field.min : void 0,
1348
+ max: field.kind === "number" ? field.max : void 0,
1349
+ value: String(value ?? ""),
1350
+ onChange: (e) => onChange(e.target.value),
1351
+ className: "vos-input",
1352
+ "aria-invalid": error ? true : void 0
1353
+ }
1354
+ ),
1355
+ error ? /* @__PURE__ */ jsx2("p", { role: "alert", className: "vos-field-error", children: error }) : null
1356
+ ] });
1357
+ }
1358
+
1116
1359
  // src/glossary-text.tsx
1117
1360
  import { Fragment as Fragment2 } from "react";
1118
1361
 
@@ -1193,7 +1436,7 @@ function toGlossaryTerms(records) {
1193
1436
  }
1194
1437
 
1195
1438
  // src/glossary-text.tsx
1196
- import { Fragment as Fragment3, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1439
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1197
1440
  var PILL_CLASS = {
1198
1441
  good: "vos-pill vos-pill-good",
1199
1442
  warn: "vos-pill vos-pill-warn",
@@ -1208,8 +1451,8 @@ function GlossaryText({
1208
1451
  onOpenTerm
1209
1452
  }) {
1210
1453
  const nodes = linkify(text, terms, { selfId });
1211
- return /* @__PURE__ */ jsx2(Fragment3, { children: nodes.map(
1212
- (node, i) => node.kind === "text" ? /* @__PURE__ */ jsx2(Fragment2, { children: node.text }, i) : /* @__PURE__ */ jsx2(
1454
+ return /* @__PURE__ */ jsx3(Fragment3, { children: nodes.map(
1455
+ (node, i) => node.kind === "text" ? /* @__PURE__ */ jsx3(Fragment2, { children: node.text }, i) : /* @__PURE__ */ jsx3(
1213
1456
  TermLink,
1214
1457
  {
1215
1458
  text: node.text,
@@ -1225,8 +1468,8 @@ function TermLink({
1225
1468
  term,
1226
1469
  onOpenTerm
1227
1470
  }) {
1228
- return /* @__PURE__ */ jsxs2("span", { className: "vos-gloss", children: [
1229
- /* @__PURE__ */ jsx2(
1471
+ return /* @__PURE__ */ jsxs3("span", { className: "vos-gloss", children: [
1472
+ /* @__PURE__ */ jsx3(
1230
1473
  "button",
1231
1474
  {
1232
1475
  type: "button",
@@ -1235,15 +1478,15 @@ function TermLink({
1235
1478
  children: text
1236
1479
  }
1237
1480
  ),
1238
- /* @__PURE__ */ jsxs2("span", { className: "vos-gloss-pop", role: "tooltip", children: [
1239
- /* @__PURE__ */ jsxs2("span", { className: "vos-gloss-pop-head", children: [
1240
- /* @__PURE__ */ jsx2("b", { children: term.title }),
1241
- /* @__PURE__ */ jsx2("span", { className: PILL_CLASS[statusTone(term.status)], children: term.status })
1481
+ /* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop", role: "tooltip", children: [
1482
+ /* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop-head", children: [
1483
+ /* @__PURE__ */ jsx3("b", { children: term.title }),
1484
+ /* @__PURE__ */ jsx3("span", { className: PILL_CLASS[statusTone(term.status)], children: term.status })
1242
1485
  ] }),
1243
- /* @__PURE__ */ jsx2("span", { className: "vos-gloss-pop-def", children: term.definition || "\u2014" }),
1244
- term.dontConfuseWith.length ? /* @__PURE__ */ jsxs2("span", { className: "vos-gloss-pop-neighbours", children: [
1245
- /* @__PURE__ */ jsx2("span", { className: "vos-gloss-pop-label", children: "Don't confuse with" }),
1246
- term.dontConfuseWith.map((n) => /* @__PURE__ */ jsx2(
1486
+ /* @__PURE__ */ jsx3("span", { className: "vos-gloss-pop-def", children: term.definition || "\u2014" }),
1487
+ term.dontConfuseWith.length ? /* @__PURE__ */ jsxs3("span", { className: "vos-gloss-pop-neighbours", children: [
1488
+ /* @__PURE__ */ jsx3("span", { className: "vos-gloss-pop-label", children: "Don't confuse with" }),
1489
+ term.dontConfuseWith.map((n) => /* @__PURE__ */ jsx3(
1247
1490
  "button",
1248
1491
  {
1249
1492
  type: "button",
@@ -1261,7 +1504,7 @@ function TermLink({
1261
1504
  // src/journey.ts
1262
1505
  import {
1263
1506
  assumptionCompleteness as assumptionCompleteness2,
1264
- toReadingInput as toReadingInput2
1507
+ readingBeliefInputs as readingBeliefInputs3
1265
1508
  } from "@validation-os/core";
1266
1509
  import {
1267
1510
  assembleJourney,
@@ -1271,35 +1514,103 @@ import {
1271
1514
  rankNextMoves
1272
1515
  } from "@validation-os/core/derivation";
1273
1516
 
1274
- // src/derived-views.ts
1275
- var KILL_ZONE = -50;
1276
- function str3(v) {
1277
- return typeof v === "string" && v !== "" ? v : null;
1278
- }
1279
- function derivedNum(r, key) {
1280
- const v = r.derived?.[key];
1281
- return typeof v === "number" ? v : null;
1282
- }
1283
- function strList(v) {
1284
- return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
1285
- }
1286
- function testsAssumption(exp, assumptionId) {
1287
- const bars = exp.barLines;
1288
- if (bars?.some((b) => b.assumptionId === assumptionId)) return true;
1289
- return strList(exp.barLineAssumptionIds).includes(assumptionId);
1517
+ // src/cycles.ts
1518
+ import {
1519
+ readingBeliefInputs as readingBeliefInputs2
1520
+ } from "@validation-os/core";
1521
+ import { confidenceAttribution } from "@validation-os/core/derivation";
1522
+ var DIRECT_CYCLE_KEY = "direct";
1523
+ function readingDate(r) {
1524
+ return str(r.Date);
1290
1525
  }
1291
- function hasOpenBarOn(exp, assumptionId) {
1292
- const bars = exp.barLines;
1293
- return bars?.some((b) => b.assumptionId === assumptionId && b.barVerdict == null) ?? false;
1526
+ function toCycleReading(r, assumptionId) {
1527
+ return {
1528
+ id: r.id,
1529
+ date: readingDate(r),
1530
+ result: readingBeliefFor(r, assumptionId)?.Result ?? null
1531
+ };
1294
1532
  }
1295
- function inKillLane(a) {
1296
- return str3(a.Status) === "Live" && (derivedNum(a, "confidence") ?? 0) <= KILL_ZONE;
1533
+ function sortByDate(readings) {
1534
+ return [...readings].sort((a, b) => {
1535
+ if (a.date === b.date) return 0;
1536
+ if (a.date === null) return 1;
1537
+ if (b.date === null) return -1;
1538
+ return a.date < b.date ? -1 : 1;
1539
+ });
1297
1540
  }
1298
- function isTesting(a, experiments) {
1299
- if (str3(a.Status) !== "Live") return false;
1300
- return experiments.some(
1301
- (e) => str3(e.Status) === "Running" && hasOpenBarOn(e, a.id)
1302
- );
1541
+ function barVerdictFor(exp, assumptionId) {
1542
+ const bars = exp.barLines ?? [];
1543
+ const line = bars.find((b) => b.assumptionId === assumptionId);
1544
+ return line?.barVerdict ?? null;
1545
+ }
1546
+ function buildCycles(assumptionId, readings, experiments) {
1547
+ const mine = readings.filter((r) => readingGrades(r, assumptionId));
1548
+ const inputs = readings.flatMap(readingBeliefInputs2).filter((i) => i.assumptionId === assumptionId);
1549
+ const { movers } = confidenceAttribution(inputs);
1550
+ const moverByKey = new Map(movers.map((m) => [m.key, m]));
1551
+ const byExperiment = /* @__PURE__ */ new Map();
1552
+ const direct = [];
1553
+ for (const r of mine) {
1554
+ const expId = str(r.experimentId);
1555
+ if (expId) {
1556
+ const bucket = byExperiment.get(expId) ?? [];
1557
+ bucket.push(r);
1558
+ byExperiment.set(expId, bucket);
1559
+ } else {
1560
+ direct.push(r);
1561
+ }
1562
+ }
1563
+ const experimentsById = new Map(experiments.map((e) => [e.id, e]));
1564
+ const experimentIds = /* @__PURE__ */ new Set([
1565
+ ...liveExperiments(experiments).filter((e) => testsAssumption(e, assumptionId)).map((e) => e.id),
1566
+ ...[...byExperiment.keys()].filter((id) => {
1567
+ const e = experimentsById.get(id);
1568
+ return !e || !isArchivedExperiment(e);
1569
+ })
1570
+ ]);
1571
+ const cycles = [...experimentIds].map((id) => {
1572
+ const exp = experimentsById.get(id);
1573
+ const readingViews = sortByDate(
1574
+ (byExperiment.get(id) ?? []).map((r) => toCycleReading(r, assumptionId))
1575
+ );
1576
+ const mover = moverByKey.get(id);
1577
+ const date = (exp ? str(exp.Date) : null) ?? readingViews[0]?.date ?? null;
1578
+ return {
1579
+ key: id,
1580
+ kind: "experiment",
1581
+ title: exp ? str(exp.Title) : null,
1582
+ status: exp ? str(exp.Status) : null,
1583
+ date,
1584
+ barVerdict: exp ? barVerdictFor(exp, assumptionId) : null,
1585
+ readings: readingViews,
1586
+ contribution: mover?.contribution ?? 0,
1587
+ magnitude: mover?.magnitude ?? 0
1588
+ };
1589
+ });
1590
+ if (direct.length > 0) {
1591
+ const readingViews = sortByDate(
1592
+ direct.map((r) => toCycleReading(r, assumptionId))
1593
+ );
1594
+ const mover = moverByKey.get(DIRECT_CYCLE_KEY);
1595
+ cycles.push({
1596
+ key: DIRECT_CYCLE_KEY,
1597
+ kind: "direct",
1598
+ title: null,
1599
+ status: null,
1600
+ date: readingViews[0]?.date ?? null,
1601
+ barVerdict: null,
1602
+ readings: readingViews,
1603
+ contribution: mover?.contribution ?? 0,
1604
+ magnitude: mover?.magnitude ?? 0
1605
+ });
1606
+ }
1607
+ cycles.sort((a, b) => {
1608
+ if (a.date === b.date) return a.key.localeCompare(b.key);
1609
+ if (a.date === null) return 1;
1610
+ if (b.date === null) return -1;
1611
+ return a.date < b.date ? -1 : 1;
1612
+ });
1613
+ return cycles;
1303
1614
  }
1304
1615
 
1305
1616
  // src/journey.ts
@@ -1354,32 +1665,31 @@ function buildJourney(assumptionId, records, now) {
1354
1665
  if (!belief2) return null;
1355
1666
  const derived = belief2.derived && typeof belief2.derived === "object" ? belief2.derived : {};
1356
1667
  const confidence2 = typeof derived.confidence === "number" ? derived.confidence : 0;
1357
- const test = beliefTestMeters2(records.experiments.map(toStageExperimentInput)).get(
1358
- assumptionId
1359
- ) ?? emptyTestMeter();
1668
+ const live = liveExperiments(records.experiments);
1669
+ const test = beliefTestMeters2(live.map(toStageExperimentInput)).get(assumptionId) ?? emptyTestMeter();
1360
1670
  const framed = assumptionCompleteness2(belief2);
1361
1671
  const stage = deriveBeliefStage2({ framed, confidence: confidence2, test });
1362
- const myReadings = records.readings.filter(
1363
- (r) => r.assumptionId === assumptionId
1364
- );
1365
- const myExperiments = records.experiments.filter((e) => testsAssumption(e, assumptionId)).map((e) => ({ id: e.id, date: str4(e.Date) || str4(e.createdAt) || null }));
1672
+ const myReadingInputs = records.readings.flatMap(readingBeliefInputs3).filter((i) => i.assumptionId === assumptionId);
1673
+ const myExperiments = live.filter((e) => testsAssumption(e, assumptionId)).map((e) => ({ id: e.id, date: str4(e.Date) || str4(e.createdAt) || null }));
1366
1674
  const events = assembleJourney({
1367
1675
  belief: {
1368
1676
  createdAt: str4(belief2.createdAt) || null,
1369
1677
  impactScored: belief2.Impact != null
1370
1678
  },
1371
- readings: myReadings.map(toReadingInput2),
1679
+ readings: myReadingInputs,
1372
1680
  experiments: myExperiments,
1373
1681
  now
1374
1682
  }).map((event) => ({ ...event, label: labelFor(event) }));
1375
1683
  const nextMove2 = rankNextMoves(toNextMoveInput(records)).find(
1376
1684
  (m) => m.assumptionId === assumptionId
1377
1685
  ) ?? null;
1686
+ const cycles = buildCycles(assumptionId, records.readings, records.experiments);
1378
1687
  return {
1379
1688
  id: assumptionId,
1380
1689
  statement: str4(belief2.Title),
1381
1690
  stage,
1382
1691
  events,
1692
+ cycles,
1383
1693
  nextMove: nextMove2,
1384
1694
  resolved: resolvedKind(belief2)
1385
1695
  };
@@ -1393,7 +1703,7 @@ import { useState as useState3 } from "react";
1393
1703
 
1394
1704
  // src/drawer-shell.tsx
1395
1705
  import { useEffect as useEffect2, useRef } from "react";
1396
- import { Fragment as Fragment4, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1706
+ import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1397
1707
  function DrawerShell({
1398
1708
  open,
1399
1709
  onClose,
@@ -1411,8 +1721,8 @@ function DrawerShell({
1411
1721
  return () => document.removeEventListener("keydown", onKey);
1412
1722
  }, [open, onClose]);
1413
1723
  if (!open) return null;
1414
- return /* @__PURE__ */ jsxs3(Fragment4, { children: [
1415
- /* @__PURE__ */ jsx3(
1724
+ return /* @__PURE__ */ jsxs4(Fragment4, { children: [
1725
+ /* @__PURE__ */ jsx4(
1416
1726
  "button",
1417
1727
  {
1418
1728
  type: "button",
@@ -1421,7 +1731,7 @@ function DrawerShell({
1421
1731
  className: "vos-scrim"
1422
1732
  }
1423
1733
  ),
1424
- /* @__PURE__ */ jsx3(
1734
+ /* @__PURE__ */ jsx4(
1425
1735
  "aside",
1426
1736
  {
1427
1737
  ref: panelRef,
@@ -1436,65 +1746,6 @@ function DrawerShell({
1436
1746
  ] });
1437
1747
  }
1438
1748
 
1439
- // src/edit-fields.tsx
1440
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1441
- function EditFields({
1442
- register,
1443
- draft,
1444
- onField
1445
- }) {
1446
- return /* @__PURE__ */ jsx4("div", { className: "vos-field-stack", children: editableFields(register).map((field) => /* @__PURE__ */ jsx4(
1447
- FieldInput,
1448
- {
1449
- field,
1450
- value: draft[field.key],
1451
- onChange: (v) => onField(field.key, v)
1452
- },
1453
- field.key
1454
- )) });
1455
- }
1456
- function FieldInput({
1457
- field,
1458
- value,
1459
- onChange
1460
- }) {
1461
- const id = `field-${field.key.replace(/\s+/g, "-")}`;
1462
- return /* @__PURE__ */ jsxs4("div", { className: "vos-field", children: [
1463
- /* @__PURE__ */ jsx4("label", { htmlFor: id, children: field.label }),
1464
- field.kind === "textarea" ? /* @__PURE__ */ jsx4(
1465
- "textarea",
1466
- {
1467
- id,
1468
- value: String(value ?? ""),
1469
- onChange: (e) => onChange(e.target.value),
1470
- rows: 3,
1471
- className: "vos-input"
1472
- }
1473
- ) : field.kind === "select" ? /* @__PURE__ */ jsxs4(
1474
- "select",
1475
- {
1476
- id,
1477
- value: String(value ?? ""),
1478
- onChange: (e) => onChange(e.target.value),
1479
- className: "vos-input",
1480
- children: [
1481
- field.nullable ? /* @__PURE__ */ jsx4("option", { value: "", children: "\u2014" }) : null,
1482
- field.options?.map((opt) => /* @__PURE__ */ jsx4("option", { value: opt, children: opt }, opt))
1483
- ]
1484
- }
1485
- ) : /* @__PURE__ */ jsx4(
1486
- "input",
1487
- {
1488
- id,
1489
- type: field.kind === "number" ? "number" : "text",
1490
- value: String(value ?? ""),
1491
- onChange: (e) => onChange(e.target.value),
1492
- className: "vos-input"
1493
- }
1494
- )
1495
- ] });
1496
- }
1497
-
1498
1749
  // src/field-styles.ts
1499
1750
  var FIELD_LABEL_CLASS = "vos-field-label";
1500
1751
  var FIELD_CONTROL_CLASS = "vos-input";
@@ -2012,35 +2263,37 @@ function StatTile({
2012
2263
 
2013
2264
  // src/understanding.ts
2014
2265
  import {
2015
- toReadingInput as toReadingInput3
2266
+ readingBeliefInputs as readingBeliefInputs4
2016
2267
  } from "@validation-os/core";
2017
2268
  import {
2018
- confidenceAttribution,
2269
+ confidenceAttribution as confidenceAttribution2,
2019
2270
  confidenceTrajectory,
2020
2271
  experimentProgress,
2021
2272
  isConcluded as isConcluded2
2022
2273
  } from "@validation-os/core/derivation";
2023
2274
  function buildUnderstanding(assumption, readings, experiments) {
2024
- const mine = readings.filter((r) => r.assumptionId === assumption.id);
2025
- const inputs = mine.map(toReadingInput3);
2026
- const { confidence: confidence2, movers } = confidenceAttribution(inputs);
2275
+ const inputs = readings.flatMap(readingBeliefInputs4).filter((i) => i.assumptionId === assumption.id);
2276
+ const { confidence: confidence2, movers } = confidenceAttribution2(inputs);
2027
2277
  const experimentsById = new Map(experiments.map((e) => [e.id, e]));
2028
2278
  const moverByExperiment = new Map(
2029
2279
  movers.filter((m) => m.kind === "experiment").map((m) => [m.experimentId, m])
2030
2280
  );
2031
2281
  const experimentIds = /* @__PURE__ */ new Set([
2032
- ...experiments.filter((e) => testsAssumption(e, assumption.id)).map((e) => e.id),
2033
- ...moverByExperiment.keys()
2282
+ ...liveExperiments(experiments).filter((e) => testsAssumption(e, assumption.id)).map((e) => e.id),
2283
+ ...[...moverByExperiment.keys()].filter((id) => {
2284
+ const e = experimentsById.get(id);
2285
+ return !e || !isArchivedExperiment(e);
2286
+ })
2034
2287
  ]);
2035
2288
  const experimentViews = [...experimentIds].map((id) => {
2036
2289
  const exp = experimentsById.get(id);
2037
2290
  const mover = moverByExperiment.get(id);
2038
2291
  const bars = exp?.barLines ?? [];
2039
2292
  const progress = bars.length ? experimentProgress(bars) : null;
2040
- const status = exp ? str3(exp.Status) : null;
2293
+ const status = exp ? str(exp.Status) : null;
2041
2294
  return {
2042
2295
  experimentId: id,
2043
- title: exp ? str3(exp.Title) : null,
2296
+ title: exp ? str(exp.Title) : null,
2044
2297
  status,
2045
2298
  contribution: mover?.contribution ?? 0,
2046
2299
  magnitude: mover?.magnitude ?? 0,
@@ -2268,6 +2521,10 @@ function BeliefJourney({
2268
2521
  `${event.kind}-${event.refId ?? i}`
2269
2522
  )) })
2270
2523
  ] }),
2524
+ journey.cycles.length > 0 ? /* @__PURE__ */ jsxs8("section", { children: [
2525
+ /* @__PURE__ */ jsx8("div", { className: "vos-why-section-title", children: "Round by round" }),
2526
+ /* @__PURE__ */ jsx8(CycleTimeline, { cycles: journey.cycles })
2527
+ ] }) : null,
2271
2528
  /* @__PURE__ */ jsxs8("section", { children: [
2272
2529
  /* @__PURE__ */ jsx8("div", { className: "vos-why-section-title", children: "What moved the number" }),
2273
2530
  /* @__PURE__ */ jsx8(UnderstandingPanel, { assumption, basePath })
@@ -2413,6 +2670,62 @@ function EventRow({
2413
2670
  ) : null
2414
2671
  ] });
2415
2672
  }
2673
+ function readingDotTone(result) {
2674
+ if (result === "Validated") return "good";
2675
+ if (result === "Invalidated") return "crit";
2676
+ return "neutral";
2677
+ }
2678
+ var BAR_VERDICT_PILL = {
2679
+ Validated: "vos-pill vos-pill-good",
2680
+ Invalidated: "vos-pill vos-pill-crit",
2681
+ Inconclusive: "vos-pill vos-pill-neutral"
2682
+ };
2683
+ function CycleTimeline({ cycles }) {
2684
+ const maxMagnitude = Math.max(...cycles.map((c) => c.magnitude), 0.01);
2685
+ return /* @__PURE__ */ jsx8("ol", { className: "vos-cyc-list", children: cycles.map((cycle, i) => /* @__PURE__ */ jsx8(CycleCard, { cycle, n: i + 1, max: maxMagnitude }, cycle.key)) });
2686
+ }
2687
+ function CycleCard({
2688
+ cycle,
2689
+ n,
2690
+ max
2691
+ }) {
2692
+ const up = cycle.contribution >= 0;
2693
+ const moving = cycle.magnitude > 0;
2694
+ const width = Math.round(cycle.magnitude / max * 50);
2695
+ const fill = up ? { left: "50%", width: `${width}%`, background: "var(--vos-good)" } : { right: "50%", width: `${width}%`, background: "var(--vos-crit)" };
2696
+ return /* @__PURE__ */ jsxs8("li", { className: "vos-cyc-card", children: [
2697
+ /* @__PURE__ */ jsxs8("div", { className: "vos-cyc-head", children: [
2698
+ /* @__PURE__ */ jsxs8("span", { className: "vos-cyc-num", children: [
2699
+ "Round ",
2700
+ n
2701
+ ] }),
2702
+ cycle.date ? /* @__PURE__ */ jsx8("span", { className: "vos-cyc-date", children: cycle.date }) : null
2703
+ ] }),
2704
+ /* @__PURE__ */ jsx8("div", { className: "vos-cyc-title", children: cycle.kind === "direct" ? "Direct evidence" : cycle.title ?? "Untitled experiment" }),
2705
+ cycle.readings.length > 0 ? /* @__PURE__ */ jsx8(
2706
+ "div",
2707
+ {
2708
+ className: "vos-cyc-dots",
2709
+ role: "img",
2710
+ "aria-label": `${cycle.readings.length} reading${cycle.readings.length === 1 ? "" : "s"}`,
2711
+ children: cycle.readings.map((r) => /* @__PURE__ */ jsx8(
2712
+ "span",
2713
+ {
2714
+ className: `vos-jny-dot ${DOT_CLASS[readingDotTone(r.result)]}`
2715
+ },
2716
+ r.id
2717
+ ))
2718
+ }
2719
+ ) : /* @__PURE__ */ jsx8("span", { className: "vos-hint", children: "No readings yet" }),
2720
+ /* @__PURE__ */ jsxs8("div", { className: "vos-cyc-foot", children: [
2721
+ cycle.barVerdict ? /* @__PURE__ */ jsx8("span", { className: BAR_VERDICT_PILL[cycle.barVerdict], children: cycle.barVerdict }) : cycle.kind === "experiment" ? /* @__PURE__ */ jsx8("span", { className: "vos-hint", children: cycle.status === "Closed" ? "No bar line" : "Bar pending" }) : null,
2722
+ moving ? /* @__PURE__ */ jsxs8("span", { className: "vos-cyc-push", children: [
2723
+ /* @__PURE__ */ jsx8("span", { className: "vos-track vos-signed vos-cyc-track", children: /* @__PURE__ */ jsx8("i", { style: fill }) }),
2724
+ /* @__PURE__ */ jsx8("span", { className: up ? "vos-text-good" : "vos-text-crit", children: formatSigned(cycle.contribution) })
2725
+ ] }) : null
2726
+ ] })
2727
+ ] });
2728
+ }
2416
2729
  function NextMoveCard({
2417
2730
  move,
2418
2731
  resolved,
@@ -2457,42 +2770,43 @@ function JourneyColdCard({
2457
2770
  }
2458
2771
 
2459
2772
  // src/list-surface.ts
2773
+ function hasConcludedBelief(r) {
2774
+ return readingBeliefs(r).some((b) => b.Result !== "Inconclusive");
2775
+ }
2460
2776
  function isProven(a, ctx) {
2461
- if (str3(a.Status) !== "Live") return false;
2462
- const mine = (ctx.readings ?? []).filter(
2463
- (r) => r.assumptionId === a.id && str3(r.Result) !== "Inconclusive"
2464
- );
2465
- if (mine.length === 0) return false;
2466
- const strongest = mine.reduce(
2467
- (best, r) => Math.abs(derivedNum(r, "strength") ?? 0) > Math.abs(derivedNum(best, "strength") ?? 0) ? r : best
2777
+ if (str(a.Status) !== "Live") return false;
2778
+ const scores = (ctx.readings ?? []).map((r) => readingBeliefFor(r, a.id)).filter((b) => b != null && b.Result !== "Inconclusive");
2779
+ if (scores.length === 0) return false;
2780
+ const strongest = scores.reduce(
2781
+ (best, b) => Math.abs(b.derived?.strength ?? 0) > Math.abs(best.derived?.strength ?? 0) ? b : best
2468
2782
  );
2469
- return str3(strongest.Result) === "Validated";
2783
+ return strongest.Result === "Validated";
2470
2784
  }
2471
2785
  function isOverdue(e, ctx) {
2472
- const deadline = str3(e.Deadline);
2473
- if (!ctx.asOf || !deadline || str3(e.Status) !== "Running") return false;
2786
+ const deadline = str(e.Deadline);
2787
+ if (!ctx.asOf || !deadline || str(e.Status) !== "Running") return false;
2474
2788
  return deadline < ctx.asOf;
2475
2789
  }
2476
2790
  function inTension(d, ctx) {
2477
- if (str3(d.Status) !== "Active") return false;
2791
+ if (str(d.Status) !== "Active") return false;
2478
2792
  const based = strList(d.basedOnIds);
2479
2793
  if (based.length === 0) return false;
2480
2794
  const byId = new Map((ctx.assumptions ?? []).map((a) => [a.id, a]));
2481
2795
  return based.some((id) => {
2482
2796
  const a = byId.get(id);
2483
2797
  if (!a) return false;
2484
- return str3(a.Status) === "Invalidated" || inKillLane(a);
2798
+ return str(a.Status) === "Invalidated" || inKillLane(a);
2485
2799
  });
2486
2800
  }
2487
2801
  var ALWAYS = () => true;
2488
- var byStatus = (...values) => (r) => values.includes(str3(r.Status) ?? "");
2802
+ var byStatus = (...values) => (r) => values.includes(str(r.Status) ?? "");
2489
2803
  var TAB_CATALOGUE = {
2490
2804
  assumptions: [
2491
2805
  {
2492
2806
  id: "live",
2493
2807
  label: "Live",
2494
2808
  isDefault: true,
2495
- predicate: (r) => str3(r.Status) === "Live" && r.moot !== true,
2809
+ predicate: (r) => str(r.Status) === "Live" && r.moot !== true,
2496
2810
  defaultSort: { key: "risk", dir: "desc" }
2497
2811
  },
2498
2812
  {
@@ -2545,12 +2859,12 @@ var TAB_CATALOGUE = {
2545
2859
  {
2546
2860
  id: "concluded",
2547
2861
  label: "\xB1 Concluded",
2548
- predicate: (r) => str3(r.Result) !== "Inconclusive"
2862
+ predicate: (r) => hasConcludedBelief(r)
2549
2863
  },
2550
2864
  {
2551
2865
  id: "inconclusive",
2552
2866
  label: "Inconclusive",
2553
- predicate: (r) => str3(r.Result) === "Inconclusive"
2867
+ predicate: (r) => !hasConcludedBelief(r)
2554
2868
  }
2555
2869
  ],
2556
2870
  decisions: [
@@ -2639,7 +2953,7 @@ function groupRecords(records, axis) {
2639
2953
  if (values.length === 0) push(emptyLabel, r);
2640
2954
  else for (const v of values) push(v, r);
2641
2955
  } else {
2642
- push(str3(r[axis]) ?? emptyLabel, r);
2956
+ push(str(r[axis]) ?? emptyLabel, r);
2643
2957
  }
2644
2958
  }
2645
2959
  return order.map((key) => ({ key, label: key, records: buckets.get(key) }));
@@ -2648,7 +2962,7 @@ function filterRecords(records, query) {
2648
2962
  const q = query.trim().toLowerCase();
2649
2963
  if (!q) return records;
2650
2964
  return records.filter((r) => {
2651
- const hay = `${str3(r.Title) ?? ""} ${str3(r.Description) ?? ""}`.toLowerCase();
2965
+ const hay = `${str(r.Title) ?? ""} ${str(r.Description) ?? ""} ${str(r.Source) ?? ""}`.toLowerCase();
2652
2966
  return hay.includes(q);
2653
2967
  });
2654
2968
  }
@@ -2674,11 +2988,11 @@ function sortRecords(records, sort) {
2674
2988
  }).map((x) => x.r);
2675
2989
  }
2676
2990
  function nestReadingsByPlan(readings, experiments) {
2677
- const titleById = new Map(experiments.map((e) => [e.id, str3(e.Title)]));
2991
+ const titleById = new Map(experiments.map((e) => [e.id, str(e.Title)]));
2678
2992
  const order = [];
2679
2993
  const groups = /* @__PURE__ */ new Map();
2680
2994
  for (const r of readings) {
2681
- const key = str3(r.experimentId);
2995
+ const key = str(r.experimentId);
2682
2996
  if (!groups.has(key)) {
2683
2997
  groups.set(key, []);
2684
2998
  order.push(key);
@@ -2722,17 +3036,160 @@ function needsHumanCounts(ctx) {
2722
3036
  };
2723
3037
  }
2724
3038
 
2725
- // src/record-view.ts
2726
- import { experimentProgress as experimentProgress2 } from "@validation-os/core/derivation";
2727
- function byIds(records, ids) {
2728
- const map = new Map((records ?? []).map((r) => [r.id, r]));
2729
- return ids.map((id) => map.get(id)).filter((r) => r != null);
2730
- }
2731
- function headerPills(register, record, related = {}, options = {}) {
2732
- const pills = [];
2733
- const status = str3(record.Status);
2734
- if (status) pills.push({ label: status, tone: statusTone(status) });
2735
- if (register === "assumptions") {
3039
+ // src/markdown.tsx
3040
+ import { jsx as jsx9 } from "react/jsx-runtime";
3041
+ function Markdown({ text }) {
3042
+ const trimmed = (text ?? "").trim();
3043
+ if (!trimmed) return null;
3044
+ return /* @__PURE__ */ jsx9("div", { className: "vos-md", children: renderBlocks(trimmed) });
3045
+ }
3046
+ function renderBlocks(text) {
3047
+ const lines = text.replace(/\r\n?/g, "\n").split("\n");
3048
+ const out = [];
3049
+ let i = 0;
3050
+ let key = 0;
3051
+ while (i < lines.length) {
3052
+ const line = lines[i];
3053
+ if (line.trim() === "") {
3054
+ i += 1;
3055
+ continue;
3056
+ }
3057
+ const fence = line.match(/^```/);
3058
+ if (fence) {
3059
+ const body = [];
3060
+ i += 1;
3061
+ while (i < lines.length && !/^```/.test(lines[i])) {
3062
+ body.push(lines[i]);
3063
+ i += 1;
3064
+ }
3065
+ i += 1;
3066
+ out.push(
3067
+ /* @__PURE__ */ jsx9("pre", { className: "vos-md-pre", children: /* @__PURE__ */ jsx9("code", { children: body.join("\n") }) }, key++)
3068
+ );
3069
+ continue;
3070
+ }
3071
+ const heading = line.match(/^(#{1,6})\s+(.*)$/);
3072
+ if (heading) {
3073
+ const level = heading[1].length;
3074
+ const Tag = `h${Math.min(level + 2, 6)}`;
3075
+ out.push(/* @__PURE__ */ jsx9(Tag, { children: renderInline(heading[2]) }, key++));
3076
+ i += 1;
3077
+ continue;
3078
+ }
3079
+ if (/^>\s?/.test(line)) {
3080
+ const quote = [];
3081
+ while (i < lines.length && /^>\s?/.test(lines[i])) {
3082
+ quote.push(lines[i].replace(/^>\s?/, ""));
3083
+ i += 1;
3084
+ }
3085
+ out.push(
3086
+ /* @__PURE__ */ jsx9("blockquote", { className: "vos-md-quote", children: renderBlocks(quote.join("\n")) }, key++)
3087
+ );
3088
+ continue;
3089
+ }
3090
+ if (/^[-*+]\s+/.test(line)) {
3091
+ const items = [];
3092
+ while (i < lines.length && /^[-*+]\s+/.test(lines[i])) {
3093
+ items.push(lines[i].replace(/^[-*+]\s+/, ""));
3094
+ i += 1;
3095
+ }
3096
+ out.push(
3097
+ /* @__PURE__ */ jsx9("ul", { className: "vos-md-ul", children: items.map((it, n) => /* @__PURE__ */ jsx9("li", { children: renderInline(it) }, n)) }, key++)
3098
+ );
3099
+ continue;
3100
+ }
3101
+ if (/^\d+\.\s+/.test(line)) {
3102
+ const items = [];
3103
+ while (i < lines.length && /^\d+\.\s+/.test(lines[i])) {
3104
+ items.push(lines[i].replace(/^\d+\.\s+/, ""));
3105
+ i += 1;
3106
+ }
3107
+ out.push(
3108
+ /* @__PURE__ */ jsx9("ol", { className: "vos-md-ol", children: items.map((it, n) => /* @__PURE__ */ jsx9("li", { children: renderInline(it) }, n)) }, key++)
3109
+ );
3110
+ continue;
3111
+ }
3112
+ const para = [];
3113
+ while (i < lines.length && lines[i].trim() !== "" && !/^```|^#{1,6}\s|^>\s?|^[-*+]\s+|^\d+\.\s+/.test(lines[i])) {
3114
+ para.push(lines[i]);
3115
+ i += 1;
3116
+ }
3117
+ out.push(/* @__PURE__ */ jsx9("p", { children: renderInline(para.join(" ")) }, key++));
3118
+ }
3119
+ return out;
3120
+ }
3121
+ function safeHref(href) {
3122
+ if (/^(https?:\/\/|mailto:)/i.test(href)) return href;
3123
+ if (/^[#/]/.test(href)) return href;
3124
+ return null;
3125
+ }
3126
+ var INLINE_RULES = [
3127
+ // Inline code first — its contents are literal.
3128
+ {
3129
+ re: /`([^`]+)`/,
3130
+ render: (m, key) => /* @__PURE__ */ jsx9("code", { className: "vos-md-code", children: m[1] }, key),
3131
+ recurse: false
3132
+ },
3133
+ // Links: [text](href)
3134
+ {
3135
+ re: /\[([^\]]+)\]\(([^)\s]+)\)/,
3136
+ render: (m, key) => {
3137
+ const href = safeHref(m[2]);
3138
+ if (!href) return /* @__PURE__ */ jsx9("span", { children: m[1] }, key);
3139
+ return /* @__PURE__ */ jsx9("a", { href, target: "_blank", rel: "noopener noreferrer", children: m[1] }, key);
3140
+ },
3141
+ recurse: false
3142
+ },
3143
+ // Bold: **text** or __text__
3144
+ {
3145
+ re: /\*\*([^*]+)\*\*|__([^_]+)__/,
3146
+ render: (m, key) => /* @__PURE__ */ jsx9("strong", { children: renderInline(m[1] ?? m[2] ?? "") }, key),
3147
+ recurse: true,
3148
+ inner: (m) => m[1] ?? m[2] ?? ""
3149
+ },
3150
+ // Italic: *text* or _text_
3151
+ {
3152
+ re: /\*([^*]+)\*|_([^_]+)_/,
3153
+ render: (m, key) => /* @__PURE__ */ jsx9("em", { children: renderInline(m[1] ?? m[2] ?? "") }, key),
3154
+ recurse: true,
3155
+ inner: (m) => m[1] ?? m[2] ?? ""
3156
+ }
3157
+ ];
3158
+ function renderInline(text) {
3159
+ const nodes = [];
3160
+ let rest = text;
3161
+ let key = 0;
3162
+ while (rest.length > 0) {
3163
+ let best = null;
3164
+ for (const rule2 of INLINE_RULES) {
3165
+ const m2 = new RegExp(rule2.re).exec(rest);
3166
+ if (m2 && (best === null || m2.index < best.m.index)) {
3167
+ best = { rule: rule2, m: m2 };
3168
+ }
3169
+ }
3170
+ if (!best) {
3171
+ nodes.push(rest);
3172
+ break;
3173
+ }
3174
+ const { rule, m } = best;
3175
+ if (m.index > 0) nodes.push(rest.slice(0, m.index));
3176
+ nodes.push(rule.render(m, key++));
3177
+ rest = rest.slice(m.index + m[0].length);
3178
+ }
3179
+ return nodes;
3180
+ }
3181
+
3182
+ // src/record-view.ts
3183
+ import { experimentProgress as experimentProgress2 } from "@validation-os/core/derivation";
3184
+ function byIds(records, ids) {
3185
+ const map = new Map((records ?? []).map((r) => [r.id, r]));
3186
+ return ids.map((id) => map.get(id)).filter((r) => r != null);
3187
+ }
3188
+ function headerPills(register, record, related = {}, options = {}) {
3189
+ const pills = [];
3190
+ const status = str(record.Status);
3191
+ if (status) pills.push({ label: status, tone: statusTone(status) });
3192
+ if (register === "assumptions") {
2736
3193
  if (record.moot === true) pills.push({ label: "Moot", tone: "neutral" });
2737
3194
  if (inKillLane(record)) pills.push({ label: "Kill lane", tone: "crit" });
2738
3195
  else if (isTesting(record, related.experiments ?? []))
@@ -2740,7 +3197,7 @@ function headerPills(register, record, related = {}, options = {}) {
2740
3197
  } else if (register === "experiments") {
2741
3198
  if (status === "Draft") pills.push({ label: "Test-next", tone: "accent" });
2742
3199
  if (status === "Closed") pills.push({ label: "Concluded", tone: "good" });
2743
- const deadline = str3(record.Deadline);
3200
+ const deadline = str(record.Deadline);
2744
3201
  if (options.asOf && deadline && status === "Running" && deadline < options.asOf)
2745
3202
  pills.push({ label: "Overdue", tone: "crit" });
2746
3203
  } else if (register === "decisions") {
@@ -2781,15 +3238,6 @@ function leadingMeters(register, record) {
2781
3238
  ];
2782
3239
  case "readings":
2783
3240
  return [
2784
- {
2785
- key: "strength",
2786
- label: "Strength",
2787
- kind: "signed",
2788
- value: derivedNum(record, "strength"),
2789
- tone: "neutral",
2790
- min: -100,
2791
- max: 100
2792
- },
2793
3241
  {
2794
3242
  key: "sourceQuality",
2795
3243
  label: "Source quality",
@@ -2798,13 +3246,6 @@ function leadingMeters(register, record) {
2798
3246
  value: derivedNum(record, "sourceQuality") === null ? null : Math.round((derivedNum(record, "sourceQuality") ?? 0) * 100),
2799
3247
  tone: "neutral",
2800
3248
  max: 100
2801
- },
2802
- {
2803
- key: "Result",
2804
- label: "Result",
2805
- kind: "pill",
2806
- value: str3(record.Result),
2807
- tone: statusTone(str3(record.Result) ?? "")
2808
3249
  }
2809
3250
  ];
2810
3251
  case "experiments": {
@@ -2823,7 +3264,7 @@ function leadingMeters(register, record) {
2823
3264
  key: "Feasibility",
2824
3265
  label: "Feasibility",
2825
3266
  kind: "pill",
2826
- value: str3(record.Feasibility),
3267
+ value: str(record.Feasibility),
2827
3268
  tone: "neutral"
2828
3269
  }
2829
3270
  ];
@@ -2834,8 +3275,8 @@ function leadingMeters(register, record) {
2834
3275
  key: "Status",
2835
3276
  label: "Status",
2836
3277
  kind: "pill",
2837
- value: str3(record.Status),
2838
- tone: statusTone(str3(record.Status) ?? "")
3278
+ value: str(record.Status),
3279
+ tone: statusTone(str(record.Status) ?? "")
2839
3280
  }
2840
3281
  ];
2841
3282
  case "glossary":
@@ -2844,8 +3285,8 @@ function leadingMeters(register, record) {
2844
3285
  key: "Status",
2845
3286
  label: "Status",
2846
3287
  kind: "pill",
2847
- value: str3(record.Status),
2848
- tone: statusTone(str3(record.Status) ?? "")
3288
+ value: str(record.Status),
3289
+ tone: statusTone(str(record.Status) ?? "")
2849
3290
  }
2850
3291
  ];
2851
3292
  }
@@ -2864,7 +3305,24 @@ var HUMAN_FIELDS = {
2864
3305
  ]
2865
3306
  };
2866
3307
  function humanInputFields(register, record) {
2867
- return HUMAN_FIELDS[register].map((f) => ({ key: f.key, label: f.label, text: str3(record[f.key]) ?? "" })).filter((f) => f.text !== "");
3308
+ return HUMAN_FIELDS[register].map((f) => ({ key: f.key, label: f.label, text: str(record[f.key]) ?? "" })).filter((f) => f.text !== "");
3309
+ }
3310
+ function readingBeliefVerdicts(reading, assumptions = []) {
3311
+ const byId = new Map(assumptions.map((a) => [a.id, a]));
3312
+ return readingBeliefs(reading).map((b) => {
3313
+ const hit = byId.get(b.assumptionId);
3314
+ const strength = b.derived && typeof b.derived.strength === "number" ? b.derived.strength : null;
3315
+ return {
3316
+ assumptionId: b.assumptionId,
3317
+ title: hit ? primaryLabel(hit) : b.assumptionId,
3318
+ linked: hit != null,
3319
+ rung: b.Rung ?? null,
3320
+ result: b.Result ?? null,
3321
+ strength,
3322
+ magnitudeBand: b.magnitudeBand ?? null,
3323
+ justification: typeof b["Grading justification"] === "string" ? b["Grading justification"] : ""
3324
+ };
3325
+ });
2868
3326
  }
2869
3327
  function scoreChip(register, record) {
2870
3328
  if (register === "assumptions") {
@@ -2872,14 +3330,14 @@ function scoreChip(register, record) {
2872
3330
  return { label: "Confidence", value: formatSigned(c), tone: confidenceTone(c) };
2873
3331
  }
2874
3332
  if (register === "readings") {
2875
- const s = derivedNum(record, "strength");
3333
+ const sq = derivedNum(record, "sourceQuality");
2876
3334
  return {
2877
- label: "Strength",
2878
- value: s === null ? "\u2014" : formatSigned(s),
3335
+ label: "Source quality",
3336
+ value: sq === null ? "\u2014" : String(Math.round(sq * 100)),
2879
3337
  tone: "neutral"
2880
3338
  };
2881
3339
  }
2882
- const status = str3(record.Status) ?? "\u2014";
3340
+ const status = str(record.Status) ?? "\u2014";
2883
3341
  return { label: "Status", value: status, tone: statusTone(status) };
2884
3342
  }
2885
3343
  var PANELS = {
@@ -2888,7 +3346,7 @@ var PANELS = {
2888
3346
  id: "readings",
2889
3347
  label: "Readings",
2890
3348
  register: "readings",
2891
- resolve: (r, rel) => (rel.readings ?? []).filter((x) => x.assumptionId === r.id)
3349
+ resolve: (r, rel) => (rel.readings ?? []).filter((x) => readingGrades(x, r.id))
2892
3350
  },
2893
3351
  {
2894
3352
  id: "depends-on",
@@ -2912,7 +3370,10 @@ var PANELS = {
2912
3370
  id: "tested-by",
2913
3371
  label: "Tested by",
2914
3372
  register: "experiments",
2915
- resolve: (r, rel) => (rel.experiments ?? []).filter((e) => testsAssumption(e, r.id))
3373
+ // Archived plans never surface as a relation (OPS-1305) live plans only.
3374
+ resolve: (r, rel) => liveExperiments(rel.experiments ?? []).filter(
3375
+ (e) => testsAssumption(e, r.id)
3376
+ )
2916
3377
  },
2917
3378
  {
2918
3379
  id: "decisions-based",
@@ -2930,15 +3391,20 @@ var PANELS = {
2930
3391
  readings: [
2931
3392
  {
2932
3393
  id: "assumption",
2933
- label: "Belief",
3394
+ label: "Beliefs",
2934
3395
  register: "assumptions",
2935
- resolve: (r, rel) => byIds(rel.assumptions, [str3(r.assumptionId) ?? ""].filter(Boolean))
3396
+ // A reading grades several beliefs now (OPS-1305) resolve them all.
3397
+ resolve: (r, rel) => byIds(rel.assumptions, strList(r.assumptionIds))
2936
3398
  },
2937
3399
  {
2938
3400
  id: "experiment",
2939
3401
  label: "Evidence plan",
2940
3402
  register: "experiments",
2941
- resolve: (r, rel) => byIds(rel.experiments, [str3(r.experimentId) ?? ""].filter(Boolean))
3403
+ // Only ever surface a NON-archived plan (OPS-1305): an archived origin
3404
+ // reads as no plan at all, never a leaked backlink.
3405
+ resolve: (r, rel) => byIds(rel.experiments, [str(r.experimentId) ?? ""].filter(Boolean)).filter(
3406
+ (e) => !isArchivedExperiment(e)
3407
+ )
2942
3408
  }
2943
3409
  ],
2944
3410
  experiments: [
@@ -3007,8 +3473,49 @@ function buildRecordPage(register, record, related = {}, options = {}) {
3007
3473
  };
3008
3474
  }
3009
3475
 
3476
+ // src/belief-verdicts.tsx
3477
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
3478
+ function resultClass(result) {
3479
+ if (result === "Validated") return "vos-pill vos-pill-good";
3480
+ if (result === "Invalidated") return "vos-pill vos-pill-crit";
3481
+ return "vos-pill vos-pill-neutral";
3482
+ }
3483
+ function BeliefVerdicts({
3484
+ reading,
3485
+ assumptions,
3486
+ onOpenRecord
3487
+ }) {
3488
+ const verdicts = readingBeliefVerdicts(reading, assumptions);
3489
+ if (verdicts.length === 0) {
3490
+ return /* @__PURE__ */ jsx10("p", { className: "vos-hint", children: "This reading grades no beliefs yet." });
3491
+ }
3492
+ return /* @__PURE__ */ jsx10("ul", { className: "vos-verdicts", children: verdicts.map((v) => /* @__PURE__ */ jsxs9("li", { className: "vos-verdict", children: [
3493
+ /* @__PURE__ */ jsxs9("div", { className: "vos-verdict-head", children: [
3494
+ v.linked && onOpenRecord ? /* @__PURE__ */ jsx10(
3495
+ "button",
3496
+ {
3497
+ type: "button",
3498
+ className: "vos-inline-link",
3499
+ onClick: () => onOpenRecord(v.assumptionId),
3500
+ children: v.title
3501
+ }
3502
+ ) : /* @__PURE__ */ jsx10("span", { className: "vos-verdict-title", children: v.title }),
3503
+ /* @__PURE__ */ jsx10("span", { className: resultClass(v.result), children: v.result ?? "\u2014" })
3504
+ ] }),
3505
+ /* @__PURE__ */ jsxs9("div", { className: "vos-verdict-meta", children: [
3506
+ v.rung ? /* @__PURE__ */ jsx10("span", { className: "vos-chip vos-pill vos-pill-neutral", children: v.rung }) : null,
3507
+ v.magnitudeBand ? /* @__PURE__ */ jsx10("span", { className: "vos-chip vos-pill vos-pill-neutral", children: v.magnitudeBand }) : null,
3508
+ v.strength !== null ? /* @__PURE__ */ jsxs9("span", { className: "vos-verdict-strength", children: [
3509
+ "Strength ",
3510
+ formatSigned(v.strength)
3511
+ ] }) : null
3512
+ ] }),
3513
+ v.justification ? /* @__PURE__ */ jsx10("p", { className: "vos-verdict-why", children: v.justification }) : null
3514
+ ] }, v.assumptionId)) });
3515
+ }
3516
+
3010
3517
  // src/record-page.tsx
3011
- import { Fragment as Fragment8, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
3518
+ import { Fragment as Fragment8, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
3012
3519
  var TAB_LABEL = {
3013
3520
  overview: "Overview",
3014
3521
  evidence: "Evidence",
@@ -3073,12 +3580,65 @@ function RecordPage({
3073
3580
  lists.experiments.refresh();
3074
3581
  lists.readings.refresh();
3075
3582
  lists.decisions.refresh();
3583
+ lists.glossary.refresh();
3076
3584
  };
3077
3585
  const terms = toGlossaryTerms(related.glossary ?? []);
3078
3586
  const openTerm = (id) => onNavigate({ name: "record", id });
3079
- return /* @__PURE__ */ jsxs9("div", { children: [
3080
- /* @__PURE__ */ jsxs9("nav", { className: "vos-crumbs", "aria-label": "Breadcrumb", children: [
3081
- /* @__PURE__ */ jsx9(
3587
+ const [editing, setEditing] = useState5(false);
3588
+ const [draft, setDraft] = useState5({});
3589
+ const [baseline, setBaseline] = useState5(null);
3590
+ const { save, saving, conflict, error: saveError, reset } = useUpdate(
3591
+ register ?? backRegister,
3592
+ basePath
3593
+ );
3594
+ function startEditing() {
3595
+ if (!record || !register) return;
3596
+ setBaseline(record);
3597
+ setDraft(draftFrom(register, record));
3598
+ reset();
3599
+ setEditing(true);
3600
+ }
3601
+ function cancelEditing() {
3602
+ setEditing(false);
3603
+ reset();
3604
+ }
3605
+ async function onSaveEdit() {
3606
+ if (!record || !register || !baseline) return;
3607
+ if (Object.keys(draftErrors(register, draft)).length > 0) return;
3608
+ const patch = buildPatch(register, baseline, draft);
3609
+ patch.version = record.version;
3610
+ if (Object.keys(patch).length <= 1) {
3611
+ setEditing(false);
3612
+ return;
3613
+ }
3614
+ const result = await save(record.id, patch);
3615
+ if (result.ok) {
3616
+ setEditing(false);
3617
+ refreshAll();
3618
+ }
3619
+ }
3620
+ function reloadLatest() {
3621
+ reset();
3622
+ refreshAll();
3623
+ }
3624
+ const setField = (key, value) => setDraft((d) => ({ ...d, [key]: value }));
3625
+ const editErrors = editing && register ? draftErrors(register, draft) : {};
3626
+ const edit = {
3627
+ editing,
3628
+ draft,
3629
+ errors: editErrors,
3630
+ saving,
3631
+ conflict,
3632
+ saveError,
3633
+ onEdit: startEditing,
3634
+ onCancel: cancelEditing,
3635
+ onSave: onSaveEdit,
3636
+ onReload: reloadLatest,
3637
+ onField: setField
3638
+ };
3639
+ return /* @__PURE__ */ jsxs10("div", { children: [
3640
+ /* @__PURE__ */ jsxs10("nav", { className: "vos-crumbs", "aria-label": "Breadcrumb", children: [
3641
+ /* @__PURE__ */ jsx11(
3082
3642
  "button",
3083
3643
  {
3084
3644
  type: "button",
@@ -3086,14 +3646,14 @@ function RecordPage({
3086
3646
  children: REGISTER_LABEL[register ?? backRegister]
3087
3647
  }
3088
3648
  ),
3089
- /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: "\u203A" }),
3090
- /* @__PURE__ */ jsx9("span", { className: "vos-rid", children: record ? formatValue(record.Title) : recordId })
3649
+ /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", children: "\u203A" }),
3650
+ /* @__PURE__ */ jsx11("span", { className: "vos-rid", children: record ? formatValue(record.Title) : recordId })
3091
3651
  ] }),
3092
- anyLoading ? /* @__PURE__ */ jsx9("p", { className: "vos-muted", children: "Loading record\u2026" }) : !record || !register ? /* @__PURE__ */ jsxs9("div", { className: "vos-empty", children: [
3652
+ anyLoading ? /* @__PURE__ */ jsx11("p", { className: "vos-muted", children: "Loading record\u2026" }) : !record || !register ? /* @__PURE__ */ jsxs10("div", { className: "vos-empty", children: [
3093
3653
  "Couldn't find a record with id ",
3094
- /* @__PURE__ */ jsx9("b", { children: recordId }),
3654
+ /* @__PURE__ */ jsx11("b", { children: recordId }),
3095
3655
  "."
3096
- ] }) : /* @__PURE__ */ jsx9(
3656
+ ] }) : /* @__PURE__ */ jsx11(
3097
3657
  RecordBody,
3098
3658
  {
3099
3659
  register,
@@ -3108,7 +3668,8 @@ function RecordPage({
3108
3668
  basePath,
3109
3669
  journey,
3110
3670
  onJourneyChanged: refreshAll,
3111
- onNavigate
3671
+ onNavigate,
3672
+ edit
3112
3673
  }
3113
3674
  )
3114
3675
  ] });
@@ -3126,25 +3687,37 @@ function RecordBody({
3126
3687
  basePath,
3127
3688
  journey,
3128
3689
  onJourneyChanged,
3129
- onNavigate
3690
+ onNavigate,
3691
+ edit
3130
3692
  }) {
3131
3693
  const page = buildRecordPage(register, record, related, { asOf });
3132
3694
  const activeTab = page.tabs.includes(tab) ? tab : "overview";
3133
3695
  const description = typeof record.Description === "string" ? record.Description : "";
3134
- return /* @__PURE__ */ jsxs9(Fragment8, { children: [
3135
- /* @__PURE__ */ jsxs9("div", { className: "vos-head vos-record-head", children: [
3136
- /* @__PURE__ */ jsxs9("div", { children: [
3137
- /* @__PURE__ */ jsx9("p", { className: "vos-drawer-eyebrow", children: REGISTER_SINGULAR[register] }),
3138
- /* @__PURE__ */ jsx9("h1", { children: page.title }),
3139
- /* @__PURE__ */ jsx9("div", { className: "vos-pill-row", children: page.pills.map((p, i) => /* @__PURE__ */ jsx9(PillView, { pill: p }, i)) })
3696
+ const bodyText = typeof record.body === "string" ? record.body : "";
3697
+ const hasErrors = Object.keys(edit.errors).length > 0;
3698
+ return /* @__PURE__ */ jsxs10(Fragment8, { children: [
3699
+ /* @__PURE__ */ jsxs10("div", { className: "vos-head vos-record-head", children: [
3700
+ /* @__PURE__ */ jsxs10("div", { children: [
3701
+ /* @__PURE__ */ jsx11("p", { className: "vos-drawer-eyebrow", children: REGISTER_SINGULAR[register] }),
3702
+ /* @__PURE__ */ jsx11("h1", { children: page.title }),
3703
+ /* @__PURE__ */ jsx11("div", { className: "vos-pill-row", children: page.pills.map((p, i) => /* @__PURE__ */ jsx11(PillView, { pill: p }, i)) })
3140
3704
  ] }),
3141
- /* @__PURE__ */ jsx9("div", { className: "vos-spacer" }),
3142
- /* @__PURE__ */ jsxs9("span", { className: "vos-verbadge", children: [
3705
+ /* @__PURE__ */ jsx11("div", { className: "vos-spacer" }),
3706
+ /* @__PURE__ */ jsxs10("span", { className: "vos-verbadge", children: [
3143
3707
  "v",
3144
3708
  formatValue(record.version)
3145
- ] })
3709
+ ] }),
3710
+ !edit.editing ? /* @__PURE__ */ jsx11(
3711
+ "button",
3712
+ {
3713
+ type: "button",
3714
+ onClick: edit.onEdit,
3715
+ className: "vos-btn vos-btn-ghost vos-btn-sm",
3716
+ children: "Edit"
3717
+ }
3718
+ ) : null
3146
3719
  ] }),
3147
- /* @__PURE__ */ jsx9("div", { className: "vos-tabs", role: "tablist", "aria-label": "Record sections", children: page.tabs.map((t2) => /* @__PURE__ */ jsx9(
3720
+ /* @__PURE__ */ jsx11("div", { className: "vos-tabs", role: "tablist", "aria-label": "Record sections", children: page.tabs.map((t2) => /* @__PURE__ */ jsx11(
3148
3721
  "button",
3149
3722
  {
3150
3723
  type: "button",
@@ -3156,8 +3729,8 @@ function RecordBody({
3156
3729
  },
3157
3730
  t2
3158
3731
  )) }),
3159
- activeTab === "overview" ? /* @__PURE__ */ jsxs9("div", { className: "vos-record-cols", children: [
3160
- /* @__PURE__ */ jsx9("section", { className: "vos-meter-grid", children: page.meters.map((m) => /* @__PURE__ */ jsx9(
3732
+ activeTab === "overview" ? /* @__PURE__ */ jsxs10("div", { className: "vos-record-cols", children: [
3733
+ /* @__PURE__ */ jsx11("section", { className: "vos-meter-grid", children: page.meters.map((m) => /* @__PURE__ */ jsx11(
3161
3734
  MeterView,
3162
3735
  {
3163
3736
  meter: m,
@@ -3166,38 +3739,91 @@ function RecordBody({
3166
3739
  },
3167
3740
  m.key
3168
3741
  )) }),
3169
- description ? /* @__PURE__ */ jsxs9("section", { className: "vos-record-prose", children: [
3170
- /* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "Description" }),
3171
- /* @__PURE__ */ jsx9("p", { children: /* @__PURE__ */ jsx9(
3172
- GlossaryText,
3742
+ edit.editing ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-editor", children: [
3743
+ /* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Edit" }),
3744
+ edit.conflict ? /* @__PURE__ */ jsx11(ConflictBanner, { message: edit.conflict, onReload: edit.onReload }) : null,
3745
+ edit.saveError ? /* @__PURE__ */ jsx11("p", { role: "alert", className: "vos-error", children: edit.saveError }) : null,
3746
+ /* @__PURE__ */ jsx11(
3747
+ EditFields,
3173
3748
  {
3174
- text: description,
3175
- terms,
3176
- selfId: register === "glossary" ? record.id : void 0,
3177
- onOpenTerm
3749
+ register,
3750
+ draft: edit.draft,
3751
+ errors: edit.errors,
3752
+ onField: edit.onField
3178
3753
  }
3179
- ) })
3180
- ] }) : null,
3181
- page.humanText.length ? /* @__PURE__ */ jsxs9("section", { className: "vos-record-prose", children: [
3182
- /* @__PURE__ */ jsxs9("h3", { className: "vos-section-title", children: [
3183
- "From a human ",
3184
- /* @__PURE__ */ jsx9("span", { className: "vos-hint", children: "\u2014 not computed" })
3185
- ] }),
3186
- page.humanText.map((h) => /* @__PURE__ */ jsxs9("div", { className: "vos-human-field", children: [
3187
- /* @__PURE__ */ jsx9("div", { className: "vos-detail-k", children: h.label }),
3188
- /* @__PURE__ */ jsx9("p", { children: /* @__PURE__ */ jsx9(
3754
+ ),
3755
+ /* @__PURE__ */ jsxs10("footer", { className: "vos-drawer-footer", children: [
3756
+ /* @__PURE__ */ jsx11(
3757
+ "button",
3758
+ {
3759
+ type: "button",
3760
+ onClick: edit.onCancel,
3761
+ disabled: edit.saving,
3762
+ className: "vos-btn vos-btn-ghost vos-btn-sm",
3763
+ children: "Cancel"
3764
+ }
3765
+ ),
3766
+ /* @__PURE__ */ jsx11(
3767
+ "button",
3768
+ {
3769
+ type: "button",
3770
+ onClick: edit.onSave,
3771
+ disabled: edit.saving || hasErrors,
3772
+ title: hasErrors ? "Fix the highlighted field before saving" : void 0,
3773
+ className: "vos-btn vos-btn-sm",
3774
+ children: edit.saving ? "Saving\u2026" : "Save"
3775
+ }
3776
+ )
3777
+ ] })
3778
+ ] }) : /* @__PURE__ */ jsxs10(Fragment8, { children: [
3779
+ description ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-prose", children: [
3780
+ /* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Description" }),
3781
+ /* @__PURE__ */ jsx11("p", { children: /* @__PURE__ */ jsx11(
3189
3782
  GlossaryText,
3190
3783
  {
3191
- text: h.text,
3784
+ text: description,
3192
3785
  terms,
3193
3786
  selfId: register === "glossary" ? record.id : void 0,
3194
3787
  onOpenTerm
3195
3788
  }
3196
3789
  ) })
3197
- ] }, h.key))
3198
- ] }) : null
3790
+ ] }) : null,
3791
+ bodyText ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-prose", children: [
3792
+ /* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: register === "readings" ? "Quote" : "Narrative" }),
3793
+ /* @__PURE__ */ jsx11(Markdown, { text: bodyText })
3794
+ ] }) : null,
3795
+ register === "readings" ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-prose", children: [
3796
+ /* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Per-belief verdicts" }),
3797
+ /* @__PURE__ */ jsx11(
3798
+ BeliefVerdicts,
3799
+ {
3800
+ reading: record,
3801
+ assumptions: related.assumptions ?? [],
3802
+ onOpenRecord
3803
+ }
3804
+ )
3805
+ ] }) : null,
3806
+ page.humanText.length ? /* @__PURE__ */ jsxs10("section", { className: "vos-record-prose", children: [
3807
+ /* @__PURE__ */ jsxs10("h3", { className: "vos-section-title", children: [
3808
+ "From a human ",
3809
+ /* @__PURE__ */ jsx11("span", { className: "vos-hint", children: "\u2014 not computed" })
3810
+ ] }),
3811
+ page.humanText.map((h) => /* @__PURE__ */ jsxs10("div", { className: "vos-human-field", children: [
3812
+ /* @__PURE__ */ jsx11("div", { className: "vos-detail-k", children: h.label }),
3813
+ /* @__PURE__ */ jsx11("p", { children: /* @__PURE__ */ jsx11(
3814
+ GlossaryText,
3815
+ {
3816
+ text: h.text,
3817
+ terms,
3818
+ selfId: register === "glossary" ? record.id : void 0,
3819
+ onOpenTerm
3820
+ }
3821
+ ) })
3822
+ ] }, h.key))
3823
+ ] }) : null
3824
+ ] })
3199
3825
  ] }) : null,
3200
- activeTab === "evidence" ? /* @__PURE__ */ jsx9(
3826
+ activeTab === "evidence" ? /* @__PURE__ */ jsx11(
3201
3827
  EvidenceTab,
3202
3828
  {
3203
3829
  register,
@@ -3207,25 +3833,25 @@ function RecordBody({
3207
3833
  basePath
3208
3834
  }
3209
3835
  ) : null,
3210
- activeTab === "connections" ? /* @__PURE__ */ jsx9("div", { className: "vos-panels", children: page.panels.map((panel) => /* @__PURE__ */ jsx9(PanelView, { panel, onOpenRecord }, panel.id)) }) : null,
3211
- activeTab === "history" ? /* @__PURE__ */ jsxs9("section", { className: "vos-detail-list", children: [
3212
- /* @__PURE__ */ jsxs9("div", { className: "vos-detail-row", children: [
3213
- /* @__PURE__ */ jsx9("span", { className: "vos-detail-k", children: "Created" }),
3214
- /* @__PURE__ */ jsx9("span", { className: "vos-detail-v", children: formatValue(record.createdAt) })
3836
+ activeTab === "connections" ? /* @__PURE__ */ jsx11("div", { className: "vos-panels", children: page.panels.map((panel) => /* @__PURE__ */ jsx11(PanelView, { panel, onOpenRecord }, panel.id)) }) : null,
3837
+ activeTab === "history" ? /* @__PURE__ */ jsxs10("section", { className: "vos-detail-list", children: [
3838
+ /* @__PURE__ */ jsxs10("div", { className: "vos-detail-row", children: [
3839
+ /* @__PURE__ */ jsx11("span", { className: "vos-detail-k", children: "Created" }),
3840
+ /* @__PURE__ */ jsx11("span", { className: "vos-detail-v", children: formatValue(record.createdAt) })
3215
3841
  ] }),
3216
- /* @__PURE__ */ jsxs9("div", { className: "vos-detail-row", children: [
3217
- /* @__PURE__ */ jsx9("span", { className: "vos-detail-k", children: "Last updated" }),
3218
- /* @__PURE__ */ jsx9("span", { className: "vos-detail-v", children: formatValue(record.updatedAt) })
3842
+ /* @__PURE__ */ jsxs10("div", { className: "vos-detail-row", children: [
3843
+ /* @__PURE__ */ jsx11("span", { className: "vos-detail-k", children: "Last updated" }),
3844
+ /* @__PURE__ */ jsx11("span", { className: "vos-detail-v", children: formatValue(record.updatedAt) })
3219
3845
  ] }),
3220
- /* @__PURE__ */ jsxs9("div", { className: "vos-detail-row", children: [
3221
- /* @__PURE__ */ jsx9("span", { className: "vos-detail-k", children: "Version" }),
3222
- /* @__PURE__ */ jsx9("span", { className: "vos-detail-v", children: formatValue(record.version) })
3846
+ /* @__PURE__ */ jsxs10("div", { className: "vos-detail-row", children: [
3847
+ /* @__PURE__ */ jsx11("span", { className: "vos-detail-k", children: "Version" }),
3848
+ /* @__PURE__ */ jsx11("span", { className: "vos-detail-v", children: formatValue(record.version) })
3223
3849
  ] }),
3224
- /* @__PURE__ */ jsx9("p", { className: "vos-hint", children: "The full change trail lands here as the API exposes version history; this absorbs the retired provenance prose." })
3850
+ /* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "The full change trail lands here as the API exposes version history; this absorbs the retired provenance prose." })
3225
3851
  ] }) : null,
3226
- page.hasJourney && journey ? /* @__PURE__ */ jsxs9("section", { className: "vos-journey-host", children: [
3227
- /* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "Validation journey" }),
3228
- /* @__PURE__ */ jsx9(
3852
+ page.hasJourney && journey ? /* @__PURE__ */ jsxs10("section", { className: "vos-journey-host", children: [
3853
+ /* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Validation journey" }),
3854
+ /* @__PURE__ */ jsx11(
3229
3855
  BeliefJourney,
3230
3856
  {
3231
3857
  journey,
@@ -3235,14 +3861,23 @@ function RecordBody({
3235
3861
  onChanged: onJourneyChanged
3236
3862
  }
3237
3863
  )
3238
- ] }) : page.hasJourney ? /* @__PURE__ */ jsxs9("section", { className: "vos-journey-host", children: [
3239
- /* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "Validation journey" }),
3240
- /* @__PURE__ */ jsx9("p", { className: "vos-hint", children: "The per-belief journey (Framed \u2192 Planned \u2192 Tested \u2192 Known) mounts here \u2014 built by the workflow-first map (OPS-1289). This page is its host." })
3864
+ ] }) : page.hasJourney ? /* @__PURE__ */ jsxs10("section", { className: "vos-journey-host", children: [
3865
+ /* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Validation journey" }),
3866
+ /* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "The per-belief journey (Framed \u2192 Planned \u2192 Tested \u2192 Known) mounts here \u2014 built by the workflow-first map (OPS-1289). This page is its host." })
3241
3867
  ] }) : null
3242
3868
  ] });
3243
3869
  }
3244
3870
  function PillView({ pill }) {
3245
- return /* @__PURE__ */ jsx9("span", { className: PILL_CLASS3[pill.tone], children: pill.label });
3871
+ return /* @__PURE__ */ jsx11("span", { className: PILL_CLASS3[pill.tone], children: pill.label });
3872
+ }
3873
+ function ConflictBanner({
3874
+ message,
3875
+ onReload
3876
+ }) {
3877
+ return /* @__PURE__ */ jsxs10("div", { role: "alert", className: "vos-banner vos-banner-warn", children: [
3878
+ /* @__PURE__ */ jsx11("div", { className: "vos-banner-body", children: /* @__PURE__ */ jsx11("span", { children: message }) }),
3879
+ /* @__PURE__ */ jsx11("button", { type: "button", onClick: onReload, children: "Review the latest" })
3880
+ ] });
3246
3881
  }
3247
3882
  function MeterView({
3248
3883
  meter,
@@ -3251,10 +3886,10 @@ function MeterView({
3251
3886
  }) {
3252
3887
  const [why, setWhy] = useState5(false);
3253
3888
  const textTone = meter.tone === "crit" ? "vos-text-crit" : meter.tone === "warn" ? "vos-text-warn" : "";
3254
- return /* @__PURE__ */ jsxs9("div", { className: "vos-meter", children: [
3255
- /* @__PURE__ */ jsxs9("div", { className: "vos-meter-head", children: [
3256
- /* @__PURE__ */ jsx9("span", { className: "vos-meter-label", children: meter.label }),
3257
- meter.hasWhy && assumption ? /* @__PURE__ */ jsxs9(
3889
+ return /* @__PURE__ */ jsxs10("div", { className: "vos-meter", children: [
3890
+ /* @__PURE__ */ jsxs10("div", { className: "vos-meter-head", children: [
3891
+ /* @__PURE__ */ jsx11("span", { className: "vos-meter-label", children: meter.label }),
3892
+ meter.hasWhy && assumption ? /* @__PURE__ */ jsxs10(
3258
3893
  "button",
3259
3894
  {
3260
3895
  type: "button",
@@ -3268,12 +3903,12 @@ function MeterView({
3268
3903
  }
3269
3904
  ) : null
3270
3905
  ] }),
3271
- meter.value === null ? /* @__PURE__ */ jsx9("div", { className: "vos-meter-val vos-muted", children: "\u2014" }) : meter.kind === "pill" ? /* @__PURE__ */ jsx9("span", { className: PILL_CLASS3[meter.tone], children: meter.value }) : meter.kind === "signed" ? /* @__PURE__ */ jsxs9(Fragment8, { children: [
3272
- /* @__PURE__ */ jsx9("div", { className: `vos-meter-val ${textTone}`, children: formatSigned(Number(meter.value)) }),
3273
- /* @__PURE__ */ jsx9("span", { className: "vos-track vos-signed", children: /* @__PURE__ */ jsx9(SignedFill, { value: Number(meter.value), min: meter.min ?? -100, max: meter.max ?? 100 }) })
3274
- ] }) : /* @__PURE__ */ jsxs9(Fragment8, { children: [
3275
- /* @__PURE__ */ jsx9("div", { className: `vos-meter-val ${textTone}`, children: Math.round(Number(meter.value)) }),
3276
- /* @__PURE__ */ jsx9("span", { className: "vos-risk-bar", children: /* @__PURE__ */ jsx9(
3906
+ meter.value === null ? /* @__PURE__ */ jsx11("div", { className: "vos-meter-val vos-muted", children: "\u2014" }) : meter.kind === "pill" ? /* @__PURE__ */ jsx11("span", { className: PILL_CLASS3[meter.tone], children: meter.value }) : meter.kind === "signed" ? /* @__PURE__ */ jsxs10(Fragment8, { children: [
3907
+ /* @__PURE__ */ jsx11("div", { className: `vos-meter-val ${textTone}`, children: formatSigned(Number(meter.value)) }),
3908
+ /* @__PURE__ */ jsx11("span", { className: "vos-track vos-signed", children: /* @__PURE__ */ jsx11(SignedFill, { value: Number(meter.value), min: meter.min ?? -100, max: meter.max ?? 100 }) })
3909
+ ] }) : /* @__PURE__ */ jsxs10(Fragment8, { children: [
3910
+ /* @__PURE__ */ jsx11("div", { className: `vos-meter-val ${textTone}`, children: Math.round(Number(meter.value)) }),
3911
+ /* @__PURE__ */ jsx11("span", { className: "vos-risk-bar", children: /* @__PURE__ */ jsx11(
3277
3912
  "i",
3278
3913
  {
3279
3914
  className: meter.tone === "crit" ? "vos-fill-crit" : meter.tone === "warn" ? "vos-fill-warn" : "vos-fill-good",
@@ -3281,7 +3916,7 @@ function MeterView({
3281
3916
  }
3282
3917
  ) })
3283
3918
  ] }),
3284
- why && assumption ? /* @__PURE__ */ jsx9("div", { className: "vos-why-panel", children: /* @__PURE__ */ jsx9(UnderstandingPanel, { assumption, basePath }) }) : null
3919
+ why && assumption ? /* @__PURE__ */ jsx11("div", { className: "vos-why-panel", children: /* @__PURE__ */ jsx11(UnderstandingPanel, { assumption, basePath }) }) : null
3285
3920
  ] });
3286
3921
  }
3287
3922
  function SignedFill({ value, min, max }) {
@@ -3289,34 +3924,34 @@ function SignedFill({ value, min, max }) {
3289
3924
  const width = Math.round(Math.min(Math.abs(value), span) / span * 50);
3290
3925
  const up = value >= 0;
3291
3926
  const style = up ? { left: "50%", width: `${width}%`, background: "var(--vos-good)" } : { right: "50%", width: `${width}%`, background: "var(--vos-crit)" };
3292
- return width > 0 ? /* @__PURE__ */ jsx9("i", { style }) : null;
3927
+ return width > 0 ? /* @__PURE__ */ jsx11("i", { style }) : null;
3293
3928
  }
3294
3929
  function PanelView({
3295
3930
  panel,
3296
3931
  onOpenRecord
3297
3932
  }) {
3298
- return /* @__PURE__ */ jsxs9("section", { className: "vos-panel", children: [
3299
- /* @__PURE__ */ jsxs9("h3", { className: "vos-panel-head", children: [
3933
+ return /* @__PURE__ */ jsxs10("section", { className: "vos-panel", children: [
3934
+ /* @__PURE__ */ jsxs10("h3", { className: "vos-panel-head", children: [
3300
3935
  panel.label,
3301
- /* @__PURE__ */ jsx9("span", { className: "vos-group-n", children: panel.items.length })
3936
+ /* @__PURE__ */ jsx11("span", { className: "vos-group-n", children: panel.items.length })
3302
3937
  ] }),
3303
- panel.items.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "vos-hint", children: "None yet." }) : /* @__PURE__ */ jsx9("ul", { className: "vos-backlinks", children: panel.items.map((item) => /* @__PURE__ */ jsx9(BacklinkRow, { item, onOpenRecord }, item.id)) })
3938
+ panel.items.length === 0 ? /* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "None yet." }) : /* @__PURE__ */ jsx11("ul", { className: "vos-backlinks", children: panel.items.map((item) => /* @__PURE__ */ jsx11(BacklinkRow, { item, onOpenRecord }, item.id)) })
3304
3939
  ] });
3305
3940
  }
3306
3941
  function BacklinkRow({
3307
3942
  item,
3308
3943
  onOpenRecord
3309
3944
  }) {
3310
- return /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsxs9(
3945
+ return /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsxs10(
3311
3946
  "button",
3312
3947
  {
3313
3948
  type: "button",
3314
3949
  className: "vos-backlink",
3315
3950
  onClick: () => onOpenRecord(item.id),
3316
3951
  children: [
3317
- /* @__PURE__ */ jsx9("span", { className: "vos-backlink-title", children: item.title }),
3318
- /* @__PURE__ */ jsxs9("span", { className: `vos-chip ${PILL_CLASS3[item.chip.tone]}`, children: [
3319
- /* @__PURE__ */ jsx9("span", { className: "vos-chip-k", children: item.chip.label }),
3952
+ /* @__PURE__ */ jsx11("span", { className: "vos-backlink-title", children: item.title }),
3953
+ /* @__PURE__ */ jsxs10("span", { className: `vos-chip ${PILL_CLASS3[item.chip.tone]}`, children: [
3954
+ /* @__PURE__ */ jsx11("span", { className: "vos-chip-k", children: item.chip.label }),
3320
3955
  item.chip.value
3321
3956
  ] })
3322
3957
  ]
@@ -3331,17 +3966,29 @@ function EvidenceTab({
3331
3966
  basePath
3332
3967
  }) {
3333
3968
  if (register === "assumptions") {
3334
- return /* @__PURE__ */ jsx9("section", { className: "vos-why-panel", children: /* @__PURE__ */ jsx9(UnderstandingPanel, { assumption: record, basePath }) });
3969
+ return /* @__PURE__ */ jsx11("section", { className: "vos-why-panel", children: /* @__PURE__ */ jsx11(UnderstandingPanel, { assumption: record, basePath }) });
3335
3970
  }
3336
- const bars = record.barLines ?? [];
3971
+ const bars = resolveBarLines(
3972
+ record.barLines ?? [],
3973
+ related
3974
+ );
3337
3975
  const mine = (related.readings ?? []).filter((r) => r.experimentId === record.id);
3338
3976
  const nested = nestReadingsByPlan(mine, [record]);
3339
- return /* @__PURE__ */ jsxs9("div", { className: "vos-record-cols", children: [
3340
- /* @__PURE__ */ jsxs9("section", { children: [
3341
- /* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "Bar lines" }),
3342
- bars.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "vos-hint", children: "No pre-registered bars." }) : /* @__PURE__ */ jsx9("ul", { className: "vos-bars", children: bars.map((b, i) => /* @__PURE__ */ jsxs9("li", { className: "vos-bar-line", children: [
3343
- /* @__PURE__ */ jsx9("span", { className: "vos-bar-if", children: b.rightIf ?? "\u2014" }),
3344
- /* @__PURE__ */ jsx9(
3977
+ return /* @__PURE__ */ jsxs10("div", { className: "vos-record-cols", children: [
3978
+ /* @__PURE__ */ jsxs10("section", { children: [
3979
+ /* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Bar lines" }),
3980
+ bars.length === 0 ? /* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "No pre-registered bars." }) : /* @__PURE__ */ jsx11("ul", { className: "vos-bars", children: bars.map((b, i) => /* @__PURE__ */ jsxs10("li", { className: "vos-bar-line", children: [
3981
+ /* @__PURE__ */ jsx11("span", { className: "vos-bar-if", children: b.rightIf || "\u2014" }),
3982
+ b.assumption ? /* @__PURE__ */ jsx11(
3983
+ "button",
3984
+ {
3985
+ type: "button",
3986
+ className: "vos-inline-link",
3987
+ onClick: () => onOpenRecord(b.assumption.id),
3988
+ children: b.assumption.title
3989
+ }
3990
+ ) : null,
3991
+ /* @__PURE__ */ jsx11(
3345
3992
  "span",
3346
3993
  {
3347
3994
  className: b.barVerdict ? "vos-pill vos-pill-good" : "vos-pill vos-pill-neutral",
@@ -3350,17 +3997,21 @@ function EvidenceTab({
3350
3997
  )
3351
3998
  ] }, i)) })
3352
3999
  ] }),
3353
- /* @__PURE__ */ jsxs9("section", { children: [
3354
- /* @__PURE__ */ jsx9("h3", { className: "vos-section-title", children: "Readings" }),
3355
- nested.length === 0 ? /* @__PURE__ */ jsx9("p", { className: "vos-hint", children: "No readings logged yet." }) : /* @__PURE__ */ jsx9("ul", { className: "vos-backlinks", children: nested[0].readings.map((r) => /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsxs9(
4000
+ /* @__PURE__ */ jsxs10("section", { children: [
4001
+ /* @__PURE__ */ jsx11("h3", { className: "vos-section-title", children: "Readings" }),
4002
+ nested.length === 0 ? /* @__PURE__ */ jsx11("p", { className: "vos-hint", children: "No readings logged yet." }) : /* @__PURE__ */ jsx11("ul", { className: "vos-backlinks", children: nested[0].readings.map((r) => /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsxs10(
3356
4003
  "button",
3357
4004
  {
3358
4005
  type: "button",
3359
4006
  className: "vos-backlink",
3360
4007
  onClick: () => onOpenRecord(r.id),
3361
4008
  children: [
3362
- /* @__PURE__ */ jsx9("span", { className: "vos-backlink-title", children: formatValue(r.Title) }),
3363
- /* @__PURE__ */ jsx9("span", { className: "vos-chip vos-pill vos-pill-neutral", children: formatValue(r.Result) })
4009
+ /* @__PURE__ */ jsx11("span", { className: "vos-backlink-title", children: formatValue(r.Title) }),
4010
+ /* @__PURE__ */ jsxs10("span", { className: "vos-chip vos-pill vos-pill-neutral", children: [
4011
+ readingBeliefs(r).length,
4012
+ " belief",
4013
+ readingBeliefs(r).length === 1 ? "" : "s"
4014
+ ] })
3364
4015
  ]
3365
4016
  }
3366
4017
  ) }, r.id)) })
@@ -3372,19 +4023,20 @@ function EvidenceTab({
3372
4023
  import { useMemo as useMemo4, useState as useState10 } from "react";
3373
4024
 
3374
4025
  // src/register-table.tsx
3375
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
4026
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
3376
4027
  function RegisterTable({
3377
4028
  register,
3378
4029
  records,
3379
4030
  onRowClick,
3380
- selectedId
4031
+ selectedId,
4032
+ assumptionTitles
3381
4033
  }) {
3382
4034
  const columns = columnsFor(register);
3383
4035
  if (records.length === 0) {
3384
- return /* @__PURE__ */ jsx10("p", { className: "vos-empty", children: "No records yet." });
4036
+ return /* @__PURE__ */ jsx12("p", { className: "vos-empty", children: "No records yet." });
3385
4037
  }
3386
- return /* @__PURE__ */ jsx10("div", { className: "vos-card vos-table-scroll", children: /* @__PURE__ */ jsxs10("table", { className: "vos-table", children: [
3387
- /* @__PURE__ */ jsx10("thead", { children: /* @__PURE__ */ jsx10("tr", { children: columns.map((c) => /* @__PURE__ */ jsx10(
4038
+ return /* @__PURE__ */ jsx12("div", { className: "vos-card vos-table-scroll", children: /* @__PURE__ */ jsxs11("table", { className: "vos-table", children: [
4039
+ /* @__PURE__ */ jsx12("thead", { children: /* @__PURE__ */ jsx12("tr", { children: columns.map((c) => /* @__PURE__ */ jsx12(
3388
4040
  "th",
3389
4041
  {
3390
4042
  scope: "col",
@@ -3393,9 +4045,9 @@ function RegisterTable({
3393
4045
  },
3394
4046
  c.key
3395
4047
  )) }) }),
3396
- /* @__PURE__ */ jsx10("tbody", { children: records.map((record) => {
4048
+ /* @__PURE__ */ jsx12("tbody", { children: records.map((record) => {
3397
4049
  const isSelected = record.id === selectedId;
3398
- return /* @__PURE__ */ jsx10(
4050
+ return /* @__PURE__ */ jsx12(
3399
4051
  "tr",
3400
4052
  {
3401
4053
  onClick: () => onRowClick?.(record.id),
@@ -3408,11 +4060,19 @@ function RegisterTable({
3408
4060
  tabIndex: onRowClick ? 0 : void 0,
3409
4061
  "aria-selected": isSelected,
3410
4062
  className: isSelected ? "is-selected" : void 0,
3411
- children: columns.map((c, i) => /* @__PURE__ */ jsx10(
4063
+ children: columns.map((c, i) => /* @__PURE__ */ jsx12(
3412
4064
  "td",
3413
4065
  {
3414
4066
  className: c.align === "right" ? "vos-r" : void 0,
3415
- children: /* @__PURE__ */ jsx10(Cell, { column: c, record, headline: i === 0 })
4067
+ children: /* @__PURE__ */ jsx12(
4068
+ Cell,
4069
+ {
4070
+ column: c,
4071
+ record,
4072
+ headline: i === 0,
4073
+ chips: i === 0 && register === "readings" ? readingAssumptionChips(record, assumptionTitles) : void 0
4074
+ }
4075
+ )
3416
4076
  },
3417
4077
  c.key
3418
4078
  ))
@@ -3425,26 +4085,32 @@ function RegisterTable({
3425
4085
  function Cell({
3426
4086
  column,
3427
4087
  record,
3428
- headline
4088
+ headline,
4089
+ chips
3429
4090
  }) {
3430
4091
  const raw = cellValue(column, record);
3431
4092
  if (column.kind === "status") {
3432
- return /* @__PURE__ */ jsx10(StatusPill, { status: raw == null ? null : String(raw) });
4093
+ return /* @__PURE__ */ jsx12(StatusPill, { status: raw == null ? null : String(raw) });
3433
4094
  }
3434
4095
  if (column.kind === "risk") {
3435
- return typeof raw === "number" ? /* @__PURE__ */ jsx10(RiskBar, { risk: raw }) : /* @__PURE__ */ jsx10("span", { className: "vos-muted", children: "\u2014" });
4096
+ return typeof raw === "number" ? /* @__PURE__ */ jsx12(RiskBar, { risk: raw }) : /* @__PURE__ */ jsx12("span", { className: "vos-muted", children: "\u2014" });
3436
4097
  }
3437
4098
  if (column.kind === "confidence") {
3438
- return typeof raw === "number" ? /* @__PURE__ */ jsx10(ConfidenceCell, { confidence: raw }) : /* @__PURE__ */ jsx10("span", { className: "vos-muted", children: "\u2014" });
4099
+ return typeof raw === "number" ? /* @__PURE__ */ jsx12(ConfidenceCell, { confidence: raw }) : /* @__PURE__ */ jsx12("span", { className: "vos-muted", children: "\u2014" });
3439
4100
  }
3440
4101
  const text = headline && (raw === null || raw === void 0 || raw === "") ? primaryLabel(record) : formatValue(raw);
3441
- return /* @__PURE__ */ jsx10("span", { className: headline ? "vos-ttl" : void 0, children: text });
4102
+ if (headline && chips && chips.length > 0) {
4103
+ return /* @__PURE__ */ jsxs11("span", { className: "vos-ttl-wrap", children: [
4104
+ /* @__PURE__ */ jsx12("span", { className: "vos-ttl", children: text }),
4105
+ /* @__PURE__ */ jsx12("span", { className: "vos-reading-chips", children: chips.map((chip, n) => /* @__PURE__ */ jsx12("span", { className: "vos-chip vos-pill vos-pill-neutral", children: chip }, n)) })
4106
+ ] });
4107
+ }
4108
+ return /* @__PURE__ */ jsx12("span", { className: headline ? "vos-ttl" : void 0, children: text });
3442
4109
  }
3443
4110
 
3444
4111
  // src/record-drawer.tsx
3445
4112
  import { useEffect as useEffect3, useState as useState6 } from "react";
3446
- import { Fragment as Fragment9, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
3447
- var META_FIELDS = /* @__PURE__ */ new Set(["id", "version", "createdAt", "updatedAt", "derived"]);
4113
+ import { Fragment as Fragment9, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
3448
4114
  var DERIVED_SUB = {
3449
4115
  confidence: "Signed average of concluded readings",
3450
4116
  risk: "Impact \xD7 (1 \u2212 Confidence\u207A/100)",
@@ -3463,6 +4129,8 @@ function RecordDrawer({
3463
4129
  basePath,
3464
4130
  onChanged,
3465
4131
  onOpenFull,
4132
+ onOpenRecord,
4133
+ related,
3466
4134
  children
3467
4135
  }) {
3468
4136
  const [editing, setEditing] = useState6(false);
@@ -3481,7 +4149,7 @@ function RecordDrawer({
3481
4149
  reset();
3482
4150
  }, [recordId, reset]);
3483
4151
  const derived = record && record.derived && typeof record.derived === "object" ? record.derived : null;
3484
- const fields = record ? Object.keys(record).filter((k) => !META_FIELDS.has(k)) : [];
4152
+ const rows = record ? detailRows(register, record, related ?? {}) : [];
3485
4153
  function startEditing() {
3486
4154
  if (!record) return;
3487
4155
  setBaseline(record);
@@ -3495,6 +4163,7 @@ function RecordDrawer({
3495
4163
  }
3496
4164
  async function onSave() {
3497
4165
  if (!record || !baseline) return;
4166
+ if (Object.keys(draftErrors(register, draft)).length > 0) return;
3498
4167
  const patch = buildPatch(register, baseline, draft);
3499
4168
  patch.version = record.version;
3500
4169
  if (Object.keys(patch).length <= 1) {
@@ -3512,23 +4181,25 @@ function RecordDrawer({
3512
4181
  onChanged?.();
3513
4182
  }
3514
4183
  const setField = (key, value) => setDraft((d) => ({ ...d, [key]: value }));
3515
- return /* @__PURE__ */ jsxs11(
4184
+ const errors = editing ? draftErrors(register, draft) : {};
4185
+ const hasErrors = Object.keys(errors).length > 0;
4186
+ return /* @__PURE__ */ jsxs12(
3516
4187
  DrawerShell,
3517
4188
  {
3518
4189
  open,
3519
4190
  onClose,
3520
4191
  ariaLabel: `${REGISTER_LABEL[register]} record`,
3521
4192
  children: [
3522
- /* @__PURE__ */ jsxs11("header", { className: "vos-drawer-header", children: [
3523
- /* @__PURE__ */ jsxs11("div", { style: { flex: 1, minWidth: 0 }, children: [
3524
- /* @__PURE__ */ jsx11("p", { className: "vos-drawer-eyebrow", children: REGISTER_LABEL[register] }),
3525
- /* @__PURE__ */ jsx11("h2", { className: "vos-drawer-title", children: record ? primaryLabel(record) : loading ? "Loading\u2026" : "\u2014" })
4193
+ /* @__PURE__ */ jsxs12("header", { className: "vos-drawer-header", children: [
4194
+ /* @__PURE__ */ jsxs12("div", { style: { flex: 1, minWidth: 0 }, children: [
4195
+ /* @__PURE__ */ jsx13("p", { className: "vos-drawer-eyebrow", children: REGISTER_LABEL[register] }),
4196
+ /* @__PURE__ */ jsx13("h2", { className: "vos-drawer-title", children: record ? primaryLabel(record) : loading ? "Loading\u2026" : "\u2014" })
3526
4197
  ] }),
3527
- record ? /* @__PURE__ */ jsxs11("span", { className: "vos-verbadge", children: [
4198
+ record ? /* @__PURE__ */ jsxs12("span", { className: "vos-verbadge", children: [
3528
4199
  "v",
3529
4200
  formatValue(record.version)
3530
4201
  ] }) : null,
3531
- record && !editing && onOpenFull ? /* @__PURE__ */ jsx11(
4202
+ record && !editing && onOpenFull ? /* @__PURE__ */ jsx13(
3532
4203
  "button",
3533
4204
  {
3534
4205
  type: "button",
@@ -3537,7 +4208,7 @@ function RecordDrawer({
3537
4208
  children: "Full page \u2197"
3538
4209
  }
3539
4210
  ) : null,
3540
- record && !editing ? /* @__PURE__ */ jsx11(
4211
+ record && !editing ? /* @__PURE__ */ jsx13(
3541
4212
  "button",
3542
4213
  {
3543
4214
  type: "button",
@@ -3546,7 +4217,7 @@ function RecordDrawer({
3546
4217
  children: "Edit"
3547
4218
  }
3548
4219
  ) : null,
3549
- /* @__PURE__ */ jsx11(
4220
+ /* @__PURE__ */ jsx13(
3550
4221
  "button",
3551
4222
  {
3552
4223
  type: "button",
@@ -3557,14 +4228,14 @@ function RecordDrawer({
3557
4228
  }
3558
4229
  )
3559
4230
  ] }),
3560
- /* @__PURE__ */ jsx11("div", { className: "vos-drawer-body", children: loading ? /* @__PURE__ */ jsx11("p", { className: "vos-muted", children: "Loading record\u2026" }) : error ? /* @__PURE__ */ jsx11("p", { className: "vos-error", children: error }) : !record ? /* @__PURE__ */ jsx11("p", { className: "vos-muted", children: "No record." }) : /* @__PURE__ */ jsxs11(Fragment9, { children: [
3561
- derived ? /* @__PURE__ */ jsxs11("div", { children: [
3562
- /* @__PURE__ */ jsxs11("div", { className: "vos-derived", children: [
3563
- /* @__PURE__ */ jsxs11("div", { className: "vos-derived-head", children: [
4231
+ /* @__PURE__ */ jsx13("div", { className: "vos-drawer-body", children: loading ? /* @__PURE__ */ jsx13("p", { className: "vos-muted", children: "Loading record\u2026" }) : error ? /* @__PURE__ */ jsx13("p", { className: "vos-error", children: error }) : !record ? /* @__PURE__ */ jsx13("p", { className: "vos-muted", children: "No record." }) : /* @__PURE__ */ jsxs12(Fragment9, { children: [
4232
+ derived ? /* @__PURE__ */ jsxs12("div", { children: [
4233
+ /* @__PURE__ */ jsxs12("div", { className: "vos-derived", children: [
4234
+ /* @__PURE__ */ jsxs12("div", { className: "vos-derived-head", children: [
3564
4235
  "Derived",
3565
- /* @__PURE__ */ jsx11("span", { className: "vos-lock", children: "\u{1F512} computed on write \u2014 not editable" })
4236
+ /* @__PURE__ */ jsx13("span", { className: "vos-lock", children: "\u{1F512} computed on write \u2014 not editable" })
3566
4237
  ] }),
3567
- /* @__PURE__ */ jsx11("div", { className: "vos-dgrid", children: Object.entries(derived).map(([key, value]) => /* @__PURE__ */ jsx11(
4238
+ /* @__PURE__ */ jsx13("div", { className: "vos-dgrid", children: Object.entries(derived).map(([key, value]) => /* @__PURE__ */ jsx13(
3568
4239
  DerivedCell,
3569
4240
  {
3570
4241
  field: key,
@@ -3576,25 +4247,47 @@ function RecordDrawer({
3576
4247
  key
3577
4248
  )) })
3578
4249
  ] }),
3579
- "confidence" in derived && why ? /* @__PURE__ */ jsx11("div", { className: "vos-why-panel", children: /* @__PURE__ */ jsx11(UnderstandingPanel, { assumption: record, basePath }) }) : null
4250
+ "confidence" in derived && why ? /* @__PURE__ */ jsx13("div", { className: "vos-why-panel", children: /* @__PURE__ */ jsx13(UnderstandingPanel, { assumption: record, basePath }) }) : null
3580
4251
  ] }) : null,
3581
- conflict ? /* @__PURE__ */ jsx11(ConflictBanner, { message: conflict, onReload: reloadLatest }) : null,
3582
- saveError ? /* @__PURE__ */ jsx11("p", { role: "alert", className: "vos-banner vos-banner-crit", children: saveError }) : null,
3583
- editing ? /* @__PURE__ */ jsx11(
4252
+ conflict ? /* @__PURE__ */ jsx13(ConflictBanner2, { message: conflict, onReload: reloadLatest }) : null,
4253
+ saveError ? /* @__PURE__ */ jsx13("p", { role: "alert", className: "vos-banner vos-banner-crit", children: saveError }) : null,
4254
+ editing ? /* @__PURE__ */ jsx13(
3584
4255
  EditFields,
3585
4256
  {
3586
4257
  register,
3587
4258
  draft,
4259
+ errors,
3588
4260
  onField: setField
3589
4261
  }
3590
- ) : /* @__PURE__ */ jsx11("div", { className: "vos-detail-list", children: fields.map((key) => /* @__PURE__ */ jsxs11("div", { className: "vos-detail-row", children: [
3591
- /* @__PURE__ */ jsx11("span", { className: "vos-detail-k", children: fieldLabel(key) }),
3592
- /* @__PURE__ */ jsx11("span", { className: "vos-detail-v", children: formatValue(record[key]) })
3593
- ] }, key)) })
4262
+ ) : /* @__PURE__ */ jsxs12(Fragment9, { children: [
4263
+ /* @__PURE__ */ jsx13("div", { className: "vos-detail-list", children: rows.map((row) => /* @__PURE__ */ jsx13(
4264
+ DetailRowView,
4265
+ {
4266
+ row,
4267
+ onOpenRecord
4268
+ },
4269
+ row.key
4270
+ )) }),
4271
+ typeof record.body === "string" && record.body.trim() ? /* @__PURE__ */ jsxs12("section", { className: "vos-record-prose", children: [
4272
+ /* @__PURE__ */ jsx13("div", { className: "vos-detail-k", children: register === "readings" ? "Quote" : "Narrative" }),
4273
+ /* @__PURE__ */ jsx13(Markdown, { text: record.body })
4274
+ ] }) : null,
4275
+ register === "readings" ? /* @__PURE__ */ jsxs12("section", { className: "vos-record-prose", children: [
4276
+ /* @__PURE__ */ jsx13("div", { className: "vos-detail-k", children: "Per-belief verdicts" }),
4277
+ /* @__PURE__ */ jsx13(
4278
+ BeliefVerdicts,
4279
+ {
4280
+ reading: record,
4281
+ assumptions: related?.assumptions ?? [],
4282
+ onOpenRecord
4283
+ }
4284
+ )
4285
+ ] }) : null
4286
+ ] })
3594
4287
  ] }) }),
3595
4288
  record && !loading && !error && !editing ? children : null,
3596
- record && editing ? /* @__PURE__ */ jsxs11("footer", { className: "vos-drawer-footer", children: [
3597
- /* @__PURE__ */ jsx11(
4289
+ record && editing ? /* @__PURE__ */ jsxs12("footer", { className: "vos-drawer-footer", children: [
4290
+ /* @__PURE__ */ jsx13(
3598
4291
  "button",
3599
4292
  {
3600
4293
  type: "button",
@@ -3604,17 +4297,18 @@ function RecordDrawer({
3604
4297
  children: "Cancel"
3605
4298
  }
3606
4299
  ),
3607
- /* @__PURE__ */ jsx11(
4300
+ /* @__PURE__ */ jsx13(
3608
4301
  "button",
3609
4302
  {
3610
4303
  type: "button",
3611
4304
  onClick: onSave,
3612
- disabled: saving,
4305
+ disabled: saving || hasErrors,
4306
+ title: hasErrors ? "Fix the highlighted field before saving" : void 0,
3613
4307
  className: "vos-btn vos-btn-sm",
3614
4308
  children: saving ? "Saving\u2026" : "Save"
3615
4309
  }
3616
4310
  )
3617
- ] }) : record ? /* @__PURE__ */ jsxs11("footer", { className: "vos-drawer-footer", children: [
4311
+ ] }) : record ? /* @__PURE__ */ jsxs12("footer", { className: "vos-drawer-footer", children: [
3618
4312
  record.id,
3619
4313
  " \xB7 updated ",
3620
4314
  formatValue(record.updatedAt)
@@ -3623,6 +4317,56 @@ function RecordDrawer({
3623
4317
  }
3624
4318
  );
3625
4319
  }
4320
+ function DetailRowView({
4321
+ row,
4322
+ onOpenRecord
4323
+ }) {
4324
+ return /* @__PURE__ */ jsxs12("div", { className: "vos-detail-row", children: [
4325
+ /* @__PURE__ */ jsx13("span", { className: "vos-detail-k", children: row.label }),
4326
+ /* @__PURE__ */ jsx13("span", { className: "vos-detail-v", children: row.kind === "relation" ? row.items && row.items.length ? /* @__PURE__ */ jsx13(RelationLinks, { items: row.items, onOpenRecord }) : "\u2014" : row.kind === "owner" ? row.names && row.names.length ? row.names.join(", ") : "\u2014" : row.kind === "bar-lines" ? row.bars && row.bars.length ? /* @__PURE__ */ jsx13("ul", { className: "vos-bars", children: row.bars.map((b, i) => /* @__PURE__ */ jsxs12("li", { className: "vos-bar-line", children: [
4327
+ /* @__PURE__ */ jsx13("span", { className: "vos-bar-if", children: b.rightIf || "\u2014" }),
4328
+ b.assumption ? /* @__PURE__ */ jsx13(
4329
+ InlineLink,
4330
+ {
4331
+ id: b.assumption.id,
4332
+ title: b.assumption.title,
4333
+ onOpenRecord
4334
+ }
4335
+ ) : null,
4336
+ /* @__PURE__ */ jsx13(
4337
+ "span",
4338
+ {
4339
+ className: b.barVerdict ? "vos-pill vos-pill-good" : "vos-pill vos-pill-neutral",
4340
+ children: b.barVerdict ?? "open"
4341
+ }
4342
+ )
4343
+ ] }, i)) }) : "\u2014" : row.text })
4344
+ ] });
4345
+ }
4346
+ function RelationLinks({
4347
+ items,
4348
+ onOpenRecord
4349
+ }) {
4350
+ return /* @__PURE__ */ jsx13("span", { className: "vos-detail-links", children: items.map((item, i) => /* @__PURE__ */ jsxs12("span", { children: [
4351
+ i > 0 ? ", " : null,
4352
+ /* @__PURE__ */ jsx13(InlineLink, { id: item.id, title: item.title, onOpenRecord })
4353
+ ] }, item.id)) });
4354
+ }
4355
+ function InlineLink({
4356
+ id,
4357
+ title,
4358
+ onOpenRecord
4359
+ }) {
4360
+ return onOpenRecord ? /* @__PURE__ */ jsx13(
4361
+ "button",
4362
+ {
4363
+ type: "button",
4364
+ className: "vos-inline-link",
4365
+ onClick: () => onOpenRecord(id),
4366
+ children: title
4367
+ }
4368
+ ) : /* @__PURE__ */ jsx13("span", { children: title });
4369
+ }
3626
4370
  function DerivedCell({
3627
4371
  field,
3628
4372
  value,
@@ -3637,10 +4381,10 @@ function DerivedCell({
3637
4381
  toneClass = heroToneClass(derivedTone(field, num3));
3638
4382
  display = field === "confidence" ? formatSigned(num3) : String(Math.round(num3));
3639
4383
  }
3640
- return /* @__PURE__ */ jsxs11("div", { className: "vos-dcell", children: [
3641
- /* @__PURE__ */ jsxs11("div", { className: "vos-dcell-k", children: [
4384
+ return /* @__PURE__ */ jsxs12("div", { className: "vos-dcell", children: [
4385
+ /* @__PURE__ */ jsxs12("div", { className: "vos-dcell-k", children: [
3642
4386
  derivedLabel(field),
3643
- showWhy ? /* @__PURE__ */ jsxs11(
4387
+ showWhy ? /* @__PURE__ */ jsxs12(
3644
4388
  "button",
3645
4389
  {
3646
4390
  type: "button",
@@ -3654,17 +4398,17 @@ function DerivedCell({
3654
4398
  }
3655
4399
  ) : null
3656
4400
  ] }),
3657
- /* @__PURE__ */ jsx11("div", { className: `vos-dcell-v ${toneClass}`, children: display }),
3658
- DERIVED_SUB[field] ? /* @__PURE__ */ jsx11("div", { className: "vos-dcell-sub", children: DERIVED_SUB[field] }) : null
4401
+ /* @__PURE__ */ jsx13("div", { className: `vos-dcell-v ${toneClass}`, children: display }),
4402
+ DERIVED_SUB[field] ? /* @__PURE__ */ jsx13("div", { className: "vos-dcell-sub", children: DERIVED_SUB[field] }) : null
3659
4403
  ] });
3660
4404
  }
3661
- function ConflictBanner({
4405
+ function ConflictBanner2({
3662
4406
  message,
3663
4407
  onReload
3664
4408
  }) {
3665
- return /* @__PURE__ */ jsxs11("div", { role: "alert", className: "vos-banner vos-banner-warn", children: [
3666
- /* @__PURE__ */ jsx11("div", { className: "vos-banner-body", children: /* @__PURE__ */ jsx11("span", { children: message }) }),
3667
- /* @__PURE__ */ jsx11("button", { type: "button", onClick: onReload, children: "Review the latest" })
4409
+ return /* @__PURE__ */ jsxs12("div", { role: "alert", className: "vos-banner vos-banner-warn", children: [
4410
+ /* @__PURE__ */ jsx13("div", { className: "vos-banner-body", children: /* @__PURE__ */ jsx13("span", { children: message }) }),
4411
+ /* @__PURE__ */ jsx13("button", { type: "button", onClick: onReload, children: "Review the latest" })
3668
4412
  ] });
3669
4413
  }
3670
4414
 
@@ -3672,20 +4416,13 @@ function ConflictBanner({
3672
4416
  import { useMemo as useMemo2, useState as useState7 } from "react";
3673
4417
 
3674
4418
  // src/form-fields.ts
3675
- import {
3676
- MARKET_RUNG_VALUES,
3677
- TESTING_RUNGS
3678
- } from "@validation-os/core";
3679
4419
  var ASSUMPTION_STATUS = ["Draft", "Live", "Invalidated"];
3680
4420
  var EXPERIMENT_STATUS = ["Draft", "Running", "Closed"];
3681
4421
  var CLOSURE_REASON = ["Completed", "Early-stop", "Kill"];
3682
4422
  var EXPERIMENT_OUTCOME = ["Achieved", "Missed", "Dropped"];
3683
4423
  var DECISION_STATUS2 = ["Active", "Provisional", "Superseded", "Reversed"];
3684
4424
  var GLOSSARY_STATUS = ["Active", "Provisional", "Superseded"];
3685
- var RESULT = ["Validated", "Invalidated", "Inconclusive"];
3686
- var MAGNITUDE = ["Low", "Typical", "High"];
3687
4425
  var FEASIBILITY = ["High", "Medium", "Low"];
3688
- var RUNGS = [...TESTING_RUNGS, ...MARKET_RUNG_VALUES];
3689
4426
  var QUALITY = ["1", "0.7", "0.5"];
3690
4427
  var FIELDS = {
3691
4428
  assumptions: [
@@ -3718,8 +4455,10 @@ var FIELDS = {
3718
4455
  readings: [
3719
4456
  { key: "Title", label: "Reading", kind: "text", required: true },
3720
4457
  { key: "Source", label: "Source", kind: "text" },
3721
- { key: "Rung", label: "Rung", kind: "select", options: RUNGS, required: true },
3722
- { key: "Result", label: "Result", kind: "select", options: RESULT, required: true },
4458
+ // Rung / Result / Magnitude band / Grading justification are PER BELIEF now
4459
+ // (OPS-1305) carried in `beliefs[]`, not on the row. They are omitted here
4460
+ // so the create form can never write a dead row-level field; grading a
4461
+ // reading's beliefs is a deferred follow-up (a `beliefs[]` editor).
3723
4462
  {
3724
4463
  key: "Representativeness",
3725
4464
  label: "Representativeness",
@@ -3734,17 +4473,7 @@ var FIELDS = {
3734
4473
  options: QUALITY,
3735
4474
  coerce: "number"
3736
4475
  },
3737
- {
3738
- key: "magnitudeBand",
3739
- label: "Magnitude band",
3740
- kind: "select",
3741
- options: MAGNITUDE
3742
- },
3743
- {
3744
- key: "Grading justification",
3745
- label: "Grading justification",
3746
- kind: "textarea"
3747
- },
4476
+ { key: "body", label: "Quote", kind: "textarea" },
3748
4477
  { key: "Date", label: "Date", kind: "text", placeholder: "YYYY-MM-DD" }
3749
4478
  ],
3750
4479
  decisions: [
@@ -3786,7 +4515,7 @@ function toCreatePayload(register, draft) {
3786
4515
  }
3787
4516
 
3788
4517
  // src/record-form.tsx
3789
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
4518
+ import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
3790
4519
  function RecordForm({
3791
4520
  register,
3792
4521
  basePath,
@@ -3809,9 +4538,9 @@ function RecordForm({
3809
4538
  } catch {
3810
4539
  }
3811
4540
  };
3812
- return /* @__PURE__ */ jsxs12("form", { onSubmit, className: "vos-form", children: [
3813
- /* @__PURE__ */ jsxs12("div", { className: "vos-form-body", children: [
3814
- fields.map((field) => /* @__PURE__ */ jsx12(
4541
+ return /* @__PURE__ */ jsxs13("form", { onSubmit, className: "vos-form", children: [
4542
+ /* @__PURE__ */ jsxs13("div", { className: "vos-form-body", children: [
4543
+ fields.map((field) => /* @__PURE__ */ jsx14(
3815
4544
  Field,
3816
4545
  {
3817
4546
  field,
@@ -3820,11 +4549,11 @@ function RecordForm({
3820
4549
  },
3821
4550
  field.key
3822
4551
  )),
3823
- error ? /* @__PURE__ */ jsx12("p", { className: "vos-error", children: error }) : null
4552
+ error ? /* @__PURE__ */ jsx14("p", { className: "vos-error", children: error }) : null
3824
4553
  ] }),
3825
- /* @__PURE__ */ jsxs12("footer", { className: "vos-drawer-footer", children: [
3826
- /* @__PURE__ */ jsx12("button", { type: "button", onClick: onCancel, className: "vos-btn vos-btn-ghost vos-btn-sm", children: "Cancel" }),
3827
- /* @__PURE__ */ jsx12(
4554
+ /* @__PURE__ */ jsxs13("footer", { className: "vos-drawer-footer", children: [
4555
+ /* @__PURE__ */ jsx14("button", { type: "button", onClick: onCancel, className: "vos-btn vos-btn-ghost vos-btn-sm", children: "Cancel" }),
4556
+ /* @__PURE__ */ jsx14(
3828
4557
  "button",
3829
4558
  {
3830
4559
  type: "submit",
@@ -3843,12 +4572,12 @@ function Field({
3843
4572
  onChange
3844
4573
  }) {
3845
4574
  const id = `field-${field.key}`;
3846
- return /* @__PURE__ */ jsxs12("div", { className: "vos-field", children: [
3847
- /* @__PURE__ */ jsxs12("label", { htmlFor: id, className: FIELD_LABEL_CLASS, children: [
4575
+ return /* @__PURE__ */ jsxs13("div", { className: "vos-field", children: [
4576
+ /* @__PURE__ */ jsxs13("label", { htmlFor: id, className: FIELD_LABEL_CLASS, children: [
3848
4577
  field.label,
3849
- field.required ? /* @__PURE__ */ jsx12("span", { className: "vos-req", children: " *" }) : null
4578
+ field.required ? /* @__PURE__ */ jsx14("span", { className: "vos-req", children: " *" }) : null
3850
4579
  ] }),
3851
- field.kind === "textarea" ? /* @__PURE__ */ jsx12(
4580
+ field.kind === "textarea" ? /* @__PURE__ */ jsx14(
3852
4581
  "textarea",
3853
4582
  {
3854
4583
  id,
@@ -3858,7 +4587,7 @@ function Field({
3858
4587
  onChange: (e) => onChange(e.target.value),
3859
4588
  className: FIELD_CONTROL_CLASS
3860
4589
  }
3861
- ) : field.kind === "select" ? /* @__PURE__ */ jsxs12(
4590
+ ) : field.kind === "select" ? /* @__PURE__ */ jsxs13(
3862
4591
  "select",
3863
4592
  {
3864
4593
  id,
@@ -3866,11 +4595,11 @@ function Field({
3866
4595
  onChange: (e) => onChange(e.target.value),
3867
4596
  className: FIELD_CONTROL_CLASS,
3868
4597
  children: [
3869
- /* @__PURE__ */ jsx12("option", { value: "", children: "\u2014" }),
3870
- field.options?.map((opt) => /* @__PURE__ */ jsx12("option", { value: opt, children: opt }, opt))
4598
+ /* @__PURE__ */ jsx14("option", { value: "", children: "\u2014" }),
4599
+ field.options?.map((opt) => /* @__PURE__ */ jsx14("option", { value: opt, children: opt }, opt))
3871
4600
  ]
3872
4601
  }
3873
- ) : /* @__PURE__ */ jsx12(
4602
+ ) : /* @__PURE__ */ jsx14(
3874
4603
  "input",
3875
4604
  {
3876
4605
  id,
@@ -3906,7 +4635,7 @@ function linkChoicesFrom(register) {
3906
4635
  }
3907
4636
 
3908
4637
  // src/relation-editor.tsx
3909
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
4638
+ import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
3910
4639
  function RelationEditor({
3911
4640
  register,
3912
4641
  recordId,
@@ -3940,10 +4669,10 @@ function RelationEditor({
3940
4669
  } catch {
3941
4670
  }
3942
4671
  };
3943
- return /* @__PURE__ */ jsxs13("section", { className: "vos-relation", children: [
3944
- /* @__PURE__ */ jsx13("h3", { className: "vos-sectitle", children: "Link a record" }),
3945
- /* @__PURE__ */ jsxs13("div", { className: "vos-field-stack", children: [
3946
- /* @__PURE__ */ jsxs13(
4672
+ return /* @__PURE__ */ jsxs14("section", { className: "vos-relation", children: [
4673
+ /* @__PURE__ */ jsx15("h3", { className: "vos-sectitle", children: "Link a record" }),
4674
+ /* @__PURE__ */ jsxs14("div", { className: "vos-field-stack", children: [
4675
+ /* @__PURE__ */ jsxs14(
3947
4676
  "select",
3948
4677
  {
3949
4678
  "aria-label": "Relation",
@@ -3954,12 +4683,12 @@ function RelationEditor({
3954
4683
  },
3955
4684
  className: FIELD_CONTROL_CLASS,
3956
4685
  children: [
3957
- /* @__PURE__ */ jsx13("option", { value: "", children: "Choose a relation\u2026" }),
3958
- choices.map((c) => /* @__PURE__ */ jsx13("option", { value: c.relation, children: c.label }, c.relation))
4686
+ /* @__PURE__ */ jsx15("option", { value: "", children: "Choose a relation\u2026" }),
4687
+ choices.map((c) => /* @__PURE__ */ jsx15("option", { value: c.relation, children: c.label }, c.relation))
3959
4688
  ]
3960
4689
  }
3961
4690
  ),
3962
- active ? /* @__PURE__ */ jsxs13(
4691
+ active ? /* @__PURE__ */ jsxs14(
3963
4692
  "select",
3964
4693
  {
3965
4694
  "aria-label": "Target record",
@@ -3967,13 +4696,13 @@ function RelationEditor({
3967
4696
  onChange: (e) => setTargetId(e.target.value),
3968
4697
  className: FIELD_CONTROL_CLASS,
3969
4698
  children: [
3970
- /* @__PURE__ */ jsx13("option", { value: "", children: "Choose a record\u2026" }),
3971
- targets.map((r) => /* @__PURE__ */ jsx13("option", { value: r.id, children: primaryLabel(r) }, r.id))
4699
+ /* @__PURE__ */ jsx15("option", { value: "", children: "Choose a record\u2026" }),
4700
+ targets.map((r) => /* @__PURE__ */ jsx15("option", { value: r.id, children: primaryLabel(r) }, r.id))
3972
4701
  ]
3973
4702
  }
3974
4703
  ) : null,
3975
- error ? /* @__PURE__ */ jsx13("p", { className: "vos-error", children: error }) : null,
3976
- /* @__PURE__ */ jsx13(
4704
+ error ? /* @__PURE__ */ jsx15("p", { className: "vos-error", children: error }) : null,
4705
+ /* @__PURE__ */ jsx15(
3977
4706
  "button",
3978
4707
  {
3979
4708
  type: "button",
@@ -4040,12 +4769,12 @@ function useSavedViews(register) {
4040
4769
  }
4041
4770
 
4042
4771
  // src/register-browser.tsx
4043
- import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
4772
+ import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
4044
4773
  function contextNeeds(register) {
4045
4774
  return {
4046
4775
  experiments: register === "assumptions" || register === "readings",
4047
4776
  readings: register === "assumptions",
4048
- assumptions: register === "decisions"
4777
+ assumptions: register === "decisions" || register === "experiments" || register === "readings"
4049
4778
  };
4050
4779
  }
4051
4780
  function RegisterBrowser({
@@ -4098,6 +4827,15 @@ function RegisterBrowser({
4098
4827
  const n = humanCount[tab.id] ?? 0;
4099
4828
  return n > 0 ? n : null;
4100
4829
  };
4830
+ const related = {
4831
+ assumptions: ctx.assumptions,
4832
+ experiments: ctx.experiments,
4833
+ readings: ctx.readings,
4834
+ decisions: ctx.decisions
4835
+ };
4836
+ const assumptionTitles = new Map(
4837
+ (ctx.assumptions ?? []).map((a) => [a.id, primaryLabel(a)])
4838
+ );
4101
4839
  const patch = (p) => setDescriptor((d) => ({ ...d, ...p }));
4102
4840
  const saveCurrentView = () => {
4103
4841
  if (typeof window === "undefined") return;
@@ -4109,14 +4847,14 @@ function RegisterBrowser({
4109
4847
  void _name;
4110
4848
  setDescriptor(rest);
4111
4849
  };
4112
- return /* @__PURE__ */ jsxs14("div", { children: [
4113
- /* @__PURE__ */ jsxs14("div", { className: "vos-head", children: [
4114
- /* @__PURE__ */ jsxs14("div", { children: [
4115
- /* @__PURE__ */ jsx14("h1", { children: REGISTER_LABEL[register] }),
4116
- subtitle ? /* @__PURE__ */ jsx14("p", { children: subtitle }) : null
4850
+ return /* @__PURE__ */ jsxs15("div", { children: [
4851
+ /* @__PURE__ */ jsxs15("div", { className: "vos-head", children: [
4852
+ /* @__PURE__ */ jsxs15("div", { children: [
4853
+ /* @__PURE__ */ jsx16("h1", { children: REGISTER_LABEL[register] }),
4854
+ subtitle ? /* @__PURE__ */ jsx16("p", { children: subtitle }) : null
4117
4855
  ] }),
4118
- /* @__PURE__ */ jsx14("div", { className: "vos-spacer" }),
4119
- /* @__PURE__ */ jsx14(
4856
+ /* @__PURE__ */ jsx16("div", { className: "vos-spacer" }),
4857
+ /* @__PURE__ */ jsx16(
4120
4858
  "button",
4121
4859
  {
4122
4860
  type: "button",
@@ -4125,7 +4863,7 @@ function RegisterBrowser({
4125
4863
  children: "\u21BB Refresh"
4126
4864
  }
4127
4865
  ),
4128
- /* @__PURE__ */ jsxs14(
4866
+ /* @__PURE__ */ jsxs15(
4129
4867
  "button",
4130
4868
  {
4131
4869
  type: "button",
@@ -4138,10 +4876,10 @@ function RegisterBrowser({
4138
4876
  }
4139
4877
  )
4140
4878
  ] }),
4141
- /* @__PURE__ */ jsx14("div", { className: "vos-tabs", role: "tablist", "aria-label": "Views", children: shaped.tabs.map((tab) => {
4879
+ /* @__PURE__ */ jsx16("div", { className: "vos-tabs", role: "tablist", "aria-label": "Views", children: shaped.tabs.map((tab) => {
4142
4880
  const active = tab.id === shaped.activeTabId;
4143
4881
  const badge = badgeFor(tab);
4144
- return /* @__PURE__ */ jsxs14(
4882
+ return /* @__PURE__ */ jsxs15(
4145
4883
  "button",
4146
4884
  {
4147
4885
  type: "button",
@@ -4151,13 +4889,13 @@ function RegisterBrowser({
4151
4889
  onClick: () => patch({ tabId: tab.id }),
4152
4890
  children: [
4153
4891
  tab.label,
4154
- badge !== null ? /* @__PURE__ */ jsx14("span", { className: "vos-tab-badge", children: badge }) : null
4892
+ badge !== null ? /* @__PURE__ */ jsx16("span", { className: "vos-tab-badge", children: badge }) : null
4155
4893
  ]
4156
4894
  },
4157
4895
  tab.id
4158
4896
  );
4159
4897
  }) }),
4160
- /* @__PURE__ */ jsx14(
4898
+ /* @__PURE__ */ jsx16(
4161
4899
  ViewControls,
4162
4900
  {
4163
4901
  register,
@@ -4168,10 +4906,10 @@ function RegisterBrowser({
4168
4906
  onQuery: (query) => patch({ query })
4169
4907
  }
4170
4908
  ),
4171
- /* @__PURE__ */ jsxs14("div", { className: "vos-saved-views", children: [
4172
- /* @__PURE__ */ jsx14("span", { className: "vos-saved-label", children: "Saved views" }),
4173
- savedViews.views.length === 0 ? /* @__PURE__ */ jsx14("span", { className: "vos-hint", children: "none yet" }) : savedViews.views.map((v) => /* @__PURE__ */ jsxs14("span", { className: "vos-saved-view", children: [
4174
- /* @__PURE__ */ jsx14(
4909
+ /* @__PURE__ */ jsxs15("div", { className: "vos-saved-views", children: [
4910
+ /* @__PURE__ */ jsx16("span", { className: "vos-saved-label", children: "Saved views" }),
4911
+ savedViews.views.length === 0 ? /* @__PURE__ */ jsx16("span", { className: "vos-hint", children: "none yet" }) : savedViews.views.map((v) => /* @__PURE__ */ jsxs15("span", { className: "vos-saved-view", children: [
4912
+ /* @__PURE__ */ jsx16(
4175
4913
  "button",
4176
4914
  {
4177
4915
  type: "button",
@@ -4180,7 +4918,7 @@ function RegisterBrowser({
4180
4918
  children: v.name
4181
4919
  }
4182
4920
  ),
4183
- /* @__PURE__ */ jsx14(
4921
+ /* @__PURE__ */ jsx16(
4184
4922
  "button",
4185
4923
  {
4186
4924
  type: "button",
@@ -4191,7 +4929,7 @@ function RegisterBrowser({
4191
4929
  }
4192
4930
  )
4193
4931
  ] }, v.name)),
4194
- /* @__PURE__ */ jsx14(
4932
+ /* @__PURE__ */ jsx16(
4195
4933
  "button",
4196
4934
  {
4197
4935
  type: "button",
@@ -4201,20 +4939,21 @@ function RegisterBrowser({
4201
4939
  }
4202
4940
  )
4203
4941
  ] }),
4204
- loading && !records ? /* @__PURE__ */ jsxs14("p", { className: "vos-muted", children: [
4942
+ loading && !records ? /* @__PURE__ */ jsxs15("p", { className: "vos-muted", children: [
4205
4943
  "Loading ",
4206
4944
  REGISTER_LABEL[register].toLowerCase(),
4207
4945
  "\u2026"
4208
- ] }) : error ? /* @__PURE__ */ jsx14("p", { className: "vos-error", children: error }) : /* @__PURE__ */ jsx14(
4946
+ ] }) : error ? /* @__PURE__ */ jsx16("p", { className: "vos-error", children: error }) : /* @__PURE__ */ jsx16(
4209
4947
  ShapedBody,
4210
4948
  {
4211
4949
  register,
4212
4950
  shaped,
4213
4951
  onRowClick: setOpenId,
4214
- selectedId: openId
4952
+ selectedId: openId,
4953
+ assumptionTitles
4215
4954
  }
4216
4955
  ),
4217
- /* @__PURE__ */ jsx14(
4956
+ /* @__PURE__ */ jsx16(
4218
4957
  RecordDrawer,
4219
4958
  {
4220
4959
  register,
@@ -4225,11 +4964,13 @@ function RegisterBrowser({
4225
4964
  onClose: () => setOpenId(null),
4226
4965
  basePath,
4227
4966
  onOpenFull: onOpenRecord && openId ? () => onOpenRecord(openId) : void 0,
4967
+ onOpenRecord,
4968
+ related,
4228
4969
  onChanged: () => {
4229
4970
  refreshRecord();
4230
4971
  refreshList();
4231
4972
  },
4232
- children: openId ? /* @__PURE__ */ jsx14(
4973
+ children: openId ? /* @__PURE__ */ jsx16(
4233
4974
  RelationEditor,
4234
4975
  {
4235
4976
  register,
@@ -4243,18 +4984,18 @@ function RegisterBrowser({
4243
4984
  ) : null
4244
4985
  }
4245
4986
  ),
4246
- /* @__PURE__ */ jsxs14(
4987
+ /* @__PURE__ */ jsxs15(
4247
4988
  DrawerShell,
4248
4989
  {
4249
4990
  open: creating,
4250
4991
  onClose: () => setCreating(false),
4251
4992
  ariaLabel: `New ${REGISTER_SINGULAR[register]} record`,
4252
4993
  children: [
4253
- /* @__PURE__ */ jsx14("header", { className: "vos-drawer-header", children: /* @__PURE__ */ jsxs14("div", { children: [
4254
- /* @__PURE__ */ jsx14("p", { className: "vos-drawer-eyebrow", children: "New" }),
4255
- /* @__PURE__ */ jsx14("h2", { className: "vos-drawer-title", children: REGISTER_SINGULAR[register] })
4994
+ /* @__PURE__ */ jsx16("header", { className: "vos-drawer-header", children: /* @__PURE__ */ jsxs15("div", { children: [
4995
+ /* @__PURE__ */ jsx16("p", { className: "vos-drawer-eyebrow", children: "New" }),
4996
+ /* @__PURE__ */ jsx16("h2", { className: "vos-drawer-title", children: REGISTER_SINGULAR[register] })
4256
4997
  ] }) }),
4257
- /* @__PURE__ */ jsx14(
4998
+ /* @__PURE__ */ jsx16(
4258
4999
  RecordForm,
4259
5000
  {
4260
5001
  register,
@@ -4282,8 +5023,8 @@ function ViewControls({
4282
5023
  }) {
4283
5024
  const sortable = columnsFor(register);
4284
5025
  const sort = descriptor.sort ?? null;
4285
- return /* @__PURE__ */ jsxs14("div", { className: "vos-view-controls", children: [
4286
- /* @__PURE__ */ jsx14(
5026
+ return /* @__PURE__ */ jsxs15("div", { className: "vos-view-controls", children: [
5027
+ /* @__PURE__ */ jsx16(
4287
5028
  "input",
4288
5029
  {
4289
5030
  type: "search",
@@ -4294,24 +5035,24 @@ function ViewControls({
4294
5035
  "aria-label": "Filter records"
4295
5036
  }
4296
5037
  ),
4297
- axes.length ? /* @__PURE__ */ jsxs14("label", { className: "vos-control", children: [
4298
- /* @__PURE__ */ jsx14("span", { children: "Group" }),
4299
- /* @__PURE__ */ jsxs14(
5038
+ axes.length ? /* @__PURE__ */ jsxs15("label", { className: "vos-control", children: [
5039
+ /* @__PURE__ */ jsx16("span", { children: "Group" }),
5040
+ /* @__PURE__ */ jsxs15(
4300
5041
  "select",
4301
5042
  {
4302
5043
  className: "vos-input",
4303
5044
  value: descriptor.groupBy ?? "",
4304
5045
  onChange: (e) => onGroupBy(e.target.value || null),
4305
5046
  children: [
4306
- /* @__PURE__ */ jsx14("option", { value: "", children: "None" }),
4307
- axes.map((axis) => /* @__PURE__ */ jsx14("option", { value: axis, children: axis }, axis))
5047
+ /* @__PURE__ */ jsx16("option", { value: "", children: "None" }),
5048
+ axes.map((axis) => /* @__PURE__ */ jsx16("option", { value: axis, children: axis }, axis))
4308
5049
  ]
4309
5050
  }
4310
5051
  )
4311
5052
  ] }) : null,
4312
- /* @__PURE__ */ jsxs14("label", { className: "vos-control", children: [
4313
- /* @__PURE__ */ jsx14("span", { children: "Sort" }),
4314
- /* @__PURE__ */ jsxs14(
5053
+ /* @__PURE__ */ jsxs15("label", { className: "vos-control", children: [
5054
+ /* @__PURE__ */ jsx16("span", { children: "Sort" }),
5055
+ /* @__PURE__ */ jsxs15(
4315
5056
  "select",
4316
5057
  {
4317
5058
  className: "vos-input",
@@ -4320,13 +5061,13 @@ function ViewControls({
4320
5061
  e.target.value ? { key: e.target.value, dir: sort?.dir ?? "desc" } : null
4321
5062
  ),
4322
5063
  children: [
4323
- /* @__PURE__ */ jsx14("option", { value: "", children: "Default" }),
4324
- sortable.map((c) => /* @__PURE__ */ jsx14("option", { value: c.key, children: c.header }, c.key))
5064
+ /* @__PURE__ */ jsx16("option", { value: "", children: "Default" }),
5065
+ sortable.map((c) => /* @__PURE__ */ jsx16("option", { value: c.key, children: c.header }, c.key))
4325
5066
  ]
4326
5067
  }
4327
5068
  )
4328
5069
  ] }),
4329
- sort ? /* @__PURE__ */ jsx14(
5070
+ sort ? /* @__PURE__ */ jsx16(
4330
5071
  "button",
4331
5072
  {
4332
5073
  type: "button",
@@ -4342,53 +5083,57 @@ function ShapedBody({
4342
5083
  register,
4343
5084
  shaped,
4344
5085
  onRowClick,
4345
- selectedId
5086
+ selectedId,
5087
+ assumptionTitles
4346
5088
  }) {
4347
5089
  if (shaped.nested) {
4348
5090
  if (shaped.nested.length === 0)
4349
- return /* @__PURE__ */ jsx14("p", { className: "vos-empty", children: "No readings in this view." });
4350
- return /* @__PURE__ */ jsx14("div", { className: "vos-groups", children: shaped.nested.map((group) => /* @__PURE__ */ jsxs14("section", { className: "vos-group", children: [
4351
- /* @__PURE__ */ jsxs14("h3", { className: "vos-group-head", children: [
5091
+ return /* @__PURE__ */ jsx16("p", { className: "vos-empty", children: "No readings in this view." });
5092
+ return /* @__PURE__ */ jsx16("div", { className: "vos-groups", children: shaped.nested.map((group) => /* @__PURE__ */ jsxs15("section", { className: "vos-group", children: [
5093
+ /* @__PURE__ */ jsxs15("h3", { className: "vos-group-head", children: [
4352
5094
  group.label,
4353
- /* @__PURE__ */ jsx14("span", { className: "vos-group-n", children: group.readings.length })
5095
+ /* @__PURE__ */ jsx16("span", { className: "vos-group-n", children: group.readings.length })
4354
5096
  ] }),
4355
- /* @__PURE__ */ jsx14(
5097
+ /* @__PURE__ */ jsx16(
4356
5098
  RegisterTable,
4357
5099
  {
4358
5100
  register,
4359
5101
  records: group.readings,
4360
5102
  onRowClick,
4361
- selectedId
5103
+ selectedId,
5104
+ assumptionTitles
4362
5105
  }
4363
5106
  )
4364
5107
  ] }, group.experimentId ?? "__none__")) });
4365
5108
  }
4366
5109
  if (shaped.groups) {
4367
5110
  if (shaped.groups.length === 0)
4368
- return /* @__PURE__ */ jsx14("p", { className: "vos-empty", children: "No records in this view." });
4369
- return /* @__PURE__ */ jsx14("div", { className: "vos-groups", children: shaped.groups.map((group) => /* @__PURE__ */ jsxs14("section", { className: "vos-group", children: [
4370
- /* @__PURE__ */ jsxs14("h3", { className: "vos-group-head", children: [
5111
+ return /* @__PURE__ */ jsx16("p", { className: "vos-empty", children: "No records in this view." });
5112
+ return /* @__PURE__ */ jsx16("div", { className: "vos-groups", children: shaped.groups.map((group) => /* @__PURE__ */ jsxs15("section", { className: "vos-group", children: [
5113
+ /* @__PURE__ */ jsxs15("h3", { className: "vos-group-head", children: [
4371
5114
  group.label,
4372
- /* @__PURE__ */ jsx14("span", { className: "vos-group-n", children: group.records.length })
5115
+ /* @__PURE__ */ jsx16("span", { className: "vos-group-n", children: group.records.length })
4373
5116
  ] }),
4374
- /* @__PURE__ */ jsx14(
5117
+ /* @__PURE__ */ jsx16(
4375
5118
  RegisterTable,
4376
5119
  {
4377
5120
  register,
4378
5121
  records: group.records,
4379
5122
  onRowClick,
4380
- selectedId
5123
+ selectedId,
5124
+ assumptionTitles
4381
5125
  }
4382
5126
  )
4383
5127
  ] }, group.key)) });
4384
5128
  }
4385
- return /* @__PURE__ */ jsx14(
5129
+ return /* @__PURE__ */ jsx16(
4386
5130
  RegisterTable,
4387
5131
  {
4388
5132
  register,
4389
5133
  records: shaped.rows,
4390
5134
  onRowClick,
4391
- selectedId
5135
+ selectedId,
5136
+ assumptionTitles
4392
5137
  }
4393
5138
  );
4394
5139
  }
@@ -4396,7 +5141,7 @@ function ShapedBody({
4396
5141
  // src/next-move-surface.tsx
4397
5142
  import { useMemo as useMemo5, useState as useState11 } from "react";
4398
5143
  import { rankNextMoves as rankNextMoves2 } from "@validation-os/core/derivation";
4399
- import { Fragment as Fragment10, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
5144
+ import { Fragment as Fragment10, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
4400
5145
  var STAGES = ["Framed", "Planned", "Tested", "Known"];
4401
5146
  var MOVE_STAGE = {
4402
5147
  "score-impact": 0,
@@ -4454,12 +5199,12 @@ function NextMoveSurface({ basePath, onNavigate }) {
4454
5199
  });
4455
5200
  };
4456
5201
  if (loading) {
4457
- return /* @__PURE__ */ jsx15(NextMoveFrame, { children: /* @__PURE__ */ jsx15("div", { className: "vos-empty", children: "Reading your beliefs\u2026" }) });
5202
+ return /* @__PURE__ */ jsx17(NextMoveFrame, { children: /* @__PURE__ */ jsx17("div", { className: "vos-empty", children: "Reading your beliefs\u2026" }) });
4458
5203
  }
4459
5204
  if (error) {
4460
- return /* @__PURE__ */ jsx15(NextMoveFrame, { children: /* @__PURE__ */ jsx15("div", { className: "vos-banner vos-banner-crit", children: /* @__PURE__ */ jsxs15("div", { className: "vos-banner-body", children: [
4461
- /* @__PURE__ */ jsx15("b", { children: "Couldn't load the workflow." }),
4462
- /* @__PURE__ */ jsx15("span", { children: error })
5205
+ return /* @__PURE__ */ jsx17(NextMoveFrame, { children: /* @__PURE__ */ jsx17("div", { className: "vos-banner vos-banner-crit", children: /* @__PURE__ */ jsxs16("div", { className: "vos-banner-body", children: [
5206
+ /* @__PURE__ */ jsx17("b", { children: "Couldn't load the workflow." }),
5207
+ /* @__PURE__ */ jsx17("span", { children: error })
4463
5208
  ] }) }) });
4464
5209
  }
4465
5210
  if (moves.length === 0) {
@@ -4471,13 +5216,13 @@ function NextMoveSurface({ basePath, onNavigate }) {
4471
5216
  };
4472
5217
  const cold = coldStartFor(records);
4473
5218
  if (cold.cold) {
4474
- return /* @__PURE__ */ jsxs15(NextMoveFrame, { children: [
4475
- /* @__PURE__ */ jsx15("div", { className: "vos-firstrun", children: FIRST_RUN_LINE }),
4476
- /* @__PURE__ */ jsxs15("div", { className: "vos-card vos-cold vos-cold-next", children: [
4477
- /* @__PURE__ */ jsx15("span", { className: "vos-cold-eyebrow", children: cold.next.eyebrow }),
4478
- /* @__PURE__ */ jsx15("h2", { className: "vos-cold-headline", children: cold.next.headline }),
4479
- /* @__PURE__ */ jsx15("p", { className: "vos-cold-body", children: cold.next.body }),
4480
- /* @__PURE__ */ jsx15(
5219
+ return /* @__PURE__ */ jsxs16(NextMoveFrame, { children: [
5220
+ /* @__PURE__ */ jsx17("div", { className: "vos-firstrun", children: FIRST_RUN_LINE }),
5221
+ /* @__PURE__ */ jsxs16("div", { className: "vos-card vos-cold vos-cold-next", children: [
5222
+ /* @__PURE__ */ jsx17("span", { className: "vos-cold-eyebrow", children: cold.next.eyebrow }),
5223
+ /* @__PURE__ */ jsx17("h2", { className: "vos-cold-headline", children: cold.next.headline }),
5224
+ /* @__PURE__ */ jsx17("p", { className: "vos-cold-body", children: cold.next.body }),
5225
+ /* @__PURE__ */ jsx17(
4481
5226
  "button",
4482
5227
  {
4483
5228
  type: "button",
@@ -4489,10 +5234,10 @@ function NextMoveSurface({ basePath, onNavigate }) {
4489
5234
  ] })
4490
5235
  ] });
4491
5236
  }
4492
- return /* @__PURE__ */ jsx15(NextMoveFrame, { children: /* @__PURE__ */ jsxs15("div", { className: "vos-empty", children: [
5237
+ return /* @__PURE__ */ jsx17(NextMoveFrame, { children: /* @__PURE__ */ jsxs16("div", { className: "vos-empty", children: [
4493
5238
  "Nothing needs your attention right now \u2014 every belief is either resting on a decision or waiting on a test. Add a new belief from",
4494
5239
  " ",
4495
- /* @__PURE__ */ jsx15(
5240
+ /* @__PURE__ */ jsx17(
4496
5241
  "button",
4497
5242
  {
4498
5243
  type: "button",
@@ -4510,11 +5255,11 @@ function NextMoveSurface({ basePath, onNavigate }) {
4510
5255
  const onDeck = rest.filter((m) => m.assumptionId !== top.assumptionId).slice(0, 3);
4511
5256
  const topPres = movePresentation(top.move);
4512
5257
  const topTone = riskLevel(top.risk);
4513
- return /* @__PURE__ */ jsxs15(NextMoveFrame, { children: [
4514
- killMoves.length > 0 && !top.killLane ? /* @__PURE__ */ jsx15(KillBanner, { count: killMoves.length, onReview: () => startStepIn(killMoves[0]) }) : null,
4515
- /* @__PURE__ */ jsxs15("div", { className: `vos-hero vos-card${top.killLane ? " vos-hero-kill" : ""}`, children: [
4516
- /* @__PURE__ */ jsx15("span", { className: "vos-hero-eyebrow", children: top.killLane ? "Kill lane \u2014 turning against you" : "Your next move" }),
4517
- /* @__PURE__ */ jsx15(
5258
+ return /* @__PURE__ */ jsxs16(NextMoveFrame, { children: [
5259
+ killMoves.length > 0 && !top.killLane ? /* @__PURE__ */ jsx17(KillBanner, { count: killMoves.length, onReview: () => startStepIn(killMoves[0]) }) : null,
5260
+ /* @__PURE__ */ jsxs16("div", { className: `vos-hero vos-card${top.killLane ? " vos-hero-kill" : ""}`, children: [
5261
+ /* @__PURE__ */ jsx17("span", { className: "vos-hero-eyebrow", children: top.killLane ? "Kill lane \u2014 turning against you" : "Your next move" }),
5262
+ /* @__PURE__ */ jsx17(
4518
5263
  "button",
4519
5264
  {
4520
5265
  type: "button",
@@ -4524,23 +5269,23 @@ function NextMoveSurface({ basePath, onNavigate }) {
4524
5269
  children: top.title
4525
5270
  }
4526
5271
  ),
4527
- /* @__PURE__ */ jsxs15("div", { className: "vos-riskchip", "aria-label": `Risk: ${RISK_PHRASE[topTone]}`, children: [
4528
- /* @__PURE__ */ jsx15("span", { className: "vos-risk-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsx15(
5272
+ /* @__PURE__ */ jsxs16("div", { className: "vos-riskchip", "aria-label": `Risk: ${RISK_PHRASE[topTone]}`, children: [
5273
+ /* @__PURE__ */ jsx17("span", { className: "vos-risk-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsx17(
4529
5274
  "i",
4530
5275
  {
4531
5276
  className: `vos-fill-${topTone}`,
4532
5277
  style: { width: `${riskFraction(top.risk) * 100}%` }
4533
5278
  }
4534
5279
  ) }),
4535
- /* @__PURE__ */ jsx15("span", { className: `vos-riskchip-label vos-text-${topTone}`, children: top.killLane ? "Confidence has turned negative" : RISK_PHRASE[topTone] })
5280
+ /* @__PURE__ */ jsx17("span", { className: `vos-riskchip-label vos-text-${topTone}`, children: top.killLane ? "Confidence has turned negative" : RISK_PHRASE[topTone] })
4536
5281
  ] }),
4537
- /* @__PURE__ */ jsx15(ActButton, { move: top, onStepIn: () => startStepIn(top), onReview: () => openRecord(top.assumptionId) }),
4538
- /* @__PURE__ */ jsx15("button", { type: "button", className: "vos-why", onClick: () => setWhy((w) => !w), children: why ? "Hide details" : "Why this?" })
5282
+ /* @__PURE__ */ jsx17(ActButton, { move: top, onStepIn: () => startStepIn(top), onReview: () => openRecord(top.assumptionId) }),
5283
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "vos-why", onClick: () => setWhy((w) => !w), children: why ? "Hide details" : "Why this?" })
4539
5284
  ] }),
4540
- why ? /* @__PURE__ */ jsx15(WhyPanel, { top, ranked: moves }) : null,
4541
- onDeck.length > 0 ? /* @__PURE__ */ jsxs15("section", { className: "vos-ondeck", children: [
4542
- /* @__PURE__ */ jsx15("h3", { className: "vos-sectitle", children: "On deck" }),
4543
- onDeck.map((m) => /* @__PURE__ */ jsx15(
5285
+ why ? /* @__PURE__ */ jsx17(WhyPanel, { top, ranked: moves }) : null,
5286
+ onDeck.length > 0 ? /* @__PURE__ */ jsxs16("section", { className: "vos-ondeck", children: [
5287
+ /* @__PURE__ */ jsx17("h3", { className: "vos-sectitle", children: "On deck" }),
5288
+ onDeck.map((m) => /* @__PURE__ */ jsx17(
4544
5289
  OnDeckRow,
4545
5290
  {
4546
5291
  move: m,
@@ -4550,7 +5295,7 @@ function NextMoveSurface({ basePath, onNavigate }) {
4550
5295
  m.assumptionId
4551
5296
  ))
4552
5297
  ] }) : null,
4553
- /* @__PURE__ */ jsx15(
5298
+ /* @__PURE__ */ jsx17(
4554
5299
  "button",
4555
5300
  {
4556
5301
  type: "button",
@@ -4559,7 +5304,7 @@ function NextMoveSurface({ basePath, onNavigate }) {
4559
5304
  children: "Act on a different belief \u2192"
4560
5305
  }
4561
5306
  ),
4562
- stepIn?.form === "score-impact" ? /* @__PURE__ */ jsx15(
5307
+ stepIn?.form === "score-impact" ? /* @__PURE__ */ jsx17(
4563
5308
  ScoreImpactForm,
4564
5309
  {
4565
5310
  assumption: stepIn.assumption,
@@ -4571,7 +5316,7 @@ function NextMoveSurface({ basePath, onNavigate }) {
4571
5316
  onCancel: () => setStepIn(null)
4572
5317
  }
4573
5318
  ) : null,
4574
- stepIn?.form === "write-decision" ? /* @__PURE__ */ jsx15(
5319
+ stepIn?.form === "write-decision" ? /* @__PURE__ */ jsx17(
4575
5320
  WriteDecisionForm,
4576
5321
  {
4577
5322
  assumption: stepIn.assumption,
@@ -4587,12 +5332,12 @@ function NextMoveSurface({ basePath, onNavigate }) {
4587
5332
  ] });
4588
5333
  }
4589
5334
  function NextMoveFrame({ children }) {
4590
- return /* @__PURE__ */ jsxs15("div", { children: [
4591
- /* @__PURE__ */ jsx15("div", { className: "vos-head", children: /* @__PURE__ */ jsxs15("div", { children: [
4592
- /* @__PURE__ */ jsx15("h1", { children: "Next move" }),
4593
- /* @__PURE__ */ jsx15("p", { children: "The single next move to make \u2014 and what's on deck." })
5335
+ return /* @__PURE__ */ jsxs16("div", { children: [
5336
+ /* @__PURE__ */ jsx17("div", { className: "vos-head", children: /* @__PURE__ */ jsxs16("div", { children: [
5337
+ /* @__PURE__ */ jsx17("h1", { children: "Next move" }),
5338
+ /* @__PURE__ */ jsx17("p", { children: "The single next move to make \u2014 and what's on deck." })
4594
5339
  ] }) }),
4595
- /* @__PURE__ */ jsx15("div", { className: "vos-next", children })
5340
+ /* @__PURE__ */ jsx17("div", { className: "vos-next", children })
4596
5341
  ] });
4597
5342
  }
4598
5343
  function ActButton({
@@ -4602,20 +5347,20 @@ function ActButton({
4602
5347
  }) {
4603
5348
  const pres = movePresentation(move.move);
4604
5349
  if (pres.steppable) {
4605
- return /* @__PURE__ */ jsx15("button", { type: "button", className: "vos-btn vos-hero-act", onClick: onStepIn, children: pres.cta });
5350
+ return /* @__PURE__ */ jsx17("button", { type: "button", className: "vos-btn vos-hero-act", onClick: onStepIn, children: pres.cta });
4606
5351
  }
4607
- return /* @__PURE__ */ jsxs15("div", { className: "vos-hero-agent", children: [
4608
- /* @__PURE__ */ jsx15("span", { className: "vos-agent-note", children: "\u{1F916} Claude Code runs this off the dashboard" }),
4609
- /* @__PURE__ */ jsx15("button", { type: "button", className: "vos-btn vos-btn-ghost vos-hero-act", onClick: onReview, children: "Review on the record \u2192" })
5352
+ return /* @__PURE__ */ jsxs16("div", { className: "vos-hero-agent", children: [
5353
+ /* @__PURE__ */ jsx17("span", { className: "vos-agent-note", children: "\u{1F916} Claude Code runs this off the dashboard" }),
5354
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "vos-btn vos-btn-ghost vos-hero-act", onClick: onReview, children: "Review on the record \u2192" })
4610
5355
  ] });
4611
5356
  }
4612
5357
  function KillBanner({ count, onReview }) {
4613
- return /* @__PURE__ */ jsxs15("div", { className: "vos-banner vos-banner-crit", children: [
4614
- /* @__PURE__ */ jsxs15("div", { className: "vos-banner-body", children: [
4615
- /* @__PURE__ */ jsx15("b", { children: count === 1 ? "A belief has fallen into the kill lane" : `${count} beliefs have fallen into the kill lane` }),
4616
- /* @__PURE__ */ jsx15("span", { children: "Confidence \u2264 \u221250 \u2014 the evidence is against it. Kill it or test it again." })
5358
+ return /* @__PURE__ */ jsxs16("div", { className: "vos-banner vos-banner-crit", children: [
5359
+ /* @__PURE__ */ jsxs16("div", { className: "vos-banner-body", children: [
5360
+ /* @__PURE__ */ jsx17("b", { children: count === 1 ? "A belief has fallen into the kill lane" : `${count} beliefs have fallen into the kill lane` }),
5361
+ /* @__PURE__ */ jsx17("span", { children: "Confidence \u2264 \u221250 \u2014 the evidence is against it. Kill it or test it again." })
4617
5362
  ] }),
4618
- /* @__PURE__ */ jsx15("button", { type: "button", onClick: onReview, children: "Review" })
5363
+ /* @__PURE__ */ jsx17("button", { type: "button", onClick: onReview, children: "Review" })
4619
5364
  ] });
4620
5365
  }
4621
5366
  function OnDeckRow({
@@ -4625,47 +5370,47 @@ function OnDeckRow({
4625
5370
  }) {
4626
5371
  const pres = movePresentation(move.move);
4627
5372
  const tone = riskLevel(move.risk);
4628
- return /* @__PURE__ */ jsxs15("div", { className: "vos-ondeck-row", children: [
4629
- /* @__PURE__ */ jsx15("span", { className: "vos-risk-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsx15("i", { className: `vos-fill-${tone}`, style: { width: `${riskFraction(move.risk) * 100}%` } }) }),
4630
- /* @__PURE__ */ jsx15("button", { type: "button", className: "vos-ondeck-title", onClick: onOpen, children: move.title }),
4631
- /* @__PURE__ */ jsx15("button", { type: "button", className: "vos-pill vos-pill-accent vos-ondeck-act", onClick: onAct, children: pres.pill })
5373
+ return /* @__PURE__ */ jsxs16("div", { className: "vos-ondeck-row", children: [
5374
+ /* @__PURE__ */ jsx17("span", { className: "vos-risk-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsx17("i", { className: `vos-fill-${tone}`, style: { width: `${riskFraction(move.risk) * 100}%` } }) }),
5375
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "vos-ondeck-title", onClick: onOpen, children: move.title }),
5376
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "vos-pill vos-pill-accent vos-ondeck-act", onClick: onAct, children: pres.pill })
4632
5377
  ] });
4633
5378
  }
4634
5379
  function WhyPanel({ top, ranked }) {
4635
- return /* @__PURE__ */ jsxs15("div", { className: "vos-why-panel vos-next-why", children: [
4636
- /* @__PURE__ */ jsx15("p", { className: "vos-why-reason", children: top.reason }),
4637
- /* @__PURE__ */ jsxs15("div", { children: [
4638
- /* @__PURE__ */ jsx15("div", { className: "vos-why-section-title", children: "Where it sits" }),
4639
- /* @__PURE__ */ jsx15(StageStepper, { move: top.move })
5380
+ return /* @__PURE__ */ jsxs16("div", { className: "vos-why-panel vos-next-why", children: [
5381
+ /* @__PURE__ */ jsx17("p", { className: "vos-why-reason", children: top.reason }),
5382
+ /* @__PURE__ */ jsxs16("div", { children: [
5383
+ /* @__PURE__ */ jsx17("div", { className: "vos-why-section-title", children: "Where it sits" }),
5384
+ /* @__PURE__ */ jsx17(StageStepper, { move: top.move })
4640
5385
  ] }),
4641
- /* @__PURE__ */ jsxs15("div", { children: [
4642
- /* @__PURE__ */ jsx15("div", { className: "vos-why-section-title", children: "Why it's on top" }),
4643
- /* @__PURE__ */ jsxs15("p", { className: "vos-why-formula", children: [
5386
+ /* @__PURE__ */ jsxs16("div", { children: [
5387
+ /* @__PURE__ */ jsx17("div", { className: "vos-why-section-title", children: "Why it's on top" }),
5388
+ /* @__PURE__ */ jsxs16("p", { className: "vos-why-formula", children: [
4644
5389
  "Ranked by ",
4645
- /* @__PURE__ */ jsx15("b", { children: "Feasibility \xD7 Risk" }),
5390
+ /* @__PURE__ */ jsx17("b", { children: "Feasibility \xD7 Risk" }),
4646
5391
  " \u2014 Risk ",
4647
- /* @__PURE__ */ jsx15("b", { children: Math.round(top.risk) }),
4648
- top.feasibility ? /* @__PURE__ */ jsxs15(Fragment10, { children: [
5392
+ /* @__PURE__ */ jsx17("b", { children: Math.round(top.risk) }),
5393
+ top.feasibility ? /* @__PURE__ */ jsxs16(Fragment10, { children: [
4649
5394
  " ",
4650
5395
  "\xD7 Feasibility ",
4651
- /* @__PURE__ */ jsx15("b", { children: top.feasibility })
4652
- ] }) : /* @__PURE__ */ jsx15(Fragment10, { children: " (no test planned yet \u2014 neutral feasibility)" }),
5396
+ /* @__PURE__ */ jsx17("b", { children: top.feasibility })
5397
+ ] }) : /* @__PURE__ */ jsx17(Fragment10, { children: " (no test planned yet \u2014 neutral feasibility)" }),
4653
5398
  top.killLane ? " \xB7 in the kill lane, so it jumps the queue" : null,
4654
5399
  "."
4655
5400
  ] })
4656
5401
  ] }),
4657
- /* @__PURE__ */ jsxs15("div", { children: [
4658
- /* @__PURE__ */ jsx15("div", { className: "vos-why-section-title", children: "The ranking" }),
4659
- /* @__PURE__ */ jsx15("ol", { className: "vos-why-rank", children: ranked.slice(0, 6).map((m) => /* @__PURE__ */ jsxs15("li", { className: m.assumptionId === top.assumptionId ? "vos-why-rank-top" : "", children: [
4660
- /* @__PURE__ */ jsx15("span", { className: "vos-why-rank-title", children: m.title }),
4661
- /* @__PURE__ */ jsx15("span", { className: "vos-why-rank-score", children: Math.round(m.score) })
5402
+ /* @__PURE__ */ jsxs16("div", { children: [
5403
+ /* @__PURE__ */ jsx17("div", { className: "vos-why-section-title", children: "The ranking" }),
5404
+ /* @__PURE__ */ jsx17("ol", { className: "vos-why-rank", children: ranked.slice(0, 6).map((m) => /* @__PURE__ */ jsxs16("li", { className: m.assumptionId === top.assumptionId ? "vos-why-rank-top" : "", children: [
5405
+ /* @__PURE__ */ jsx17("span", { className: "vos-why-rank-title", children: m.title }),
5406
+ /* @__PURE__ */ jsx17("span", { className: "vos-why-rank-score", children: Math.round(m.score) })
4662
5407
  ] }, m.assumptionId)) })
4663
5408
  ] })
4664
5409
  ] });
4665
5410
  }
4666
5411
  function StageStepper({ move }) {
4667
5412
  const at = MOVE_STAGE[move];
4668
- return /* @__PURE__ */ jsx15("div", { className: "vos-stepper", "aria-label": `Stage: ${STAGES[at]}`, children: STAGES.map((label, i) => /* @__PURE__ */ jsx15(
5413
+ return /* @__PURE__ */ jsx17("div", { className: "vos-stepper", "aria-label": `Stage: ${STAGES[at]}`, children: STAGES.map((label, i) => /* @__PURE__ */ jsx17(
4669
5414
  "span",
4670
5415
  {
4671
5416
  className: `vos-step${i === at ? " vos-step-at" : ""}${i < at ? " vos-step-done" : ""}`,
@@ -4705,7 +5450,7 @@ function formatRoute(route) {
4705
5450
  }
4706
5451
 
4707
5452
  // src/sidebar-nav.tsx
4708
- import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
5453
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
4709
5454
  function SidebarNav({
4710
5455
  route,
4711
5456
  onNavigate,
@@ -4714,12 +5459,12 @@ function SidebarNav({
4714
5459
  registers
4715
5460
  }) {
4716
5461
  const activeRegister = route.name === "records" ? route.register : null;
4717
- return /* @__PURE__ */ jsxs16("nav", { className: "vos-nav", "aria-label": "Navigation", children: [
4718
- /* @__PURE__ */ jsxs16("div", { children: [
4719
- /* @__PURE__ */ jsx16("div", { className: "vos-nav-group", children: "Workflow" }),
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" }),
4720
5465
  WORKFLOW_NAV.map((item) => {
4721
5466
  const active = route.name === item.route;
4722
- return /* @__PURE__ */ jsxs16(
5467
+ return /* @__PURE__ */ jsxs17(
4723
5468
  "button",
4724
5469
  {
4725
5470
  type: "button",
@@ -4727,20 +5472,20 @@ function SidebarNav({
4727
5472
  "aria-current": active ? "page" : void 0,
4728
5473
  onClick: () => onNavigate({ name: item.route }),
4729
5474
  children: [
4730
- /* @__PURE__ */ jsx16("span", { className: "vos-nav-ic", "aria-hidden": "true", children: item.icon }),
5475
+ /* @__PURE__ */ jsx18("span", { className: "vos-nav-ic", "aria-hidden": "true", children: item.icon }),
4731
5476
  item.label,
4732
- item.isDefault ? /* @__PURE__ */ jsx16("span", { className: "vos-nav-default", children: "home" }) : null
5477
+ item.isDefault ? /* @__PURE__ */ jsx18("span", { className: "vos-nav-default", children: "home" }) : null
4733
5478
  ]
4734
5479
  },
4735
5480
  item.route
4736
5481
  );
4737
5482
  })
4738
5483
  ] }),
4739
- /* @__PURE__ */ jsxs16("div", { children: [
4740
- /* @__PURE__ */ jsx16("div", { className: "vos-nav-group", children: "Records" }),
5484
+ /* @__PURE__ */ jsxs17("div", { children: [
5485
+ /* @__PURE__ */ jsx18("div", { className: "vos-nav-group", children: "Records" }),
4741
5486
  registers.map((register) => {
4742
5487
  const active = register === activeRegister;
4743
- return /* @__PURE__ */ jsxs16(
5488
+ return /* @__PURE__ */ jsxs17(
4744
5489
  "button",
4745
5490
  {
4746
5491
  type: "button",
@@ -4748,9 +5493,9 @@ function SidebarNav({
4748
5493
  "aria-current": active ? "page" : void 0,
4749
5494
  onClick: () => onNavigate({ name: "records", register }),
4750
5495
  children: [
4751
- /* @__PURE__ */ jsx16("span", { className: "vos-nav-ic", "aria-hidden": "true", children: REGISTER_ICON[register] }),
5496
+ /* @__PURE__ */ jsx18("span", { className: "vos-nav-ic", "aria-hidden": "true", children: REGISTER_ICON[register] }),
4752
5497
  REGISTER_LABEL[register],
4753
- needsHuman?.[register] ? /* @__PURE__ */ jsx16(
5498
+ needsHuman?.[register] ? /* @__PURE__ */ jsx18(
4754
5499
  "span",
4755
5500
  {
4756
5501
  className: "vos-nav-alert",
@@ -4758,7 +5503,7 @@ function SidebarNav({
4758
5503
  children: formatCount(needsHuman[register] ?? 0)
4759
5504
  }
4760
5505
  ) : null,
4761
- /* @__PURE__ */ jsx16("span", { className: "vos-nav-count vos-num", children: counts?.[register] !== void 0 ? formatCount(counts[register] ?? 0) : "\xB7" })
5506
+ /* @__PURE__ */ jsx18("span", { className: "vos-nav-count vos-num", children: counts?.[register] !== void 0 ? formatCount(counts[register] ?? 0) : "\xB7" })
4762
5507
  ]
4763
5508
  },
4764
5509
  register
@@ -4819,7 +5564,7 @@ function useNeedsHuman(basePath = "/api") {
4819
5564
  }
4820
5565
 
4821
5566
  // src/dashboard-app.tsx
4822
- import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
5567
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
4823
5568
  function initialsOf(name) {
4824
5569
  const parts = name.trim().split(/\s+/);
4825
5570
  const first = parts[0]?.[0] ?? "";
@@ -4861,33 +5606,33 @@ function ValidationOSDashboard({ config = {} }) {
4861
5606
  }, []);
4862
5607
  const brandName = branding?.name ?? "Validation-OS";
4863
5608
  const brandMark = branding?.initials ?? "V";
4864
- return /* @__PURE__ */ jsxs17("div", { className: "vos-app", children: [
4865
- /* @__PURE__ */ jsxs17("div", { className: "vos-brand", children: [
4866
- /* @__PURE__ */ jsx17("span", { className: "vos-brand-dot", children: branding?.logoUrl ? /* @__PURE__ */ jsx17("img", { src: branding.logoUrl, alt: "" }) : brandMark }),
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 }),
4867
5612
  " ",
4868
5613
  brandName
4869
5614
  ] }),
4870
- /* @__PURE__ */ jsxs17("div", { className: "vos-topbar", children: [
4871
- backendLabel ? /* @__PURE__ */ jsxs17("div", { className: "vos-backend", children: [
4872
- /* @__PURE__ */ jsx17("span", { className: "vos-live-dot" }),
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" }),
4873
5618
  " Backend: ",
4874
- /* @__PURE__ */ jsx17("b", { children: backendLabel })
5619
+ /* @__PURE__ */ jsx19("b", { children: backendLabel })
4875
5620
  ] }) : null,
4876
- agentLabel ? /* @__PURE__ */ jsxs17("span", { className: "vos-hint", children: [
5621
+ agentLabel ? /* @__PURE__ */ jsxs18("span", { className: "vos-hint", children: [
4877
5622
  "Agent: ",
4878
- /* @__PURE__ */ jsx17("b", { style: { color: "var(--vos-text)" }, children: agentLabel })
5623
+ /* @__PURE__ */ jsx19("b", { style: { color: "var(--vos-text)" }, children: agentLabel })
4879
5624
  ] }) : null,
4880
- /* @__PURE__ */ jsx17("div", { className: "vos-spacer" }),
4881
- /* @__PURE__ */ jsx17("button", { type: "button", className: "vos-iconbtn", onClick: toggleTheme, children: "\u25D0 Theme" }),
4882
- user?.name ? /* @__PURE__ */ jsxs17("div", { className: "vos-user", children: [
4883
- /* @__PURE__ */ jsx17("span", { className: "vos-avatar", children: initialsOf(user.name) }),
4884
- /* @__PURE__ */ jsxs17("div", { children: [
4885
- /* @__PURE__ */ jsx17("span", { className: "vos-user-name", children: user.name }),
4886
- user.caption ? /* @__PURE__ */ jsx17("small", { children: user.caption }) : 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
4887
5632
  ] })
4888
5633
  ] }) : null
4889
5634
  ] }),
4890
- /* @__PURE__ */ jsx17(
5635
+ /* @__PURE__ */ jsx19(
4891
5636
  SidebarNav,
4892
5637
  {
4893
5638
  route,
@@ -4897,7 +5642,7 @@ function ValidationOSDashboard({ config = {} }) {
4897
5642
  registers
4898
5643
  }
4899
5644
  ),
4900
- /* @__PURE__ */ jsx17("main", { className: "vos-main", children: route.name === "records" ? /* @__PURE__ */ jsx17(
5645
+ /* @__PURE__ */ jsx19("main", { className: "vos-main", children: route.name === "records" ? /* @__PURE__ */ jsx19(
4901
5646
  RegisterBrowser,
4902
5647
  {
4903
5648
  register: route.register,
@@ -4906,7 +5651,7 @@ function ValidationOSDashboard({ config = {} }) {
4906
5651
  onOpenRecord: (id) => navigate({ name: "record", id })
4907
5652
  },
4908
5653
  route.register
4909
- ) : route.name === "record" ? /* @__PURE__ */ jsx17(
5654
+ ) : route.name === "record" ? /* @__PURE__ */ jsx19(
4910
5655
  RecordPage,
4911
5656
  {
4912
5657
  recordId: route.id,
@@ -4915,28 +5660,128 @@ function ValidationOSDashboard({ config = {} }) {
4915
5660
  basePath
4916
5661
  },
4917
5662
  route.id
4918
- ) : route.name === "pipeline" ? /* @__PURE__ */ jsx17(PipelineSurface, { basePath, onNavigate: navigate }, "pipeline") : /* @__PURE__ */ jsx17(NextMoveSurface, { basePath, onNavigate: navigate }, "next") })
5663
+ ) : route.name === "pipeline" ? /* @__PURE__ */ jsx19(PipelineSurface, { basePath, onNavigate: navigate }, "pipeline") : /* @__PURE__ */ jsx19(NextMoveSurface, { basePath, onNavigate: navigate }, "next") })
5664
+ ] });
5665
+ }
5666
+
5667
+ // src/connect.ts
5668
+ var DEFAULT_TOKEN_ENV = "VALIDATION_OS_TOKEN";
5669
+ var SHELL_UNSAFE = /['"\\\s]/;
5670
+ function composeConnectCommand(input) {
5671
+ const tokenEnv = input.tokenEnv ?? DEFAULT_TOKEN_ENV;
5672
+ const guarded = [
5673
+ ["Token", input.token],
5674
+ ["API base URL", input.apiBaseUrl]
5675
+ ];
5676
+ for (const [label, value] of guarded) {
5677
+ if (SHELL_UNSAFE.test(value)) {
5678
+ throw new Error(`${label} contains characters that can't be safely pasted.`);
5679
+ }
5680
+ }
5681
+ return [
5682
+ `export ${tokenEnv}='${input.token}'`,
5683
+ `cat > validation-os.config.yaml <<'EOF'`,
5684
+ `connector: remote-api`,
5685
+ `remote_api:`,
5686
+ ` api_base_url: ${input.apiBaseUrl}`,
5687
+ ` token_env: ${tokenEnv}`,
5688
+ `EOF`
5689
+ ].join("\n");
5690
+ }
5691
+
5692
+ // src/connect-claude-code.tsx
5693
+ import { useState as useState14 } from "react";
5694
+ import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
5695
+ function ConnectClaudeCode({
5696
+ apiBaseUrl,
5697
+ tokenEnv,
5698
+ mintToken
5699
+ }) {
5700
+ const [state, setState] = useState14({ phase: "idle" });
5701
+ const [copied, setCopied] = useState14(false);
5702
+ async function generate() {
5703
+ setState({ phase: "minting" });
5704
+ setCopied(false);
5705
+ try {
5706
+ const token = await mintToken();
5707
+ const command = composeConnectCommand({ token, apiBaseUrl, tokenEnv });
5708
+ setState({ phase: "ready", command });
5709
+ } catch (e) {
5710
+ setState({
5711
+ phase: "error",
5712
+ message: e instanceof Error ? e.message : "Couldn't generate your connection command."
5713
+ });
5714
+ }
5715
+ }
5716
+ async function copy(command) {
5717
+ try {
5718
+ await navigator.clipboard.writeText(command);
5719
+ setCopied(true);
5720
+ } catch {
5721
+ }
5722
+ }
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." })
5727
+ ] }) }),
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: [
5732
+ "The command carries a token tied to ",
5733
+ /* @__PURE__ */ jsx20("strong", { children: "you" }),
5734
+ " \u2014 anything you write lands under your name. Don't share it."
5735
+ ] })
5736
+ ] }),
5737
+ state.phase !== "ready" ? /* @__PURE__ */ jsx20(
5738
+ "button",
5739
+ {
5740
+ type: "button",
5741
+ className: "vos-btn",
5742
+ onClick: generate,
5743
+ disabled: state.phase === "minting",
5744
+ children: state.phase === "minting" ? "Generating\u2026" : "Generate connection command"
5745
+ }
5746
+ ) : 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(
5752
+ "button",
5753
+ {
5754
+ type: "button",
5755
+ className: "vos-btn",
5756
+ onClick: () => copy(state.command),
5757
+ children: copied ? "Copied" : "Copy command"
5758
+ }
5759
+ ),
5760
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "vos-btn-ghost", onClick: generate, children: "Regenerate" })
5761
+ ] }),
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." })
5763
+ ] }) : null
4919
5764
  ] });
4920
5765
  }
4921
5766
 
4922
5767
  // src/surface-placeholder.tsx
4923
- import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
5768
+ import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
4924
5769
  function SurfacePlaceholder({
4925
5770
  title,
4926
5771
  subtitle,
4927
5772
  detail
4928
5773
  }) {
4929
- return /* @__PURE__ */ jsxs18("div", { children: [
4930
- /* @__PURE__ */ jsx18("div", { className: "vos-head", children: /* @__PURE__ */ jsxs18("div", { children: [
4931
- /* @__PURE__ */ jsx18("h1", { children: title }),
4932
- /* @__PURE__ */ jsx18("p", { children: subtitle })
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 })
4933
5778
  ] }) }),
4934
- /* @__PURE__ */ jsx18("div", { className: "vos-empty", children: detail })
5779
+ /* @__PURE__ */ jsx21("div", { className: "vos-empty", children: detail })
4935
5780
  ] });
4936
5781
  }
4937
5782
 
4938
5783
  // src/register-counts.tsx
4939
- import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
5784
+ import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
4940
5785
  function RegisterCounts({
4941
5786
  counts,
4942
5787
  caption,
@@ -4946,8 +5791,8 @@ function RegisterCounts({
4946
5791
  const registers = REGISTER_ORDER.filter(
4947
5792
  (r) => counts[r] !== void 0
4948
5793
  );
4949
- return /* @__PURE__ */ jsxs19("section", { "aria-label": "Register counts", children: [
4950
- /* @__PURE__ */ jsx19("div", { className: "vos-tile-grid", children: registers.map((register) => /* @__PURE__ */ jsx19(
5794
+ return /* @__PURE__ */ jsxs21("section", { "aria-label": "Register counts", children: [
5795
+ /* @__PURE__ */ jsx22("div", { className: "vos-tile-grid", children: registers.map((register) => /* @__PURE__ */ jsx22(
4951
5796
  StatTile,
4952
5797
  {
4953
5798
  label: REGISTER_LABEL[register],
@@ -4957,18 +5802,23 @@ function RegisterCounts({
4957
5802
  },
4958
5803
  register
4959
5804
  )) }),
4960
- caption ? /* @__PURE__ */ jsx19("p", { className: "vos-hint", style: { marginTop: 16 }, children: caption }) : null
5805
+ caption ? /* @__PURE__ */ jsx22("p", { className: "vos-hint", style: { marginTop: 16 }, children: caption }) : null
4961
5806
  ] });
4962
5807
  }
4963
5808
  export {
4964
5809
  BeliefJourney,
5810
+ BeliefVerdicts,
4965
5811
  CONFLICT_MESSAGE,
4966
5812
  ConfidenceCell,
5813
+ ConnectClaudeCode,
5814
+ DEFAULT_TOKEN_ENV,
5815
+ DIRECT_CYCLE_KEY,
4967
5816
  EditBeliefForm,
4968
5817
  EditFields,
4969
5818
  FIRST_RUN_LINE,
4970
5819
  FieldInput,
4971
5820
  GlossaryText,
5821
+ Markdown,
4972
5822
  NextMoveSurface,
4973
5823
  PipelineSurface,
4974
5824
  REGISTER_GROUPS,
@@ -4997,6 +5847,8 @@ export {
4997
5847
  ValidationOSDashboard,
4998
5848
  WriteDecisionForm,
4999
5849
  backlinkPanels,
5850
+ bodyPreview,
5851
+ buildCycles,
5000
5852
  buildJourney,
5001
5853
  buildPatch,
5002
5854
  buildPipeline,
@@ -5005,9 +5857,11 @@ export {
5005
5857
  cellValue,
5006
5858
  coldStartFor,
5007
5859
  columnsFor,
5860
+ composeConnectCommand,
5008
5861
  confidenceTone,
5009
5862
  configureRiskBands,
5010
5863
  defaultTabId,
5864
+ detailRows,
5011
5865
  dontConfuseWith,
5012
5866
  draftFrom,
5013
5867
  editableFields,
@@ -5034,8 +5888,12 @@ export {
5034
5888
  movePresentation,
5035
5889
  needsHumanCounts,
5036
5890
  nestReadingsByPlan,
5891
+ ownerNames,
5037
5892
  parseRoute,
5038
5893
  primaryLabel,
5894
+ readingAssumptionChips,
5895
+ readingBeliefVerdicts,
5896
+ resolveBarLines,
5039
5897
  riskBand,
5040
5898
  riskFraction,
5041
5899
  riskLevel,