@validation-os/core 0.5.0 → 0.6.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/chunk-22WJF5EZ.js +572 -0
- package/dist/chunk-22WJF5EZ.js.map +1 -0
- package/dist/{chunk-W7VU5JOU.js → chunk-43RQBE2E.js} +1 -12
- package/dist/{chunk-W7VU5JOU.js.map → chunk-43RQBE2E.js.map} +1 -1
- package/dist/derivation/index.d.ts +2 -2
- package/dist/derivation/index.js +33 -5
- package/dist/index-BlXH_thK.d.ts +577 -0
- package/dist/index.d.ts +6 -31
- package/dist/index.js +22 -26
- package/dist/index.js.map +1 -1
- package/dist/{provider-hW8Hxf-n.d.ts → provider-DGr5Xq5U.d.ts} +1 -1
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +1 -1
- package/dist/{types-B3eI7ASx.d.ts → types-BAyl0w2E.d.ts} +66 -32
- package/package.json +1 -1
- package/dist/chunk-4Q2B2QT3.js +0 -279
- package/dist/chunk-4Q2B2QT3.js.map +0 -1
- package/dist/index-CieW13mJ.d.ts +0 -234
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__export
|
|
3
|
+
} from "./chunk-PZ5AY32C.js";
|
|
4
|
+
|
|
5
|
+
// src/derivation/index.ts
|
|
6
|
+
var derivation_exports = {};
|
|
7
|
+
__export(derivation_exports, {
|
|
8
|
+
COMPLETENESS_SLOTS: () => COMPLETENESS_SLOTS,
|
|
9
|
+
KILL_LANE_THRESHOLD: () => KILL_LANE_THRESHOLD,
|
|
10
|
+
MARKET_RUNG_ANCHOR: () => MARKET_RUNG_ANCHOR,
|
|
11
|
+
RUNG_ANCHOR: () => RUNG_ANCHOR,
|
|
12
|
+
W0: () => W0,
|
|
13
|
+
assembleJourney: () => assembleJourney,
|
|
14
|
+
assumptionComplete: () => assumptionComplete,
|
|
15
|
+
assumptionCompleteness: () => assumptionCompleteness,
|
|
16
|
+
beliefRisk: () => beliefRisk,
|
|
17
|
+
beliefTestMeters: () => beliefTestMeters,
|
|
18
|
+
classifyStage: () => classifyStage,
|
|
19
|
+
completenessSlotPresence: () => completenessSlotPresence,
|
|
20
|
+
confidence: () => confidence,
|
|
21
|
+
confidenceAttribution: () => confidenceAttribution,
|
|
22
|
+
confidenceTrajectory: () => confidenceTrajectory,
|
|
23
|
+
deriveBeliefStage: () => deriveBeliefStage,
|
|
24
|
+
derivedImpacts: () => derivedImpacts,
|
|
25
|
+
emptyTestMeter: () => emptyTestMeter,
|
|
26
|
+
experimentProgress: () => experimentProgress,
|
|
27
|
+
isConcluded: () => isConcluded,
|
|
28
|
+
isMarketRung: () => isMarketRung,
|
|
29
|
+
missingCompletenessSlots: () => missingCompletenessSlots,
|
|
30
|
+
portfolioProgress: () => portfolioProgress,
|
|
31
|
+
rankNextMoves: () => rankNextMoves,
|
|
32
|
+
readingStrength: () => readingStrength,
|
|
33
|
+
risk: () => risk,
|
|
34
|
+
round2: () => round2,
|
|
35
|
+
scoreAndDedupe: () => scoreAndDedupe,
|
|
36
|
+
sign: () => sign,
|
|
37
|
+
sourceQuality: () => sourceQuality
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// src/derivation/round.ts
|
|
41
|
+
function round2(n) {
|
|
42
|
+
return Number(n.toFixed(2));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/types.ts
|
|
46
|
+
var REGISTERS = [
|
|
47
|
+
"assumptions",
|
|
48
|
+
"experiments",
|
|
49
|
+
"readings",
|
|
50
|
+
"decisions",
|
|
51
|
+
"glossary"
|
|
52
|
+
];
|
|
53
|
+
var TESTING_RUNGS = [
|
|
54
|
+
"Opinion",
|
|
55
|
+
"Pitch-deck reaction",
|
|
56
|
+
"Anecdotal",
|
|
57
|
+
"Desk research",
|
|
58
|
+
"Survey at scale",
|
|
59
|
+
"Prototype usage"
|
|
60
|
+
];
|
|
61
|
+
var MARKET_RUNG_VALUES = ["Signed intent", "Paying users"];
|
|
62
|
+
|
|
63
|
+
// src/derivation/rung.ts
|
|
64
|
+
var RUNG_ANCHOR = {
|
|
65
|
+
Opinion: 3,
|
|
66
|
+
"Pitch-deck reaction": 6,
|
|
67
|
+
Anecdotal: 10,
|
|
68
|
+
"Desk research": 15,
|
|
69
|
+
"Survey at scale": 25,
|
|
70
|
+
"Prototype usage": 30
|
|
71
|
+
};
|
|
72
|
+
var MARKET_RUNG_ANCHOR = {
|
|
73
|
+
"Signed intent": { Low: 55, Typical: 68, High: 80 },
|
|
74
|
+
"Paying users": { Low: 75, Typical: 88, High: 99 }
|
|
75
|
+
};
|
|
76
|
+
var MARKET_RUNG_SET = new Set(MARKET_RUNG_VALUES);
|
|
77
|
+
function isMarketRung(rung) {
|
|
78
|
+
return MARKET_RUNG_SET.has(rung);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/derivation/completeness.ts
|
|
82
|
+
var COMPLETENESS_SLOTS = [
|
|
83
|
+
"Description",
|
|
84
|
+
"Lens",
|
|
85
|
+
"Impact",
|
|
86
|
+
"Scoring justification",
|
|
87
|
+
"Dependencies traced"
|
|
88
|
+
];
|
|
89
|
+
function hasText(value) {
|
|
90
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
91
|
+
}
|
|
92
|
+
function hasNumber(value) {
|
|
93
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
94
|
+
}
|
|
95
|
+
function hasAny(value) {
|
|
96
|
+
return Array.isArray(value) && value.length > 0;
|
|
97
|
+
}
|
|
98
|
+
function completenessSlotPresence(record) {
|
|
99
|
+
return {
|
|
100
|
+
Description: hasText(record.Description),
|
|
101
|
+
Lens: hasText(record.Lens),
|
|
102
|
+
Impact: hasNumber(record.Impact),
|
|
103
|
+
"Scoring justification": hasText(record["Scoring justification"]),
|
|
104
|
+
"Dependencies traced": hasAny(record.dependsOnIds) || hasAny(record.enablesIds)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function missingCompletenessSlots(record) {
|
|
108
|
+
const present = completenessSlotPresence(record);
|
|
109
|
+
return COMPLETENESS_SLOTS.filter((slot) => !present[slot]);
|
|
110
|
+
}
|
|
111
|
+
function assumptionCompleteness(record) {
|
|
112
|
+
const present = completenessSlotPresence(record);
|
|
113
|
+
const filled = COMPLETENESS_SLOTS.filter((slot) => present[slot]).length;
|
|
114
|
+
return Math.round(filled / COMPLETENESS_SLOTS.length * 100);
|
|
115
|
+
}
|
|
116
|
+
function assumptionComplete(record) {
|
|
117
|
+
return missingCompletenessSlots(record).length === 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/derivation/strength.ts
|
|
121
|
+
function sign(result) {
|
|
122
|
+
if (result === "Validated") return 1;
|
|
123
|
+
if (result === "Invalidated") return -1;
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
function isConcluded(result) {
|
|
127
|
+
return result === "Validated" || result === "Invalidated";
|
|
128
|
+
}
|
|
129
|
+
function readingStrength(input) {
|
|
130
|
+
const s = sign(input.result);
|
|
131
|
+
if (s === 0) return 0;
|
|
132
|
+
if (isMarketRung(input.rung)) {
|
|
133
|
+
const band = input.magnitudeBand ?? "Typical";
|
|
134
|
+
return MARKET_RUNG_ANCHOR[input.rung][band] * s;
|
|
135
|
+
}
|
|
136
|
+
return (RUNG_ANCHOR[input.rung] ?? 0) * s;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/derivation/source-quality.ts
|
|
140
|
+
function sourceQuality(representativeness, credibility) {
|
|
141
|
+
return round2(representativeness * credibility);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/derivation/confidence.ts
|
|
145
|
+
var W0 = 100;
|
|
146
|
+
function scoreAndDedupe(readings) {
|
|
147
|
+
const scored = readings.filter((r) => isConcluded(r.result)).map((r) => {
|
|
148
|
+
const strength = readingStrength(r);
|
|
149
|
+
const sq = sourceQuality(r.representativeness, r.credibility);
|
|
150
|
+
return { input: r, strength, sq, weight: Math.abs(strength) * sq };
|
|
151
|
+
}).filter((x) => x.strength !== 0);
|
|
152
|
+
const best = /* @__PURE__ */ new Map();
|
|
153
|
+
for (const x of scored) {
|
|
154
|
+
if (isMarketRung(x.input.rung)) {
|
|
155
|
+
best.set(x.input.id, x);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const key = x.input.source || x.input.id;
|
|
159
|
+
const cur = best.get(key);
|
|
160
|
+
const better = !cur || Math.abs(x.strength) > Math.abs(cur.strength) || Math.abs(x.strength) === Math.abs(cur.strength) && (x.input.date || "") > (cur.input.date || "");
|
|
161
|
+
if (better) best.set(key, x);
|
|
162
|
+
}
|
|
163
|
+
return [...best.values()];
|
|
164
|
+
}
|
|
165
|
+
function confidence(readings) {
|
|
166
|
+
const winners = scoreAndDedupe(readings);
|
|
167
|
+
let num = 0;
|
|
168
|
+
let den = W0;
|
|
169
|
+
for (const x of winners) {
|
|
170
|
+
num += x.weight * x.strength;
|
|
171
|
+
den += x.weight;
|
|
172
|
+
}
|
|
173
|
+
return den > 0 ? round2(num / den) : 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/derivation/attribution.ts
|
|
177
|
+
function bucketOf(r) {
|
|
178
|
+
if (r.experimentId) {
|
|
179
|
+
return {
|
|
180
|
+
key: r.experimentId,
|
|
181
|
+
kind: "experiment",
|
|
182
|
+
experimentId: r.experimentId
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return { key: "direct", kind: "direct", experimentId: null };
|
|
186
|
+
}
|
|
187
|
+
function confidenceAttribution(readings) {
|
|
188
|
+
const winners = scoreAndDedupe(readings);
|
|
189
|
+
const den = winners.reduce((acc, x) => acc + x.weight, W0);
|
|
190
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
191
|
+
let num = 0;
|
|
192
|
+
for (const x of winners) {
|
|
193
|
+
num += x.weight * x.strength;
|
|
194
|
+
const b = bucketOf(x.input);
|
|
195
|
+
const contribution = x.weight * x.strength / den;
|
|
196
|
+
const cur = byKey.get(b.key);
|
|
197
|
+
if (cur) {
|
|
198
|
+
cur.contribution += contribution;
|
|
199
|
+
cur.readingCount += 1;
|
|
200
|
+
cur.readingIds.push(x.input.id);
|
|
201
|
+
} else {
|
|
202
|
+
byKey.set(b.key, {
|
|
203
|
+
key: b.key,
|
|
204
|
+
kind: b.kind,
|
|
205
|
+
experimentId: b.experimentId,
|
|
206
|
+
contribution,
|
|
207
|
+
magnitude: 0,
|
|
208
|
+
// finalised below
|
|
209
|
+
readingCount: 1,
|
|
210
|
+
readingIds: [x.input.id]
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const movers = [...byKey.values()].map((m) => ({
|
|
215
|
+
...m,
|
|
216
|
+
contribution: round2(m.contribution),
|
|
217
|
+
magnitude: round2(Math.abs(m.contribution))
|
|
218
|
+
}));
|
|
219
|
+
movers.sort((a, b) => b.magnitude - a.magnitude);
|
|
220
|
+
return {
|
|
221
|
+
confidence: den > 0 ? round2(num / den) : 0,
|
|
222
|
+
movers
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/derivation/progress.ts
|
|
227
|
+
function experimentProgress(bars) {
|
|
228
|
+
const total = bars.length;
|
|
229
|
+
const settled = bars.filter(
|
|
230
|
+
(b) => typeof b.barVerdict === "string" && b.barVerdict.trim() !== ""
|
|
231
|
+
).length;
|
|
232
|
+
return {
|
|
233
|
+
total,
|
|
234
|
+
settled,
|
|
235
|
+
toGo: total - settled,
|
|
236
|
+
concluded: total > 0 && settled === total
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/derivation/trajectory.ts
|
|
241
|
+
function confidenceTrajectory(readings) {
|
|
242
|
+
const concluded = readings.filter((r) => isConcluded(r.result));
|
|
243
|
+
const undated = concluded.filter((r) => !r.date);
|
|
244
|
+
const dated = concluded.filter((r) => r.date);
|
|
245
|
+
if (dated.length === 0) return [];
|
|
246
|
+
const dates = [...new Set(dated.map((r) => r.date))].sort();
|
|
247
|
+
return dates.map((date) => ({
|
|
248
|
+
date,
|
|
249
|
+
// Everything dated on/before this point, plus the always-present undated.
|
|
250
|
+
confidence: confidence([
|
|
251
|
+
...undated,
|
|
252
|
+
...dated.filter((r) => r.date <= date)
|
|
253
|
+
])
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/derivation/impact.ts
|
|
258
|
+
function derivedImpacts(assumptions, basedOnCounts = {}) {
|
|
259
|
+
const byId = new Map(assumptions.map((a) => [a.id, a]));
|
|
260
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
261
|
+
for (const a of assumptions) dependents.set(a.id, []);
|
|
262
|
+
for (const a of assumptions) {
|
|
263
|
+
for (const dep of a.dependsOnIds) dependents.get(dep)?.push(a.id);
|
|
264
|
+
}
|
|
265
|
+
const memo = /* @__PURE__ */ new Map();
|
|
266
|
+
const compute = (id, seen) => {
|
|
267
|
+
const cached = memo.get(id);
|
|
268
|
+
if (cached !== void 0) return cached;
|
|
269
|
+
if (seen.has(id)) return 0;
|
|
270
|
+
seen.add(id);
|
|
271
|
+
const a = byId.get(id);
|
|
272
|
+
if (!a) return 0;
|
|
273
|
+
if (a.moot) {
|
|
274
|
+
memo.set(id, 0);
|
|
275
|
+
return 0;
|
|
276
|
+
}
|
|
277
|
+
const seed = a.impact ?? 0;
|
|
278
|
+
let S = 0;
|
|
279
|
+
for (const depId of dependents.get(id) ?? []) {
|
|
280
|
+
const d = byId.get(depId);
|
|
281
|
+
if (d && !d.moot) S += compute(depId, seen);
|
|
282
|
+
}
|
|
283
|
+
S += 100 * (basedOnCounts[id] ?? 0);
|
|
284
|
+
const value = seed + (100 - seed) * (S / (S + 100));
|
|
285
|
+
const rounded = round2(value);
|
|
286
|
+
memo.set(id, rounded);
|
|
287
|
+
return rounded;
|
|
288
|
+
};
|
|
289
|
+
const out = /* @__PURE__ */ new Map();
|
|
290
|
+
for (const a of assumptions) out.set(a.id, compute(a.id, /* @__PURE__ */ new Set()));
|
|
291
|
+
return out;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// src/derivation/risk.ts
|
|
295
|
+
function risk(derivedImpact, confidence2) {
|
|
296
|
+
return round2(derivedImpact * (1 - Math.max(0, confidence2) / 100));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/derivation/portfolio.ts
|
|
300
|
+
function beliefRisk(b) {
|
|
301
|
+
const seed = b.seedImpact ?? 0;
|
|
302
|
+
const identified = Math.max(b.derivedImpact, seed, 0);
|
|
303
|
+
const live = b.resolved ? 0 : Math.min(identified, Math.max(0, b.risk));
|
|
304
|
+
return {
|
|
305
|
+
identified: round2(identified),
|
|
306
|
+
live: round2(live),
|
|
307
|
+
retired: round2(identified - live)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function portfolioProgress(beliefs) {
|
|
311
|
+
let identified = 0;
|
|
312
|
+
let live = 0;
|
|
313
|
+
let liveCount = 0;
|
|
314
|
+
let resolvedCount = 0;
|
|
315
|
+
for (const b of beliefs) {
|
|
316
|
+
const r = beliefRisk(b);
|
|
317
|
+
identified += r.identified;
|
|
318
|
+
live += r.live;
|
|
319
|
+
if (b.resolved) resolvedCount += 1;
|
|
320
|
+
else liveCount += 1;
|
|
321
|
+
}
|
|
322
|
+
const retired = identified - live;
|
|
323
|
+
return {
|
|
324
|
+
identified: round2(identified),
|
|
325
|
+
retired: round2(retired),
|
|
326
|
+
live: round2(live),
|
|
327
|
+
percent: identified > 0 ? round2(retired / identified * 100) : 0,
|
|
328
|
+
liveCount,
|
|
329
|
+
resolvedCount
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/derivation/next-move.ts
|
|
334
|
+
var KILL_LANE_THRESHOLD = -50;
|
|
335
|
+
var FEASIBILITY_WEIGHT = {
|
|
336
|
+
High: 1,
|
|
337
|
+
Medium: 0.6,
|
|
338
|
+
Low: 0.3
|
|
339
|
+
};
|
|
340
|
+
var NEUTRAL_FEASIBILITY_WEIGHT = FEASIBILITY_WEIGHT.Medium;
|
|
341
|
+
function isStanding(decisionStatus) {
|
|
342
|
+
return decisionStatus === "Active" || decisionStatus === "Provisional";
|
|
343
|
+
}
|
|
344
|
+
function bestFeasibility(feasibilities) {
|
|
345
|
+
let best = null;
|
|
346
|
+
let bestWeight = -1;
|
|
347
|
+
for (const f of feasibilities) {
|
|
348
|
+
if (!f) continue;
|
|
349
|
+
const w = FEASIBILITY_WEIGHT[f];
|
|
350
|
+
if (w > bestWeight) {
|
|
351
|
+
bestWeight = w;
|
|
352
|
+
best = f;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return best;
|
|
356
|
+
}
|
|
357
|
+
function stageMove(a, hasRunningTest, hasAnyTest, hasStandingDecision) {
|
|
358
|
+
if (a.impact === null) return "score-impact";
|
|
359
|
+
if (a.concludedReadings === 0) {
|
|
360
|
+
return hasRunningTest ? "record-reading" : "design-experiment";
|
|
361
|
+
}
|
|
362
|
+
if (!hasStandingDecision) return "decide";
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
function reasonFor(move, a) {
|
|
366
|
+
switch (move) {
|
|
367
|
+
case "retest":
|
|
368
|
+
return `Confidence has fallen to ${Math.round(a.confidence)} \u2014 the evidence is turning against this belief. Kill it or test it again.`;
|
|
369
|
+
case "score-impact":
|
|
370
|
+
return "This belief isn't weighted yet \u2014 score its impact so its risk can rank against the rest.";
|
|
371
|
+
case "design-experiment":
|
|
372
|
+
return `Your riskiest untested belief. Design the cheapest honest test that could move it.`;
|
|
373
|
+
case "record-reading":
|
|
374
|
+
return "A test is running against this belief \u2014 evidence is still landing.";
|
|
375
|
+
case "decide":
|
|
376
|
+
return "The evidence is in and nothing rests on it yet \u2014 time to make the call.";
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function rankNextMoves(input) {
|
|
380
|
+
const { assumptions, experiments, decisions } = input;
|
|
381
|
+
const testsByAssumption = /* @__PURE__ */ new Map();
|
|
382
|
+
for (const exp of experiments) {
|
|
383
|
+
const running = exp.status === "Running";
|
|
384
|
+
for (const id of exp.assumptionIds) {
|
|
385
|
+
const entry = testsByAssumption.get(id) ?? {
|
|
386
|
+
running: false,
|
|
387
|
+
any: false,
|
|
388
|
+
feasibilities: []
|
|
389
|
+
};
|
|
390
|
+
entry.any = true;
|
|
391
|
+
entry.running = entry.running || running;
|
|
392
|
+
entry.feasibilities.push(exp.feasibility);
|
|
393
|
+
testsByAssumption.set(id, entry);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const decidedAssumptions = /* @__PURE__ */ new Set();
|
|
397
|
+
for (const d of decisions) {
|
|
398
|
+
if (!isStanding(d.status)) continue;
|
|
399
|
+
for (const id of d.assumptionIds) decidedAssumptions.add(id);
|
|
400
|
+
}
|
|
401
|
+
const moves = [];
|
|
402
|
+
for (const a of assumptions) {
|
|
403
|
+
if (a.moot || a.status === "Invalidated") continue;
|
|
404
|
+
const killLane = a.confidence <= KILL_LANE_THRESHOLD;
|
|
405
|
+
const tests = testsByAssumption.get(a.id);
|
|
406
|
+
const feasibility = bestFeasibility(tests?.feasibilities ?? []);
|
|
407
|
+
const move = killLane ? "retest" : stageMove(
|
|
408
|
+
a,
|
|
409
|
+
tests?.running ?? false,
|
|
410
|
+
tests?.any ?? false,
|
|
411
|
+
decidedAssumptions.has(a.id)
|
|
412
|
+
);
|
|
413
|
+
if (move === null) continue;
|
|
414
|
+
const weight = feasibility ? FEASIBILITY_WEIGHT[feasibility] : NEUTRAL_FEASIBILITY_WEIGHT;
|
|
415
|
+
const score = round2(killLane ? a.risk : weight * a.risk);
|
|
416
|
+
moves.push({
|
|
417
|
+
move,
|
|
418
|
+
assumptionId: a.id,
|
|
419
|
+
title: a.title,
|
|
420
|
+
score,
|
|
421
|
+
reason: reasonFor(move, a),
|
|
422
|
+
risk: a.risk,
|
|
423
|
+
confidence: a.confidence,
|
|
424
|
+
feasibility,
|
|
425
|
+
killLane
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
moves.sort((x, y) => {
|
|
429
|
+
if (x.killLane !== y.killLane) return x.killLane ? -1 : 1;
|
|
430
|
+
if (y.score !== x.score) return y.score - x.score;
|
|
431
|
+
if (x.confidence !== y.confidence) return x.confidence - y.confidence;
|
|
432
|
+
return x.assumptionId < y.assumptionId ? -1 : 1;
|
|
433
|
+
});
|
|
434
|
+
return moves;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/derivation/stage.ts
|
|
438
|
+
function emptyTestMeter() {
|
|
439
|
+
return { planned: false, settled: 0, total: 0 };
|
|
440
|
+
}
|
|
441
|
+
function beliefTestMeters(experiments) {
|
|
442
|
+
const byAssumption = /* @__PURE__ */ new Map();
|
|
443
|
+
const ensure = (id) => {
|
|
444
|
+
let s = byAssumption.get(id);
|
|
445
|
+
if (!s) {
|
|
446
|
+
s = emptyTestMeter();
|
|
447
|
+
byAssumption.set(id, s);
|
|
448
|
+
}
|
|
449
|
+
return s;
|
|
450
|
+
};
|
|
451
|
+
for (const exp of experiments) {
|
|
452
|
+
for (const b of exp.bars) {
|
|
453
|
+
if (!b.assumptionId) continue;
|
|
454
|
+
const s = ensure(b.assumptionId);
|
|
455
|
+
s.planned = true;
|
|
456
|
+
s.total += 1;
|
|
457
|
+
if (b.settled) s.settled += 1;
|
|
458
|
+
}
|
|
459
|
+
for (const id of exp.plannedAssumptionIds) ensure(id).planned = true;
|
|
460
|
+
}
|
|
461
|
+
return byAssumption;
|
|
462
|
+
}
|
|
463
|
+
function classifyStage(framed, test) {
|
|
464
|
+
if (framed < 100) return "framed";
|
|
465
|
+
if (!test.planned) return "planned";
|
|
466
|
+
if (test.total === 0 || test.settled < test.total) return "tested";
|
|
467
|
+
return "known";
|
|
468
|
+
}
|
|
469
|
+
function deriveBeliefStage(input) {
|
|
470
|
+
const { framed, confidence: confidence2, test } = input;
|
|
471
|
+
return {
|
|
472
|
+
stage: classifyStage(framed, test),
|
|
473
|
+
framed,
|
|
474
|
+
planned: test.planned,
|
|
475
|
+
tested: { settled: test.settled, total: test.total },
|
|
476
|
+
confidence: confidence2,
|
|
477
|
+
confSign: confidence2 > 0 ? "pos" : confidence2 < 0 ? "neg" : "zero",
|
|
478
|
+
killZone: confidence2 <= KILL_LANE_THRESHOLD
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// src/derivation/journey.ts
|
|
483
|
+
var KIND_ORDER = {
|
|
484
|
+
bet: 0,
|
|
485
|
+
score: 1,
|
|
486
|
+
experiment: 2,
|
|
487
|
+
reading: 3,
|
|
488
|
+
"confidence-cross": 4,
|
|
489
|
+
now: 5
|
|
490
|
+
};
|
|
491
|
+
function assembleJourney(input) {
|
|
492
|
+
const { belief, readings, experiments, now } = input;
|
|
493
|
+
const events = [];
|
|
494
|
+
if (belief.createdAt) {
|
|
495
|
+
events.push(event("bet", belief.createdAt));
|
|
496
|
+
}
|
|
497
|
+
if (belief.impactScored) {
|
|
498
|
+
events.push(event("score", null));
|
|
499
|
+
}
|
|
500
|
+
for (const e of experiments) {
|
|
501
|
+
events.push(event("experiment", e.date, { refId: e.id }));
|
|
502
|
+
}
|
|
503
|
+
const trajectory = confidenceTrajectory(readings);
|
|
504
|
+
const confByDate = new Map(trajectory.map((p) => [p.date, p.confidence]));
|
|
505
|
+
for (const r of readings) {
|
|
506
|
+
const dated = r.date ?? null;
|
|
507
|
+
const conf = dated && isConcluded(r.result) ? confByDate.get(dated) ?? null : null;
|
|
508
|
+
events.push(
|
|
509
|
+
event("reading", dated, { confidence: conf, result: r.result, refId: r.id })
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
const cross = trajectory.find((p) => p.confidence <= KILL_LANE_THRESHOLD);
|
|
513
|
+
if (cross) {
|
|
514
|
+
events.push(event("confidence-cross", cross.date, { confidence: cross.confidence }));
|
|
515
|
+
}
|
|
516
|
+
const anchor = belief.createdAt ?? "";
|
|
517
|
+
events.sort((a, b) => {
|
|
518
|
+
const ka = a.date ?? anchor;
|
|
519
|
+
const kb = b.date ?? anchor;
|
|
520
|
+
if (ka !== kb) return ka < kb ? -1 : 1;
|
|
521
|
+
return KIND_ORDER[a.kind] - KIND_ORDER[b.kind];
|
|
522
|
+
});
|
|
523
|
+
events.push(event("now", now, { confidence: confidence(readings) }));
|
|
524
|
+
return events;
|
|
525
|
+
}
|
|
526
|
+
function event(kind, date, extra = {}) {
|
|
527
|
+
return {
|
|
528
|
+
kind,
|
|
529
|
+
date,
|
|
530
|
+
confidence: extra.confidence ?? null,
|
|
531
|
+
result: extra.result ?? null,
|
|
532
|
+
refId: extra.refId ?? null
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export {
|
|
537
|
+
REGISTERS,
|
|
538
|
+
TESTING_RUNGS,
|
|
539
|
+
MARKET_RUNG_VALUES,
|
|
540
|
+
COMPLETENESS_SLOTS,
|
|
541
|
+
completenessSlotPresence,
|
|
542
|
+
missingCompletenessSlots,
|
|
543
|
+
assumptionCompleteness,
|
|
544
|
+
assumptionComplete,
|
|
545
|
+
round2,
|
|
546
|
+
RUNG_ANCHOR,
|
|
547
|
+
MARKET_RUNG_ANCHOR,
|
|
548
|
+
isMarketRung,
|
|
549
|
+
sign,
|
|
550
|
+
isConcluded,
|
|
551
|
+
readingStrength,
|
|
552
|
+
sourceQuality,
|
|
553
|
+
W0,
|
|
554
|
+
scoreAndDedupe,
|
|
555
|
+
confidence,
|
|
556
|
+
confidenceAttribution,
|
|
557
|
+
experimentProgress,
|
|
558
|
+
confidenceTrajectory,
|
|
559
|
+
derivedImpacts,
|
|
560
|
+
risk,
|
|
561
|
+
beliefRisk,
|
|
562
|
+
portfolioProgress,
|
|
563
|
+
KILL_LANE_THRESHOLD,
|
|
564
|
+
rankNextMoves,
|
|
565
|
+
emptyTestMeter,
|
|
566
|
+
beliefTestMeters,
|
|
567
|
+
classifyStage,
|
|
568
|
+
deriveBeliefStage,
|
|
569
|
+
assembleJourney,
|
|
570
|
+
derivation_exports
|
|
571
|
+
};
|
|
572
|
+
//# sourceMappingURL=chunk-22WJF5EZ.js.map
|