@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.d.ts +366 -111
- package/dist/index.js +1462 -604
- package/dist/index.js.map +1 -1
- package/dist/styles.css +237 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { Collection, AnyRecord, Relation } from '@validation-os/core';
|
|
3
|
+
import { Collection, AnyRecord, Result, Rung, MagnitudeBand, Relation, BarLine } from '@validation-os/core';
|
|
4
4
|
import { PortfolioProgress, StageExperimentInput, MoveKind, NextMoveInput, BeliefStage, JourneyEvent, NextMove, JourneyEventKind, ConfSign, StageKey, Progress, MoverKind, TrajectoryPoint } from '@validation-os/core/derivation';
|
|
5
5
|
export { StageKey } from '@validation-os/core/derivation';
|
|
6
6
|
|
|
@@ -243,7 +243,9 @@ interface GroupBucket {
|
|
|
243
243
|
* risk band by severity, everything else first-appearance.
|
|
244
244
|
*/
|
|
245
245
|
declare function groupRecords(records: AnyRecord[], axis: GroupByAxis): GroupBucket[];
|
|
246
|
-
/** Case-insensitive substring filter over Title + Description.
|
|
246
|
+
/** Case-insensitive substring filter over Title + Description + Source. Source
|
|
247
|
+
* (a reading's generator — person / dataset / cohort) is searchable so a
|
|
248
|
+
* teammate can pull every reading from one source by typing its name. */
|
|
247
249
|
declare function filterRecords(records: AnyRecord[], query: string): AnyRecord[];
|
|
248
250
|
/** A stable sort by one key; numbers compare numerically, everything else by
|
|
249
251
|
* locale string. Missing values sort last regardless of direction. */
|
|
@@ -384,6 +386,60 @@ interface SidebarNavProps {
|
|
|
384
386
|
*/
|
|
385
387
|
declare function SidebarNav({ route, onNavigate, counts, needsHuman, registers, }: SidebarNavProps): react.JSX.Element;
|
|
386
388
|
|
|
389
|
+
/**
|
|
390
|
+
* The "Connect Claude Code" command composer (OPS-1349). A person signed into
|
|
391
|
+
* the dashboard mints a personal token and gets back ONE ready-to-paste command
|
|
392
|
+
* that points their own Claude Code at this hosted register through the
|
|
393
|
+
* `remote-api` connector. Everything environmental — the API URL, the env-var
|
|
394
|
+
* name — is baked in here; the person supplies only their minted token.
|
|
395
|
+
*
|
|
396
|
+
* Pure and deterministic so it can be unit-tested exactly (prior art:
|
|
397
|
+
* `route.ts`). The config keys it writes (`api_base_url`, `token_env`) are the
|
|
398
|
+
* `remote-api` connector's contract, fixed by the spec — so this does not
|
|
399
|
+
* depend on the connector doc or the setup wizard shipping first.
|
|
400
|
+
*/
|
|
401
|
+
/** The env var the `remote-api` connector reads the bearer token from. */
|
|
402
|
+
declare const DEFAULT_TOKEN_ENV = "VALIDATION_OS_TOKEN";
|
|
403
|
+
interface ConnectCommandInput {
|
|
404
|
+
/** The personal bearer token the deployment minted for the signed-in user. */
|
|
405
|
+
token: string;
|
|
406
|
+
/** The hosted API root, baked in by the deployment. */
|
|
407
|
+
apiBaseUrl: string;
|
|
408
|
+
/** Override the token env-var name; defaults to {@link DEFAULT_TOKEN_ENV}. */
|
|
409
|
+
tokenEnv?: string;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Build the paste command: export the token into its env var, then write a
|
|
413
|
+
* `remote-api` `validation-os.config.yaml` at the workspace root. Running it
|
|
414
|
+
* leaves the workspace ready for `/setup-validation-os` to confirm, or for the
|
|
415
|
+
* skills to use directly.
|
|
416
|
+
*/
|
|
417
|
+
declare function composeConnectCommand(input: ConnectCommandInput): string;
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* The "Connect Claude Code" page (OPS-1349). A person already signed into the
|
|
421
|
+
* dashboard mints a personal token and gets one ready-to-paste command that
|
|
422
|
+
* points their own Claude Code at this hosted register.
|
|
423
|
+
*
|
|
424
|
+
* Auth-vendor-free by construction: token minting is INJECTED (`mintToken`), so
|
|
425
|
+
* this package never imports Clerk — the deployment wires a mint function that
|
|
426
|
+
* creates the signed-in user's personal API key and hands back the token
|
|
427
|
+
* (mirrors how the API's `authenticate` is injected). The command itself is the
|
|
428
|
+
* pure `composeConnectCommand`; this component is only the chrome around it.
|
|
429
|
+
*/
|
|
430
|
+
interface ConnectClaudeCodeProps {
|
|
431
|
+
/** The hosted API root, baked into the emitted command. */
|
|
432
|
+
apiBaseUrl: string;
|
|
433
|
+
/** Override the token env-var name written into the config. */
|
|
434
|
+
tokenEnv?: string;
|
|
435
|
+
/**
|
|
436
|
+
* Mint a personal bearer token for the signed-in user. Injected by the
|
|
437
|
+
* deployment (e.g. create a Clerk API key whose subject is the user's ID).
|
|
438
|
+
*/
|
|
439
|
+
mintToken: () => Promise<string>;
|
|
440
|
+
}
|
|
441
|
+
declare function ConnectClaudeCode({ apiBaseUrl, tokenEnv, mintToken, }: ConnectClaudeCodeProps): react.JSX.Element;
|
|
442
|
+
|
|
387
443
|
interface RecordPageProps {
|
|
388
444
|
/** The record being drilled into (`#record/<id>`). */
|
|
389
445
|
recordId: string;
|
|
@@ -574,6 +630,75 @@ interface MovePresentation {
|
|
|
574
630
|
/** The front-door copy + step-in modality for one act. */
|
|
575
631
|
declare function movePresentation(kind: MoveKind): MovePresentation;
|
|
576
632
|
|
|
633
|
+
/**
|
|
634
|
+
* The per-belief cycles view-model (OPS-1347) — the validation loop's rounds,
|
|
635
|
+
* not just the belief's flat dated event log (`journey.ts`) or the
|
|
636
|
+
* strongest-push-first attribution list (`understanding.ts`). Grounded
|
|
637
|
+
* directly in the registry model (`registry-schema.md`):
|
|
638
|
+
*
|
|
639
|
+
* - a **cycle** is one round of the loop — an Experiment designed against
|
|
640
|
+
* this belief, the (dated) Readings it produced, and the per-belief
|
|
641
|
+
* bar-line verdict it settles at closure. That is literally
|
|
642
|
+
* "experiment → readings → re-score", the round the operator asked to
|
|
643
|
+
* see, and it is the only unit the data model pre-registers as a trial:
|
|
644
|
+
* the bar line's `We're right if` / `We're wrong if` are written *before*
|
|
645
|
+
* any Reading exists, so its verdict is a real round boundary, not one we
|
|
646
|
+
* invent;
|
|
647
|
+
* - readings with **no** Experiment (bare/found — a Market-rung commitment
|
|
648
|
+
* or desk research dropped in directly) carry no pre-registered bar, so
|
|
649
|
+
* they are not a "round" in that strict sense. They still move the
|
|
650
|
+
* number, so they collect into one closing, kind-`"direct"` entry rather
|
|
651
|
+
* than disappearing from the picture.
|
|
652
|
+
*
|
|
653
|
+
* Ordered chronologically (oldest first) — the point of this view is watching
|
|
654
|
+
* the belief move round by round, which `understanding.ts`'s magnitude-first
|
|
655
|
+
* ranking deliberately does not show.
|
|
656
|
+
*
|
|
657
|
+
* No new maths: each round's push on Confidence is read off
|
|
658
|
+
* `confidenceAttribution`'s per-experiment mover — the same decomposition
|
|
659
|
+
* `understanding.ts` shows, just regrouped by time instead of by size, so a
|
|
660
|
+
* cycle's push and the drawer's push always agree. Computed fresh on read,
|
|
661
|
+
* out of the OPS-1251 on-write recompute.
|
|
662
|
+
*/
|
|
663
|
+
|
|
664
|
+
/** The round's key: the experiment id, or `"direct"` for the bare-reading bucket. */
|
|
665
|
+
declare const DIRECT_CYCLE_KEY = "direct";
|
|
666
|
+
/** One reading's place inside a round, reduced to what the timeline draws. */
|
|
667
|
+
interface CycleReadingView {
|
|
668
|
+
id: string;
|
|
669
|
+
date: string | null;
|
|
670
|
+
result: Result | null;
|
|
671
|
+
}
|
|
672
|
+
/** One round of the loop. */
|
|
673
|
+
interface CycleView {
|
|
674
|
+
key: string;
|
|
675
|
+
kind: "experiment" | "direct";
|
|
676
|
+
/** The experiment's title; null for the direct bucket. */
|
|
677
|
+
title: string | null;
|
|
678
|
+
/** The experiment's lifecycle status; null for the direct bucket. */
|
|
679
|
+
status: string | null;
|
|
680
|
+
/** The round's anchor date: the experiment's own `Date`, or (falling back)
|
|
681
|
+
* its earliest reading's date. Null only when neither is known. */
|
|
682
|
+
date: string | null;
|
|
683
|
+
/** This belief's bar-line verdict, once judged; null pre-closure and always
|
|
684
|
+
* null for the direct bucket (it carries no bar line). */
|
|
685
|
+
barVerdict: Result | null;
|
|
686
|
+
/** The round's readings, oldest first. */
|
|
687
|
+
readings: CycleReadingView[];
|
|
688
|
+
/** Signed push on Confidence this round contributed (sums, across every
|
|
689
|
+
* round, to the belief's Confidence). */
|
|
690
|
+
contribution: number;
|
|
691
|
+
/** |contribution| — how hard this round moved the number. */
|
|
692
|
+
magnitude: number;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Build one belief's cycles from its readings and the Experiments register.
|
|
696
|
+
* Both arrays are the raw records (Title-cased fields) — the same shape
|
|
697
|
+
* `understanding.ts`/`journey.ts` take — so a caller loading the registers
|
|
698
|
+
* once can hand them straight through.
|
|
699
|
+
*/
|
|
700
|
+
declare function buildCycles(assumptionId: string, readings: AnyRecord[], experiments: AnyRecord[]): CycleView[];
|
|
701
|
+
|
|
577
702
|
/** A journey event with its front-door copy attached. */
|
|
578
703
|
interface JourneyEventView extends JourneyEvent {
|
|
579
704
|
/** Plain-language label the story renders. */
|
|
@@ -587,6 +712,9 @@ interface JourneyView {
|
|
|
587
712
|
stage: BeliefStage;
|
|
588
713
|
/** The story: the belief's life, oldest first, `now` last. */
|
|
589
714
|
events: JourneyEventView[];
|
|
715
|
+
/** The loop's rounds, oldest first (OPS-1347) — the same history the story
|
|
716
|
+
* tells, regrouped by Experiment run instead of by dated event. */
|
|
717
|
+
cycles: CycleView[];
|
|
590
718
|
/** The ranked next move for this belief; null once it is resolved. */
|
|
591
719
|
nextMove: NextMove | null;
|
|
592
720
|
/** Killed (Invalidated) / moot / null — the drill-in's terminal state. */
|
|
@@ -626,7 +754,9 @@ declare function buildJourney(assumptionId: string, records: NextMoveRecords, no
|
|
|
626
754
|
* rail is pure status: nothing to act on there;
|
|
627
755
|
* - it **expands into the chronological story** through the record page's
|
|
628
756
|
* existing "Why?" reveal idiom — the dated event log (bet → score →
|
|
629
|
-
* experiment → readings → confidence-cross → now),
|
|
757
|
+
* experiment → readings → confidence-cross → now), the same history
|
|
758
|
+
* regrouped into **rounds** (OPS-1347 — one card per Experiment run, plus
|
|
759
|
+
* any bare/direct evidence, oldest first), and ending in the ranked
|
|
630
760
|
* next-move card (OPS-1292).
|
|
631
761
|
*
|
|
632
762
|
* **Step-in is story-only** (OPS-1297): the next-move card and the per-event
|
|
@@ -839,6 +969,10 @@ interface FieldEditor {
|
|
|
839
969
|
options?: readonly string[];
|
|
840
970
|
/** An empty input clears the field to `null` rather than "". */
|
|
841
971
|
nullable?: boolean;
|
|
972
|
+
/** For `number`: the inclusive range a hand-scored value must sit in
|
|
973
|
+
* (e.g. Impact 0–100, `registry-schema.md`). Omitted = unbounded. */
|
|
974
|
+
min?: number;
|
|
975
|
+
max?: number;
|
|
842
976
|
}
|
|
843
977
|
/** The fields a register lets you edit, in render order. */
|
|
844
978
|
declare function editableFields(register: Collection): FieldEditor[];
|
|
@@ -865,15 +999,21 @@ declare function hasEdits(register: Collection, original: AnyRecord, draft: Draf
|
|
|
865
999
|
* surfaces editing one register should never drift into two different forms.
|
|
866
1000
|
* Derived numbers are never here — they are computed on write (OPS-1251).
|
|
867
1001
|
*/
|
|
868
|
-
declare function EditFields({ register, draft, onField, }: {
|
|
1002
|
+
declare function EditFields({ register, draft, errors, onField, }: {
|
|
869
1003
|
register: Collection;
|
|
870
1004
|
draft: Draft;
|
|
1005
|
+
/** Per-field validation messages (keyed by field), e.g. Impact out of
|
|
1006
|
+
* 0–100 — `edit.ts`'s `draftErrors`. Absent/empty = every field is valid. */
|
|
1007
|
+
errors?: Record<string, string>;
|
|
871
1008
|
onField: (key: string, value: string) => void;
|
|
872
1009
|
}): react.JSX.Element;
|
|
873
1010
|
/** One editable field, as the control its `kind` calls for. */
|
|
874
|
-
declare function FieldInput({ field, value, onChange, }: {
|
|
1011
|
+
declare function FieldInput({ field, value, error, onChange, }: {
|
|
875
1012
|
field: FieldEditor;
|
|
876
1013
|
value: string | undefined;
|
|
1014
|
+
/** A validation message shown under the control, e.g. "Impact must be at
|
|
1015
|
+
* most 100." — never blocks typing, only the Save the caller gates on it. */
|
|
1016
|
+
error?: string;
|
|
877
1017
|
onChange: (value: string) => void;
|
|
878
1018
|
}): react.JSX.Element;
|
|
879
1019
|
|
|
@@ -902,6 +1042,9 @@ interface RegisterTableProps {
|
|
|
902
1042
|
onRowClick?: (id: string) => void;
|
|
903
1043
|
/** The id of the currently-open record, highlighted in the list. */
|
|
904
1044
|
selectedId?: string | null;
|
|
1045
|
+
/** Assumption id → title, so a reading row's belief chips read as titles
|
|
1046
|
+
* rather than ids (OPS-1305). Omitted → chips fall back to the bare ids. */
|
|
1047
|
+
assumptionTitles?: Map<string, string>;
|
|
905
1048
|
}
|
|
906
1049
|
/**
|
|
907
1050
|
* A list table for one register — a row per record, the register's key fields
|
|
@@ -911,7 +1054,139 @@ interface RegisterTableProps {
|
|
|
911
1054
|
* the treatment stays testable at the columns seam and this component stays a
|
|
912
1055
|
* dumb renderer. Presentational: the caller supplies the rows.
|
|
913
1056
|
*/
|
|
914
|
-
declare function RegisterTable({ register, records, onRowClick, selectedId, }: RegisterTableProps): react.JSX.Element;
|
|
1057
|
+
declare function RegisterTable({ register, records, onRowClick, selectedId, assumptionTitles, }: RegisterTableProps): react.JSX.Element;
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* The record-page view-model (OPS-1286) — the pure join behind the canonical
|
|
1061
|
+
* full record page. Given a record and the related registers, it computes the
|
|
1062
|
+
* header lane/queue pills (all derived), the leading-score meters per register,
|
|
1063
|
+
* the genuine human-input free-text remainder, and the backlink panels grouped
|
|
1064
|
+
* by relation (each row carrying a glance-readable score chip, an empty relation
|
|
1065
|
+
* kept as a "none yet" panel rather than dropped). DOM-free and unit-tested at
|
|
1066
|
+
* this seam; `RecordPage` renders what it returns and the understanding layer
|
|
1067
|
+
* supplies the "Why?" attribution unchanged.
|
|
1068
|
+
*/
|
|
1069
|
+
|
|
1070
|
+
/** The registers a record page reads to resolve its relations. All optional —
|
|
1071
|
+
* a panel whose register is absent simply resolves to "none yet". */
|
|
1072
|
+
interface RelatedSet {
|
|
1073
|
+
assumptions?: AnyRecord[];
|
|
1074
|
+
experiments?: AnyRecord[];
|
|
1075
|
+
readings?: AnyRecord[];
|
|
1076
|
+
decisions?: AnyRecord[];
|
|
1077
|
+
glossary?: AnyRecord[];
|
|
1078
|
+
}
|
|
1079
|
+
interface RecordPageOptions {
|
|
1080
|
+
/** ISO date "now" for the Overdue pill; omitted → nothing reads overdue. */
|
|
1081
|
+
asOf?: string;
|
|
1082
|
+
}
|
|
1083
|
+
/** A header pill: a short derived label toned by meaning. */
|
|
1084
|
+
interface Pill {
|
|
1085
|
+
label: string;
|
|
1086
|
+
tone: Tone;
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* The derived lane/queue pills for a record header (story 2). Every register
|
|
1090
|
+
* leads with its Status pill; assumptions add Moot / Kill lane / Testing,
|
|
1091
|
+
* experiments add Concluded / Overdue, decisions mark Standing. All derived —
|
|
1092
|
+
* none is a stored field.
|
|
1093
|
+
*/
|
|
1094
|
+
declare function headerPills(register: Collection, record: AnyRecord, related?: RelatedSet, options?: RecordPageOptions): Pill[];
|
|
1095
|
+
/** A leading-score meter. `bar`/`signed` carry a number in a min…max domain;
|
|
1096
|
+
* `pill` carries a categorical value shown as a toned pill. */
|
|
1097
|
+
interface Meter {
|
|
1098
|
+
key: string;
|
|
1099
|
+
label: string;
|
|
1100
|
+
kind: "bar" | "signed" | "pill";
|
|
1101
|
+
/** Number (bar/signed) or category (pill); null when the record has no value. */
|
|
1102
|
+
value: number | string | null;
|
|
1103
|
+
tone: Tone;
|
|
1104
|
+
/** For bar/signed: the domain the fill maps onto. */
|
|
1105
|
+
min?: number;
|
|
1106
|
+
max?: number;
|
|
1107
|
+
/** True when a "Why?" attribution is available (Confidence only). */
|
|
1108
|
+
hasWhy?: boolean;
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* The register's leading scores as meters (story 4). Reads only what the
|
|
1112
|
+
* migrated schema actually stores — a derived number becomes a bar/signed meter,
|
|
1113
|
+
* a categorical leading field becomes a pill; nothing is invented where the
|
|
1114
|
+
* schema carries no number. Confidence is flagged `hasWhy` — the understanding
|
|
1115
|
+
* layer decomposes it.
|
|
1116
|
+
*/
|
|
1117
|
+
declare function leadingMeters(register: Collection, record: AnyRecord): Meter[];
|
|
1118
|
+
/** The genuine human-input free-text remainder — clearly separated from what
|
|
1119
|
+
* the system computed. Auto-linked against the glossary at render time. */
|
|
1120
|
+
interface HumanText {
|
|
1121
|
+
key: string;
|
|
1122
|
+
label: string;
|
|
1123
|
+
text: string;
|
|
1124
|
+
}
|
|
1125
|
+
/** The human-input fields a register carries text for (empty ones dropped). */
|
|
1126
|
+
declare function humanInputFields(register: Collection, record: AnyRecord): HumanText[];
|
|
1127
|
+
/** One belief a reading grades, prepared for the reading detail's verdict list
|
|
1128
|
+
* (OPS-1305). Modelled on the experiment bar-line view: the assumption resolved
|
|
1129
|
+
* to a title + navigable id, plus this belief's own Rung / Result / derived
|
|
1130
|
+
* Strength / magnitude band and the grading justification. */
|
|
1131
|
+
interface BeliefVerdict {
|
|
1132
|
+
assumptionId: string;
|
|
1133
|
+
/** The belief's title if it's in the loaded set, else its bare id. */
|
|
1134
|
+
title: string;
|
|
1135
|
+
/** True when the assumption resolved — drives whether the title links. */
|
|
1136
|
+
linked: boolean;
|
|
1137
|
+
rung: Rung | null;
|
|
1138
|
+
result: Result | null;
|
|
1139
|
+
/** Derived per-belief strength (signed −100…100). */
|
|
1140
|
+
strength: number | null;
|
|
1141
|
+
magnitudeBand: MagnitudeBand | null;
|
|
1142
|
+
justification: string;
|
|
1143
|
+
}
|
|
1144
|
+
/** The per-belief verdicts a reading carries, in stored order — the reading
|
|
1145
|
+
* detail's answer to "what did this artifact say about each belief?". Pure:
|
|
1146
|
+
* resolves each belief-score against the loaded assumptions for its title. */
|
|
1147
|
+
declare function readingBeliefVerdicts(reading: AnyRecord, assumptions?: AnyRecord[]): BeliefVerdict[];
|
|
1148
|
+
/** A glance-readable score chip for a linked record (story 9). */
|
|
1149
|
+
interface ScoreChip {
|
|
1150
|
+
label: string;
|
|
1151
|
+
value: string;
|
|
1152
|
+
tone: Tone;
|
|
1153
|
+
}
|
|
1154
|
+
interface BacklinkItem {
|
|
1155
|
+
id: string;
|
|
1156
|
+
register: Collection;
|
|
1157
|
+
title: string;
|
|
1158
|
+
chip: ScoreChip;
|
|
1159
|
+
}
|
|
1160
|
+
/** A relation panel — the inbound/outbound edges of one relation, grouped and
|
|
1161
|
+
* labelled. Kept even when empty (story 10). */
|
|
1162
|
+
interface RelationPanel {
|
|
1163
|
+
id: string;
|
|
1164
|
+
label: string;
|
|
1165
|
+
register: Collection;
|
|
1166
|
+
items: BacklinkItem[];
|
|
1167
|
+
}
|
|
1168
|
+
/** The linked record's headline score, glance-readable (story 9). */
|
|
1169
|
+
declare function scoreChip(register: Collection, record: AnyRecord): ScoreChip;
|
|
1170
|
+
/** The backlink panels for a record, grouped by relation, each row carrying a
|
|
1171
|
+
* score chip. Empty relations are kept (items: []) so a missing connection reads
|
|
1172
|
+
* as "none yet", not an absent section (story 8/10). */
|
|
1173
|
+
declare function backlinkPanels(register: Collection, record: AnyRecord, related?: RelatedSet): RelationPanel[];
|
|
1174
|
+
type RecordTabId = "overview" | "evidence" | "connections" | "history";
|
|
1175
|
+
interface RecordPageModel {
|
|
1176
|
+
register: Collection;
|
|
1177
|
+
title: string;
|
|
1178
|
+
pills: Pill[];
|
|
1179
|
+
meters: Meter[];
|
|
1180
|
+
humanText: HumanText[];
|
|
1181
|
+
panels: RelationPanel[];
|
|
1182
|
+
/** The tabs this record shows, in order (story 3 + 11). */
|
|
1183
|
+
tabs: RecordTabId[];
|
|
1184
|
+
/** True when the belief journey drill-in can mount here (story 13). */
|
|
1185
|
+
hasJourney: boolean;
|
|
1186
|
+
}
|
|
1187
|
+
/** Assemble the whole record-page model. Pure: same record + related always
|
|
1188
|
+
* gives the same page. */
|
|
1189
|
+
declare function buildRecordPage(register: Collection, record: AnyRecord, related?: RelatedSet, options?: RecordPageOptions): RecordPageModel;
|
|
915
1190
|
|
|
916
1191
|
interface RecordDrawerProps {
|
|
917
1192
|
register: Collection;
|
|
@@ -931,6 +1206,17 @@ interface RecordDrawerProps {
|
|
|
931
1206
|
/** Open this record's canonical full page (story 12). When set, the header
|
|
932
1207
|
* shows a "Full page" link; the drawer stays the quick read/edit peek. */
|
|
933
1208
|
onOpenFull?: () => void;
|
|
1209
|
+
/**
|
|
1210
|
+
* Open *any* linked record's full page (OPS-1345) — the same navigation the
|
|
1211
|
+
* canonical record page's Connections tab uses, reused here so a relation
|
|
1212
|
+
* field or a bar line's assumption is a click, not inert text. Falls back
|
|
1213
|
+
* to plain (unclickable) titles when omitted.
|
|
1214
|
+
*/
|
|
1215
|
+
onOpenRecord?: (id: string) => void;
|
|
1216
|
+
/** The other registers' rows, loaded so a relation field / bar line can
|
|
1217
|
+
* resolve to a title instead of a raw id (OPS-1345). Omitted relations
|
|
1218
|
+
* simply fall back to showing the id. */
|
|
1219
|
+
related?: RelatedSet;
|
|
934
1220
|
/** Extra content below the fields in read mode — e.g. the relation editor. */
|
|
935
1221
|
children?: ReactNode;
|
|
936
1222
|
}
|
|
@@ -945,7 +1231,7 @@ interface RecordDrawerProps {
|
|
|
945
1231
|
* the relation editor (`children`). Chrome is shared via `DrawerShell`; styled
|
|
946
1232
|
* with the package's own token sheet, no host Tailwind.
|
|
947
1233
|
*/
|
|
948
|
-
declare function RecordDrawer({ register, record, loading, error, open, onClose, basePath, onChanged, onOpenFull, children, }: RecordDrawerProps): react.JSX.Element;
|
|
1234
|
+
declare function RecordDrawer({ register, record, loading, error, open, onClose, basePath, onChanged, onOpenFull, onOpenRecord, related, children, }: RecordDrawerProps): react.JSX.Element;
|
|
949
1235
|
|
|
950
1236
|
interface RecordFormProps {
|
|
951
1237
|
register: Collection;
|
|
@@ -1003,7 +1289,10 @@ declare function UnderstandingPanel({ assumption, basePath, }: {
|
|
|
1003
1289
|
* also moves the number, and the Confidence-over-time trajectory.
|
|
1004
1290
|
*
|
|
1005
1291
|
* The record → derivation-input mapping is `@validation-os/core`'s shared
|
|
1006
|
-
* `
|
|
1292
|
+
* `readingBeliefInputs`, which fans a reading row out into one input per belief;
|
|
1293
|
+
* we keep this belief's inputs, so a reading is read here exactly as it is
|
|
1294
|
+
* server-side. Archived experiments never surface here (OPS-1305) — the "Why?"
|
|
1295
|
+
* only ever shows a live plan or direct evidence.
|
|
1007
1296
|
*/
|
|
1008
1297
|
|
|
1009
1298
|
/** An experiment testing this assumption: how hard it moves Confidence, and
|
|
@@ -1277,6 +1566,14 @@ interface ColumnDef {
|
|
|
1277
1566
|
}
|
|
1278
1567
|
/** The columns to render for a register. */
|
|
1279
1568
|
declare function columnsFor(register: Collection): ColumnDef[];
|
|
1569
|
+
/** A one-line, length-capped preview of a reading's free-text `body` (its
|
|
1570
|
+
* quote), for the readings table. Collapses whitespace and ellipsises; a
|
|
1571
|
+
* missing/empty body reads as the empty string (formatted to an em dash). */
|
|
1572
|
+
declare function bodyPreview(value: unknown, max?: number): string;
|
|
1573
|
+
/** The belief chips for a reading row — the assumptions it grades, resolved to
|
|
1574
|
+
* titles when a lookup is given, else their bare ids. Disambiguates readings
|
|
1575
|
+
* that share a Title by showing which belief(s) each one actually scored. */
|
|
1576
|
+
declare function readingAssumptionChips(record: AnyRecord, titleById?: Map<string, string>): string[];
|
|
1280
1577
|
/** Read a column's raw value from a record (accessor, else `record[key]`). */
|
|
1281
1578
|
declare function cellValue(column: ColumnDef, record: AnyRecord): unknown;
|
|
1282
1579
|
/** Format any stored value for display; empty/missing reads as an em dash. */
|
|
@@ -1284,6 +1581,17 @@ declare function formatValue(value: unknown): string;
|
|
|
1284
1581
|
/** The record's headline for a row/drawer: Title, else Name, else its id. */
|
|
1285
1582
|
declare function primaryLabel(record: AnyRecord): string;
|
|
1286
1583
|
|
|
1584
|
+
/** Render Markdown `text` into the package's prose styling. Empty → nothing. */
|
|
1585
|
+
declare function Markdown({ text }: {
|
|
1586
|
+
text: string;
|
|
1587
|
+
}): react.JSX.Element | null;
|
|
1588
|
+
|
|
1589
|
+
declare function BeliefVerdicts({ reading, assumptions, onOpenRecord, }: {
|
|
1590
|
+
reading: AnyRecord;
|
|
1591
|
+
assumptions: AnyRecord[];
|
|
1592
|
+
onOpenRecord?: (id: string) => void;
|
|
1593
|
+
}): react.JSX.Element;
|
|
1594
|
+
|
|
1287
1595
|
/**
|
|
1288
1596
|
* The editable-field spec for the "new record" form, per register — kept as
|
|
1289
1597
|
* pure data + functions (like `columns.ts`) so the create form is unit-testable
|
|
@@ -1418,115 +1726,62 @@ interface GlossaryTextProps {
|
|
|
1418
1726
|
declare function GlossaryText({ text, terms, selfId, onOpenTerm, }: GlossaryTextProps): react.JSX.Element;
|
|
1419
1727
|
|
|
1420
1728
|
/**
|
|
1421
|
-
* The record
|
|
1422
|
-
*
|
|
1423
|
-
*
|
|
1424
|
-
*
|
|
1425
|
-
*
|
|
1426
|
-
*
|
|
1427
|
-
*
|
|
1428
|
-
*
|
|
1729
|
+
* The record drawer's generic field list (OPS-1345) — the pure view-model
|
|
1730
|
+
* behind the "everything else" rows a record carries beyond its meters/
|
|
1731
|
+
* human-text/panels. `RecordDrawer` iterates a record's own keys (skipping
|
|
1732
|
+
* provenance/meta), and this module decides how each one reads: a relation
|
|
1733
|
+
* id/id-list (`Depends on`, `Readings`, `Assumption`…) resolves to the linked
|
|
1734
|
+
* record's title, `Owner`/`Agreed by` (stored as dashboard-user objects,
|
|
1735
|
+
* `{id, name}` — `connectors/nosql-schema.md`) reads as name(s) only, and
|
|
1736
|
+
* `barLines` (the embedded per-belief pre-registration on an experiment)
|
|
1737
|
+
* reads as structured rows with a linked assumption title — never the raw
|
|
1738
|
+
* stored JSON or an internal id, per this project's "explain visually, hide
|
|
1739
|
+
* complexity" bias. Everything else still formats through `columns.ts`.
|
|
1740
|
+
* DOM-free and unit-tested at this seam; `record-drawer.tsx` renders what it
|
|
1741
|
+
* returns.
|
|
1429
1742
|
*/
|
|
1430
1743
|
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
interface
|
|
1434
|
-
assumptions?: AnyRecord[];
|
|
1435
|
-
experiments?: AnyRecord[];
|
|
1436
|
-
readings?: AnyRecord[];
|
|
1437
|
-
decisions?: AnyRecord[];
|
|
1438
|
-
glossary?: AnyRecord[];
|
|
1439
|
-
}
|
|
1440
|
-
interface RecordPageOptions {
|
|
1441
|
-
/** ISO date "now" for the Overdue pill; omitted → nothing reads overdue. */
|
|
1442
|
-
asOf?: string;
|
|
1443
|
-
}
|
|
1444
|
-
/** A header pill: a short derived label toned by meaning. */
|
|
1445
|
-
interface Pill {
|
|
1446
|
-
label: string;
|
|
1447
|
-
tone: Tone;
|
|
1448
|
-
}
|
|
1449
|
-
/**
|
|
1450
|
-
* The derived lane/queue pills for a record header (story 2). Every register
|
|
1451
|
-
* leads with its Status pill; assumptions add Moot / Kill lane / Testing,
|
|
1452
|
-
* experiments add Concluded / Overdue, decisions mark Standing. All derived —
|
|
1453
|
-
* none is a stored field.
|
|
1454
|
-
*/
|
|
1455
|
-
declare function headerPills(register: Collection, record: AnyRecord, related?: RelatedSet, options?: RecordPageOptions): Pill[];
|
|
1456
|
-
/** A leading-score meter. `bar`/`signed` carry a number in a min…max domain;
|
|
1457
|
-
* `pill` carries a categorical value shown as a toned pill. */
|
|
1458
|
-
interface Meter {
|
|
1459
|
-
key: string;
|
|
1460
|
-
label: string;
|
|
1461
|
-
kind: "bar" | "signed" | "pill";
|
|
1462
|
-
/** Number (bar/signed) or category (pill); null when the record has no value. */
|
|
1463
|
-
value: number | string | null;
|
|
1464
|
-
tone: Tone;
|
|
1465
|
-
/** For bar/signed: the domain the fill maps onto. */
|
|
1466
|
-
min?: number;
|
|
1467
|
-
max?: number;
|
|
1468
|
-
/** True when a "Why?" attribution is available (Confidence only). */
|
|
1469
|
-
hasWhy?: boolean;
|
|
1470
|
-
}
|
|
1471
|
-
/**
|
|
1472
|
-
* The register's leading scores as meters (story 4). Reads only what the
|
|
1473
|
-
* migrated schema actually stores — a derived number becomes a bar/signed meter,
|
|
1474
|
-
* a categorical leading field becomes a pill; nothing is invented where the
|
|
1475
|
-
* schema carries no number. Confidence is flagged `hasWhy` — the understanding
|
|
1476
|
-
* layer decomposes it.
|
|
1477
|
-
*/
|
|
1478
|
-
declare function leadingMeters(register: Collection, record: AnyRecord): Meter[];
|
|
1479
|
-
/** The genuine human-input free-text remainder — clearly separated from what
|
|
1480
|
-
* the system computed. Auto-linked against the glossary at render time. */
|
|
1481
|
-
interface HumanText {
|
|
1482
|
-
key: string;
|
|
1483
|
-
label: string;
|
|
1484
|
-
text: string;
|
|
1485
|
-
}
|
|
1486
|
-
/** The human-input fields a register carries text for (empty ones dropped). */
|
|
1487
|
-
declare function humanInputFields(register: Collection, record: AnyRecord): HumanText[];
|
|
1488
|
-
/** A glance-readable score chip for a linked record (story 9). */
|
|
1489
|
-
interface ScoreChip {
|
|
1490
|
-
label: string;
|
|
1491
|
-
value: string;
|
|
1492
|
-
tone: Tone;
|
|
1493
|
-
}
|
|
1494
|
-
interface BacklinkItem {
|
|
1744
|
+
type DetailRowKind = "text" | "relation" | "owner" | "bar-lines";
|
|
1745
|
+
/** One resolved relation target — a title to show, an id to navigate to. */
|
|
1746
|
+
interface DetailRelationItem {
|
|
1495
1747
|
id: string;
|
|
1496
1748
|
register: Collection;
|
|
1497
1749
|
title: string;
|
|
1498
|
-
chip: ScoreChip;
|
|
1499
1750
|
}
|
|
1500
|
-
/**
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1751
|
+
/** One bar line, human-readable: the belief it tests resolved to a title. */
|
|
1752
|
+
interface ResolvedBarLine {
|
|
1753
|
+
rightIf: string;
|
|
1754
|
+
wrongIf: string | null;
|
|
1755
|
+
plannedRung: string;
|
|
1756
|
+
barVerdict: string | null;
|
|
1757
|
+
assumption: DetailRelationItem | null;
|
|
1507
1758
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
/**
|
|
1528
|
-
*
|
|
1529
|
-
|
|
1759
|
+
interface DetailRow {
|
|
1760
|
+
key: string;
|
|
1761
|
+
label: string;
|
|
1762
|
+
kind: DetailRowKind;
|
|
1763
|
+
/** `kind: "text"` — the formatted display string. */
|
|
1764
|
+
text?: string;
|
|
1765
|
+
/** `kind: "relation"` — the resolved link targets, in stored order. */
|
|
1766
|
+
items?: DetailRelationItem[];
|
|
1767
|
+
/** `kind: "owner"` — the dashboard-user name(s), never the id/object. */
|
|
1768
|
+
names?: string[];
|
|
1769
|
+
/** `kind: "bar-lines"` — the embedded pre-registration, resolved. */
|
|
1770
|
+
bars?: ResolvedBarLine[];
|
|
1771
|
+
}
|
|
1772
|
+
/** The dashboard-user name(s) off an `Owner`/`Agreed by` value — the stored
|
|
1773
|
+
* shape is `{id, name}[]`; a bare string is tolerated as a fallback. */
|
|
1774
|
+
declare function ownerNames(value: unknown): string[];
|
|
1775
|
+
/** Bar lines resolved against the loaded assumptions — shared by the drawer's
|
|
1776
|
+
* generic list and the record page's Evidence tab so the two never drift. */
|
|
1777
|
+
declare function resolveBarLines(bars: BarLine[], related: RelatedSet): ResolvedBarLine[];
|
|
1778
|
+
/**
|
|
1779
|
+
* The record's own fields, beyond its meta/derived tuple, as rows a drawer
|
|
1780
|
+
* can render directly — relation fields resolved to a title + navigate
|
|
1781
|
+
* target, `Owner`/`Agreed by` to plain names, `barLines` to structured rows.
|
|
1782
|
+
* Everything else still formats through `formatValue` (spec stories 1–3).
|
|
1783
|
+
*/
|
|
1784
|
+
declare function detailRows(register: Collection, record: AnyRecord, related?: RelatedSet): DetailRow[];
|
|
1530
1785
|
|
|
1531
1786
|
/** Plain-language labels — the register is a surface a non-technical
|
|
1532
1787
|
* teammate meets, so no jargon and no code-y plurals. */
|
|
@@ -1548,4 +1803,4 @@ declare const REGISTER_GROUPS: {
|
|
|
1548
1803
|
registers: Collection[];
|
|
1549
1804
|
}[];
|
|
1550
1805
|
|
|
1551
|
-
export { type BacklinkItem, BeliefJourney, type BeliefJourneyProps, CONFLICT_MESSAGE, type CellKind, type ColdStart, type ColumnDef, ConfidenceCell, type Counts, type DashboardConfig, type Draft, EditBeliefForm, type EditBeliefFormProps, EditFields, type ExperimentView, FIRST_RUN_LINE, type FieldEditor, FieldInput, type FieldKind, type FormField, type GlossaryTerm, GlossaryText, type GlossaryTextProps, type GroupBucket, type GroupByAxis, type HumanText, type JourneyColdState, type JourneyEventView, type JourneyView, type LinkArgs, type LinkChoice, type LinkifyNode, type LinkifyOptions, type Meter, type MeterKind, type MovePresentation, type NeedsHumanByRegister, type NeedsHumanCounts, type NeighbourChip, type NestedGroup, type NextColdStart, type NextMoveRecords, NextMoveSurface, type NextMoveSurfaceProps, type OtherMover, type Pill, type PipelineColdStart, type PipelineRow, PipelineSurface, type PipelineView, REGISTER_GROUPS, REGISTER_ICON, REGISTER_LABEL, REGISTER_ORDER, REGISTER_SINGULAR, REGISTER_SUBTITLE, RISK_CRIT, RISK_WARN, RecordDrawer, type RecordDrawerProps, RecordForm, type RecordFormProps, RecordPage, type RecordPageModel, type RecordPageProps, type RecordTabId, RegisterBrowser, type RegisterBrowserProps, type RegisterContext, RegisterCounts, type RegisterCountsProps, RegisterTable, type RegisterTableProps, type RelatedSet, RelationEditor, type RelationEditorProps, type RelationPanel, type ResolvedRow, type RiskBand, RiskBar, type Route, type SaveResult, type SavedView, type ScoreChip, ScoreImpactForm, type ScoreImpactFormProps, type ShapedRegister, SidebarNav, type SidebarNavProps, type SortSpec, Sparkline, type StageMeterInput, type StageMeterView, StatTile, StatusPill, type StepInForm, type StoryStepIn, SurfacePlaceholder, type SurfacePlaceholderProps, type TabDef, type TermPreview, type Tone, type Understanding, UnderstandingPanel, type UseCountsResult, type UseCreateResult, type UseLinkResult, type UseListResult, type UseNeedsHumanResult, type UseRecordResult, type UseSavedViewsResult, type UseUpdateResult, ValidationOSDashboard, type ValidationOSDashboardProps, type ViewDescriptor, WriteDecisionForm, type WriteDecisionFormProps, backlinkPanels, buildJourney, buildPatch, buildPipeline, buildRecordPage, buildUnderstanding, cellValue, coldStartFor, columnsFor, confidenceTone, configureRiskBands, defaultTabId, dontConfuseWith, draftFrom, editableFields, emptyDraft, eventStepIn, eventTone, filterRecords, formFieldsFor, formatCount, formatRoute, formatSigned, formatValue, groupByAxesFor, groupRecords, hasEdits, headerPills, humanInputFields, interpretSave, journeyColdState, leadingMeters, linkChoicesFrom, linkify, missingRequired, movePresentation, needsHumanCounts, nestReadingsByPlan, parseRoute, primaryLabel, riskBand, riskFraction, riskLevel, scoreChip, shapeRegister, sortRecords, sparklinePath, stageMeters, statusTone, tabsFor, toCreatePayload, toGlossaryTerms, toNextMoveInput, toStageExperimentInput, useCounts, useCreate, useLink, useList, useNeedsHuman, useRecord, useSavedViews, useUpdate, weekOverWeekDelta };
|
|
1806
|
+
export { type BacklinkItem, BeliefJourney, type BeliefJourneyProps, type BeliefVerdict, BeliefVerdicts, CONFLICT_MESSAGE, type CellKind, type ColdStart, type ColumnDef, ConfidenceCell, ConnectClaudeCode, type ConnectClaudeCodeProps, type ConnectCommandInput, type Counts, type CycleReadingView, type CycleView, DEFAULT_TOKEN_ENV, DIRECT_CYCLE_KEY, type DashboardConfig, type DetailRelationItem, type DetailRow, type DetailRowKind, type Draft, EditBeliefForm, type EditBeliefFormProps, EditFields, type ExperimentView, FIRST_RUN_LINE, type FieldEditor, FieldInput, type FieldKind, type FormField, type GlossaryTerm, GlossaryText, type GlossaryTextProps, type GroupBucket, type GroupByAxis, type HumanText, type JourneyColdState, type JourneyEventView, type JourneyView, type LinkArgs, type LinkChoice, type LinkifyNode, type LinkifyOptions, Markdown, type Meter, type MeterKind, type MovePresentation, type NeedsHumanByRegister, type NeedsHumanCounts, type NeighbourChip, type NestedGroup, type NextColdStart, type NextMoveRecords, NextMoveSurface, type NextMoveSurfaceProps, type OtherMover, type Pill, type PipelineColdStart, type PipelineRow, PipelineSurface, type PipelineView, REGISTER_GROUPS, REGISTER_ICON, REGISTER_LABEL, REGISTER_ORDER, REGISTER_SINGULAR, REGISTER_SUBTITLE, RISK_CRIT, RISK_WARN, RecordDrawer, type RecordDrawerProps, RecordForm, type RecordFormProps, RecordPage, type RecordPageModel, type RecordPageProps, type RecordTabId, RegisterBrowser, type RegisterBrowserProps, type RegisterContext, RegisterCounts, type RegisterCountsProps, RegisterTable, type RegisterTableProps, type RelatedSet, RelationEditor, type RelationEditorProps, type RelationPanel, type ResolvedBarLine, type ResolvedRow, type RiskBand, RiskBar, type Route, type SaveResult, type SavedView, type ScoreChip, ScoreImpactForm, type ScoreImpactFormProps, type ShapedRegister, SidebarNav, type SidebarNavProps, type SortSpec, Sparkline, type StageMeterInput, type StageMeterView, StatTile, StatusPill, type StepInForm, type StoryStepIn, SurfacePlaceholder, type SurfacePlaceholderProps, type TabDef, type TermPreview, type Tone, type Understanding, UnderstandingPanel, type UseCountsResult, type UseCreateResult, type UseLinkResult, type UseListResult, type UseNeedsHumanResult, type UseRecordResult, type UseSavedViewsResult, type UseUpdateResult, ValidationOSDashboard, type ValidationOSDashboardProps, type ViewDescriptor, WriteDecisionForm, type WriteDecisionFormProps, backlinkPanels, bodyPreview, buildCycles, buildJourney, buildPatch, buildPipeline, buildRecordPage, buildUnderstanding, cellValue, coldStartFor, columnsFor, composeConnectCommand, confidenceTone, configureRiskBands, defaultTabId, detailRows, dontConfuseWith, draftFrom, editableFields, emptyDraft, eventStepIn, eventTone, filterRecords, formFieldsFor, formatCount, formatRoute, formatSigned, formatValue, groupByAxesFor, groupRecords, hasEdits, headerPills, humanInputFields, interpretSave, journeyColdState, leadingMeters, linkChoicesFrom, linkify, missingRequired, movePresentation, needsHumanCounts, nestReadingsByPlan, ownerNames, parseRoute, primaryLabel, readingAssumptionChips, readingBeliefVerdicts, resolveBarLines, riskBand, riskFraction, riskLevel, scoreChip, shapeRegister, sortRecords, sparklinePath, stageMeters, statusTone, tabsFor, toCreatePayload, toGlossaryTerms, toNextMoveInput, toStageExperimentInput, useCounts, useCreate, useLink, useList, useNeedsHuman, useRecord, useSavedViews, useUpdate, weekOverWeekDelta };
|