@idlekit/cli 0.6.0 → 0.7.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/main.js CHANGED
@@ -6605,6 +6605,69 @@ var require_src = __commonJS(function(exports, module) {
6605
6605
  module.exports = { cursor, scroll, erase, beep };
6606
6606
  });
6607
6607
 
6608
+ // src/runtime/invocation.ts
6609
+ import { AsyncLocalStorage } from "async_hooks";
6610
+ import { resolve } from "path";
6611
+ function runWithInvocation(invocation, fn) {
6612
+ return storage.run({ ...invocation, reads: new Set }, fn);
6613
+ }
6614
+ function recordInputRead(path) {
6615
+ storage.getStore()?.reads.add(resolve(path));
6616
+ }
6617
+ function flagPaths(key, value) {
6618
+ if (typeof value !== "string" || !value.trim())
6619
+ return [];
6620
+ if (LIST_FLAGS.has(key))
6621
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
6622
+ return INPUT_FLAGS.has(key) ? [value] : [];
6623
+ }
6624
+ function recordNestedInputs(base, positional, flags) {
6625
+ for (const value of positional)
6626
+ if (value.length > 0)
6627
+ recordInputRead(resolve(base, value));
6628
+ for (const [key, value] of Object.entries(flags))
6629
+ for (const path of flagPaths(key, value))
6630
+ recordInputRead(resolve(base, path));
6631
+ }
6632
+ function invocationInputCandidates(options = {}) {
6633
+ const invocation = storage.getStore();
6634
+ if (!invocation)
6635
+ return [];
6636
+ const allow = new Set(options.allow ?? []);
6637
+ const allowed = new Set;
6638
+ const candidates = [];
6639
+ for (const [key, value] of Object.entries(invocation.flags)) {
6640
+ const paths = flagPaths(key, value);
6641
+ if (allow.has(key))
6642
+ for (const path of paths)
6643
+ allowed.add(resolve(path));
6644
+ else
6645
+ candidates.push(...paths);
6646
+ }
6647
+ for (const path of invocation.reads)
6648
+ if (!allowed.has(path))
6649
+ candidates.push(path);
6650
+ return candidates;
6651
+ }
6652
+ var INPUT_FLAGS, LIST_FLAGS, storage;
6653
+ var init_invocation = __esm(() => {
6654
+ INPUT_FLAGS = new Set([
6655
+ "scenario",
6656
+ "baseline",
6657
+ "current",
6658
+ "baseline-artifact",
6659
+ "tune",
6660
+ "checks",
6661
+ "rubric",
6662
+ "cache",
6663
+ "resume",
6664
+ "rc",
6665
+ "plugin-trust-file"
6666
+ ]);
6667
+ LIST_FLAGS = new Set(["plugin"]);
6668
+ storage = new AsyncLocalStorage;
6669
+ });
6670
+
6608
6671
  // ../core/dist/engine/types.js
6609
6672
  var init_types = () => {};
6610
6673
 
@@ -8397,7 +8460,7 @@ var init_validate = __esm(() => {
8397
8460
  OFFLINE_ACTORS = new Set(["player", "automation"]);
8398
8461
  });
8399
8462
 
8400
- // ../../node_modules/.bun/typia@15.1.0+367f7514c87f1df1/node_modules/typia/lib/internal/_validateReport.mjs
8463
+ // ../../node_modules/.bun/typia@15.2.2+38c91d72aa8392f2/node_modules/typia/lib/internal/_validateReport.mjs
8401
8464
  var _validateReport = (array) => {
8402
8465
  const isAncestor = (ancestor, descendant) => descendant === ancestor || descendant.startsWith(`${ancestor}.`) || descendant.startsWith(`${ancestor}[`);
8403
8466
  const reportable = (path) => {
@@ -8422,7 +8485,7 @@ var _validateReport = (array) => {
8422
8485
  };
8423
8486
  var init__validateReport = () => {};
8424
8487
 
8425
- // ../../node_modules/.bun/typia@15.1.0+367f7514c87f1df1/node_modules/typia/lib/internal/_createStandardSchema.mjs
8488
+ // ../../node_modules/.bun/typia@15.2.2+38c91d72aa8392f2/node_modules/typia/lib/internal/_createStandardSchema.mjs
8426
8489
  var _createStandardSchema = (fn) => Object.assign(fn, { "~standard": {
8427
8490
  version: 1,
8428
8491
  vendor: "typia",
@@ -10693,6 +10756,14 @@ var init_goalRead = __esm(() => {
10693
10756
  ledgers = new WeakMap;
10694
10757
  });
10695
10758
 
10759
+ // ../core/dist/sim/milestoneKeys.js
10760
+ function actionMilestoneKeys(actionId) {
10761
+ return [`action.${actionId}.firstApplied`, "progress.first-upgrade"];
10762
+ }
10763
+ function mayRecordAtActionStart(key) {
10764
+ return key === "progress.first-upgrade" || key.startsWith("action.") && key.endsWith(".firstApplied");
10765
+ }
10766
+
10696
10767
  // ../core/dist/sim/observation.js
10697
10768
  function emitCommittedResets(observer, resets) {
10698
10769
  if (!observer?.onReset || resets.length === 0)
@@ -10873,7 +10944,11 @@ function createObservationRecorder(args) {
10873
10944
  milestones.push(sample);
10874
10945
  }
10875
10946
  if (args.observer?.onMilestone) {
10876
- notify(() => args.observer?.onMilestone?.({ t: sample.firstSeenT, key: sample.key }));
10947
+ notify(() => args.observer?.onMilestone?.({
10948
+ t: sample.firstSeenT,
10949
+ key: sample.key,
10950
+ phase: sample.source === "action" ? "action-start" : "income-end"
10951
+ }));
10877
10952
  }
10878
10953
  };
10879
10954
  const open = (goal) => !reachedGoals.has(goal.id) && !droppedGoals.has(goal.id);
@@ -10931,8 +11006,8 @@ function createObservationRecorder(args) {
10931
11006
  if (args.observer?.onAction) {
10932
11007
  notify(() => args.observer?.onAction?.({ t: step.t0, actionId: event.actionId, outcome: "applied" }));
10933
11008
  }
10934
- rememberMilestone({ key: `action.${event.actionId}.firstApplied`, firstSeenT: step.t0, source: "action" });
10935
- rememberMilestone({ key: "progress.first-upgrade", firstSeenT: step.t0, source: "action" });
11009
+ for (const key of actionMilestoneKeys(event.actionId))
11010
+ rememberMilestone({ key, firstSeenT: step.t0, source: "action" });
10936
11011
  } else if (event.type === "action.skipped") {
10937
11012
  if (event.reason === "cannotApply")
10938
11013
  actions.skippedCannotApply += 1;
@@ -13052,11 +13127,12 @@ function finiteAmountLog10(E, amount) {
13052
13127
  throw new RangeError("Tuning requires finite monetary amounts in the selected engine");
13053
13128
  const value = E.absLog10(amount);
13054
13129
  if (value === Number.NEGATIVE_INFINITY)
13055
- return -300;
13130
+ return ZERO_AMOUNT_LOG10_FLOOR;
13056
13131
  if (!Number.isFinite(value))
13057
13132
  throw new RangeError("Tuning requires a finite monetary logarithm");
13058
- return value;
13133
+ return Math.max(ZERO_AMOUNT_LOG10_FLOOR, value);
13059
13134
  }
13135
+ var ZERO_AMOUNT_LOG10_FLOOR = -300;
13060
13136
 
13061
13137
  // ../core/dist/sim/strategy/opt/objectives/builtins.js
13062
13138
  var builtinObjectiveFactories;
@@ -15164,15 +15240,16 @@ function readBenefit(vars) {
15164
15240
  const value = vars.benefit;
15165
15241
  return typeof value === "number" && Number.isFinite(value) ? value : null;
15166
15242
  }
15167
- function observeMetrics(E, spec, end, startT, reachedAt, elapsedSec) {
15243
+ function observeMetrics(E, spec, end, moneyElapsedSec, milestoneElapsedSec, elapsedSec) {
15168
15244
  const amount = end.wallet.money.amount;
15169
15245
  const benefit = readBenefit(end.vars);
15170
15246
  return metricIds(spec).map((metricId) => {
15171
- if (metricId === "timeToMoney") {
15172
- if (reachedAt === undefined) {
15173
- return { metricId, status: "censored", value: null, lowerBound: { sec: elapsedSec, strict: true } };
15247
+ if (metricId === "timeToMoney" || metricId === "timeToMilestone") {
15248
+ const elapsed = metricId === "timeToMoney" ? moneyElapsedSec : milestoneElapsedSec;
15249
+ if (elapsed === undefined) {
15250
+ const strict = metricId === "timeToMoney" || !mayRecordAtActionStart(spec.milestoneKey ?? "");
15251
+ return { metricId, status: "censored", value: null, lowerBound: { sec: elapsedSec, strict } };
15174
15252
  }
15175
- const elapsed = reachedAt - startT;
15176
15253
  return { metricId, status: "observed", value: String(elapsed), num: elapsed };
15177
15254
  }
15178
15255
  if (metricId === "endMoney") {
@@ -15195,7 +15272,7 @@ function aggregate(E, rows, metricId) {
15195
15272
  }
15196
15273
  if (picked.some((metric) => metric.status !== "observed" || metric.value === null)) {
15197
15274
  const bounded = picked.every((metric) => metric.num !== undefined || metric.lowerBound !== undefined);
15198
- if (metricId !== "timeToMoney" || !bounded)
15275
+ if (metricId !== "timeToMoney" && metricId !== "timeToMilestone" || !bounded)
15199
15276
  return { metricId, status: "censored", value: null };
15200
15277
  const bounds = picked.map((metric) => metric.num ?? metric.lowerBound.sec);
15201
15278
  const total = bounds.reduce((sum, bound) => sum + bound, 0);
@@ -15282,6 +15359,10 @@ function prepareExperiment(request) {
15282
15359
  reject("goal target must be finite");
15283
15360
  if (metrics.includes("timeToMoney") && spec.goal === undefined)
15284
15361
  reject("timeToMoney requires a finite goal target");
15362
+ if (spec.milestoneKey !== undefined && spec.milestoneKey.trim().length === 0)
15363
+ reject("milestoneKey must not be blank");
15364
+ if (metrics.includes("timeToMilestone") && spec.milestoneKey === undefined)
15365
+ reject("timeToMilestone requires milestoneKey");
15285
15366
  if (!isJsonData(request.spec, new Set, true))
15286
15367
  reject("spec must be JSON data, because the spec hashes record it as JSON");
15287
15368
  requireScenarioData(request.scenario);
@@ -15308,7 +15389,8 @@ function checkExperimentSpec(request) {
15308
15389
  }
15309
15390
  function runExperiment(request) {
15310
15391
  const { spec, metrics, base, prepared, specHashes } = prepareExperiment(request);
15311
- const measuresReach = metrics.includes("timeToMoney");
15392
+ const measuresMoney = metrics.includes("timeToMoney");
15393
+ const measuresMilestone = metrics.includes("timeToMilestone");
15312
15394
  const E = request.engine;
15313
15395
  const { strategy: _scenarioStrategy, ...withoutStrategy } = request.scenario;
15314
15396
  const compiled = compileScenario({
@@ -15327,7 +15409,7 @@ function runExperiment(request) {
15327
15409
  models: request.modelRegistry,
15328
15410
  strategies: request.strategyRegistry
15329
15411
  });
15330
- const target = measuresReach && spec.goal !== undefined ? E.from(spec.goal.target) : undefined;
15412
+ const target = measuresMoney && spec.goal !== undefined ? E.from(spec.goal.target) : undefined;
15331
15413
  const stopAtReach = metrics.every((metricId) => metricId === "timeToMoney");
15332
15414
  const tasks = [];
15333
15415
  const perCandidate = [];
@@ -15352,21 +15434,41 @@ function runExperiment(request) {
15352
15434
  try {
15353
15435
  const opened = binding.fresh({ trialId: taskId, seed, plan });
15354
15436
  const scenario = opened.scenario;
15355
- let reachedAt;
15437
+ let moneyElapsedSec;
15438
+ let milestoneElapsedSec;
15439
+ let observedElapsedSec = 0;
15440
+ let stepStartElapsedSec = 0;
15356
15441
  const result = runScenario({
15357
15442
  ...scenario,
15358
15443
  run: {
15359
15444
  ...scenario.run,
15445
+ ...measuresMoney || measuresMilestone ? {
15446
+ observation: { ...scenario.run.observation, enabled: true, ...measuresMilestone ? { maxMilestones: 0 } : {} },
15447
+ observer: {
15448
+ ...scenario.run.observer,
15449
+ onStep: (fact) => {
15450
+ stepStartElapsedSec = observedElapsedSec;
15451
+ observedElapsedSec += fact.dt;
15452
+ scenario.run.observer?.onStep?.(fact);
15453
+ },
15454
+ onMilestone: (fact) => {
15455
+ if (measuresMilestone && milestoneElapsedSec === undefined && fact.key === spec.milestoneKey) {
15456
+ milestoneElapsedSec = fact.phase === "action-start" ? stepStartElapsedSec : observedElapsedSec;
15457
+ }
15458
+ scenario.run.observer?.onMilestone?.(fact);
15459
+ }
15460
+ }
15461
+ } : {},
15360
15462
  ...target !== undefined ? {
15361
15463
  until: (state) => {
15362
- if (reachedAt === undefined && E.cmp(state.wallet.money.amount, target) >= 0)
15363
- reachedAt = state.t;
15364
- return stopAtReach && reachedAt !== undefined;
15464
+ if (moneyElapsedSec === undefined && E.cmp(state.wallet.money.amount, target) >= 0)
15465
+ moneyElapsedSec = observedElapsedSec;
15466
+ return stopAtReach && moneyElapsedSec !== undefined;
15365
15467
  }
15366
15468
  } : {}
15367
15469
  }
15368
15470
  });
15369
- readings = observeMetrics(E, spec, result.end, result.start.t, reachedAt, runElapsedSec(result));
15471
+ readings = observeMetrics(E, spec, result.end, moneyElapsedSec, milestoneElapsedSec, runElapsedSec(result));
15370
15472
  } catch {
15371
15473
  readings = failedMetrics(spec);
15372
15474
  }
@@ -15454,6 +15556,7 @@ function runExperiment(request) {
15454
15556
  originalSpecHash: specHashes.original,
15455
15557
  effectiveSpecHash: specHashes.effective,
15456
15558
  effectiveRunHash: request.effectiveRunHash,
15559
+ ...measuresMilestone ? { milestoneKey: spec.milestoneKey } : {},
15457
15560
  budget: {
15458
15561
  candidates: spec.budget.candidates,
15459
15562
  seeds: spec.budget.seeds,
@@ -15483,30 +15586,31 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15483
15586
  const _ip8 = (input) => typeof input["originalSpecHash"] === "string";
15484
15587
  const _ip9 = (input) => typeof input["effectiveSpecHash"] === "string";
15485
15588
  const _ip10 = (input) => typeof input["effectiveRunHash"] === "string";
15486
- const _ip11 = (input) => typeof input["budget"] === "object" && input["budget"] !== null && _io2(input["budget"]);
15487
- const _ip12 = (input) => Array.isArray(input["tasks"]) && input["tasks"].every((elem) => typeof elem === "object" && elem !== null && _io3(elem));
15488
- const _ip13 = (input) => Array.isArray(input["candidates"]) && input["candidates"].every((elem) => typeof elem === "object" && elem !== null && _io4(elem));
15489
- const _ip14 = (input) => Array.isArray(input["elasticities"]) && input["elasticities"].every((elem) => typeof elem === "object" && elem !== null && _io6(elem));
15490
- const _ip15 = (input) => typeof input["pareto"] === "object" && input["pareto"] !== null && _io7(input["pareto"]);
15491
- const _ip16 = (input) => Array.isArray(input["warnings"]) && input["warnings"].every((elem) => typeof elem === "string");
15492
- const _ip17 = (input) => typeof input["taskId"] === "string";
15493
- const _ip18 = (input) => typeof input["candidateId"] === "string";
15494
- const _ip19 = (input) => typeof input["logicalSeed"] === "number";
15495
- const _ip20 = (input) => typeof input["engineId"] === "string";
15496
- const _ip21 = (input) => typeof input["engineVersion"] === "string";
15497
- const _ip22 = (input) => typeof input["modelId"] === "string";
15498
- const _ip23 = (input) => typeof input["modelVersion"] === "number";
15499
- const _ip24 = (input) => input["strategyId"] === null || typeof input["strategyId"] === "string";
15500
- const _ip25 = (input) => typeof input["modelParams"] === "string";
15501
- const _ip26 = (input) => typeof input["strategyParams"] === "string";
15502
- const _ip27 = (input) => typeof input["sessionPattern"] === "string";
15503
- const _ip28 = (input) => typeof input["sessionDays"] === "number";
15504
- const _ip29 = (input) => typeof input["horizonSec"] === "number";
15505
- const _ip30 = (input) => typeof input["stepSec"] === "number";
15506
- const _ip31 = (input) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit";
15507
- const _ip32 = (input) => input["status"] === "censored" || input["status"] === "failed" || input["status"] === "observed" || input["status"] === "rejected";
15508
- const _ip33 = (input) => input["value"] === null || typeof input["value"] === "string";
15509
- const _ve0 = 'Readonly<{ schemaVersion: 1; contract: "idlekit.experiment.v1"; estimatorVersion: "one-at-a-time-local-v1"; algorithmVersion: "experiment-oat-v1"; method: "fixed-sweep-and-one-at-a-time"; ... 11 more ...; warnings: readonly string[]; }>';
15589
+ const _ip11 = (input) => input["milestoneKey"] === undefined || typeof input["milestoneKey"] === "string";
15590
+ const _ip12 = (input) => typeof input["budget"] === "object" && input["budget"] !== null && _io2(input["budget"]);
15591
+ const _ip13 = (input) => Array.isArray(input["tasks"]) && input["tasks"].every((elem) => typeof elem === "object" && elem !== null && _io3(elem));
15592
+ const _ip14 = (input) => Array.isArray(input["candidates"]) && input["candidates"].every((elem) => typeof elem === "object" && elem !== null && _io4(elem));
15593
+ const _ip15 = (input) => Array.isArray(input["elasticities"]) && input["elasticities"].every((elem) => typeof elem === "object" && elem !== null && _io6(elem));
15594
+ const _ip16 = (input) => typeof input["pareto"] === "object" && input["pareto"] !== null && _io7(input["pareto"]);
15595
+ const _ip17 = (input) => Array.isArray(input["warnings"]) && input["warnings"].every((elem) => typeof elem === "string");
15596
+ const _ip18 = (input) => typeof input["taskId"] === "string";
15597
+ const _ip19 = (input) => typeof input["candidateId"] === "string";
15598
+ const _ip20 = (input) => typeof input["logicalSeed"] === "number";
15599
+ const _ip21 = (input) => typeof input["engineId"] === "string";
15600
+ const _ip22 = (input) => typeof input["engineVersion"] === "string";
15601
+ const _ip23 = (input) => typeof input["modelId"] === "string";
15602
+ const _ip24 = (input) => typeof input["modelVersion"] === "number";
15603
+ const _ip25 = (input) => input["strategyId"] === null || typeof input["strategyId"] === "string";
15604
+ const _ip26 = (input) => typeof input["modelParams"] === "string";
15605
+ const _ip27 = (input) => typeof input["strategyParams"] === "string";
15606
+ const _ip28 = (input) => typeof input["sessionPattern"] === "string";
15607
+ const _ip29 = (input) => typeof input["sessionDays"] === "number";
15608
+ const _ip30 = (input) => typeof input["horizonSec"] === "number";
15609
+ const _ip31 = (input) => typeof input["stepSec"] === "number";
15610
+ const _ip32 = (input) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMilestone" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit";
15611
+ const _ip33 = (input) => input["status"] === "censored" || input["status"] === "failed" || input["status"] === "observed" || input["status"] === "rejected";
15612
+ const _ip34 = (input) => input["value"] === null || typeof input["value"] === "string";
15613
+ const _ve0 = 'Readonly<{ schemaVersion: 1; contract: "idlekit.experiment.v1"; estimatorVersion: "one-at-a-time-local-v1"; algorithmVersion: "experiment-oat-v1"; method: "fixed-sweep-and-one-at-a-time"; ... 12 more ...; warnings: readonly string[]; }>';
15510
15614
  const _vp0 = (input, _path, _exceptionable = true) => input["schemaVersion"] === 1 || _report(_exceptionable, {
15511
15615
  path: _path + ".schemaVersion",
15512
15616
  expected: "1",
@@ -15566,7 +15670,12 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15566
15670
  expected: "string",
15567
15671
  value: input["effectiveRunHash"]
15568
15672
  });
15569
- const _vp11 = (input, _path, _exceptionable = true) => (typeof input["budget"] === "object" && input["budget"] !== null || _report(_exceptionable, {
15673
+ const _vp11 = (input, _path, _exceptionable = true) => input["milestoneKey"] === undefined || typeof input["milestoneKey"] === "string" || _report(_exceptionable, {
15674
+ path: _path + ".milestoneKey",
15675
+ expected: "(string | undefined)",
15676
+ value: input["milestoneKey"]
15677
+ });
15678
+ const _vp12 = (input, _path, _exceptionable = true) => (typeof input["budget"] === "object" && input["budget"] !== null || _report(_exceptionable, {
15570
15679
  path: _path + ".budget",
15571
15680
  expected: "Readonly<{ candidates: number; seeds: number; usedCandidates: number; usedSeeds: number; }>",
15572
15681
  value: input["budget"]
@@ -15575,7 +15684,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15575
15684
  expected: "Readonly<{ candidates: number; seeds: number; usedCandidates: number; usedSeeds: number; }>",
15576
15685
  value: input["budget"]
15577
15686
  });
15578
- const _vp12 = (input, _path, _exceptionable = true) => (Array.isArray(input["tasks"]) || _report(_exceptionable, {
15687
+ const _vp13 = (input, _path, _exceptionable = true) => (Array.isArray(input["tasks"]) || _report(_exceptionable, {
15579
15688
  path: _path + ".tasks",
15580
15689
  expected: _ve2,
15581
15690
  value: input["tasks"]
@@ -15594,7 +15703,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15594
15703
  });
15595
15704
  const _ve1 = "Readonly<{ taskId: string; candidateId: string; logicalSeed: number; engineId: string; engineVersion: string; modelId: string; modelVersion: number; strategyId: string | null; modelParams: string; ... 7 more ...; value: string | null; }>";
15596
15705
  const _ve2 = "ReadonlyArray<Readonly<{ taskId: string; candidateId: string; logicalSeed: number; engineId: string; engineVersion: string; modelId: string; modelVersion: number; strategyId: string | null; modelParams: string; ... 7 more ...; value: string | null; }>>";
15597
- const _vp13 = (input, _path, _exceptionable = true) => (Array.isArray(input["candidates"]) || _report(_exceptionable, {
15706
+ const _vp14 = (input, _path, _exceptionable = true) => (Array.isArray(input["candidates"]) || _report(_exceptionable, {
15598
15707
  path: _path + ".candidates",
15599
15708
  expected: _ve4,
15600
15709
  value: input["candidates"]
@@ -15613,7 +15722,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15613
15722
  });
15614
15723
  const _ve3 = "Readonly<{ id: string; metrics: readonly Readonly<{ metricId: ExperimentMetricId; status: ExperimentMetricStatus; value: string | null; }>[]; constraintViolations: readonly string[]; }>";
15615
15724
  const _ve4 = "ReadonlyArray<Readonly<{ id: string; metrics: readonly Readonly<{ metricId: ExperimentMetricId; status: ExperimentMetricStatus; value: string | null; }>[]; constraintViolations: readonly string[]; }>>";
15616
- const _vp14 = (input, _path, _exceptionable = true) => (Array.isArray(input["elasticities"]) || _report(_exceptionable, {
15725
+ const _vp15 = (input, _path, _exceptionable = true) => (Array.isArray(input["elasticities"]) || _report(_exceptionable, {
15617
15726
  path: _path + ".elasticities",
15618
15727
  expected: _ve6,
15619
15728
  value: input["elasticities"]
@@ -15632,7 +15741,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15632
15741
  });
15633
15742
  const _ve5 = 'Readonly<{ dimensionId: string; candidateId: string; metricId: ExperimentMetricId; method: "one-at-a-time-local"; methodVersion: 1; globalSensitivity: false; sobol: false; status: "observed" | "unavailable"; elasticity: string | null; absoluteChange: string | null; direction: "flat" | ... 2 more ... | "unavailable";...';
15634
15743
  const _ve6 = 'ReadonlyArray<Readonly<{ dimensionId: string; candidateId: string; metricId: ExperimentMetricId; method: "one-at-a-time-local"; methodVersion: 1; globalSensitivity: false; sobol: false; status: "observed" | "unavailable"; elasticity: string | null; absoluteChange: string | null; direction: "flat" | ... 2 more ... | "unavailable";...>';
15635
- const _vp15 = (input, _path, _exceptionable = true) => (typeof input["pareto"] === "object" && input["pareto"] !== null || _report(_exceptionable, {
15744
+ const _vp16 = (input, _path, _exceptionable = true) => (typeof input["pareto"] === "object" && input["pareto"] !== null || _report(_exceptionable, {
15636
15745
  path: _path + ".pareto",
15637
15746
  expected: 'Readonly<{ sense: "per-metric"; nonDominated: readonly string[]; uncompared: readonly string[]; }>',
15638
15747
  value: input["pareto"]
@@ -15641,7 +15750,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15641
15750
  expected: 'Readonly<{ sense: "per-metric"; nonDominated: readonly string[]; uncompared: readonly string[]; }>',
15642
15751
  value: input["pareto"]
15643
15752
  });
15644
- const _vp16 = (input, _path, _exceptionable = true) => (Array.isArray(input["warnings"]) || _report(_exceptionable, {
15753
+ const _vp17 = (input, _path, _exceptionable = true) => (Array.isArray(input["warnings"]) || _report(_exceptionable, {
15645
15754
  path: _path + ".warnings",
15646
15755
  expected: "ReadonlyArray<string>",
15647
15756
  value: input["warnings"]
@@ -15654,100 +15763,100 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15654
15763
  expected: "ReadonlyArray<string>",
15655
15764
  value: input["warnings"]
15656
15765
  });
15657
- const _vp17 = (input, _path, _exceptionable = true) => typeof input["taskId"] === "string" || _report(_exceptionable, {
15766
+ const _vp18 = (input, _path, _exceptionable = true) => typeof input["taskId"] === "string" || _report(_exceptionable, {
15658
15767
  path: _path + ".taskId",
15659
15768
  expected: "string",
15660
15769
  value: input["taskId"]
15661
15770
  });
15662
- const _vp18 = (input, _path, _exceptionable = true) => typeof input["candidateId"] === "string" || _report(_exceptionable, {
15771
+ const _vp19 = (input, _path, _exceptionable = true) => typeof input["candidateId"] === "string" || _report(_exceptionable, {
15663
15772
  path: _path + ".candidateId",
15664
15773
  expected: "string",
15665
15774
  value: input["candidateId"]
15666
15775
  });
15667
- const _vp19 = (input, _path, _exceptionable = true) => typeof input["logicalSeed"] === "number" || _report(_exceptionable, {
15776
+ const _vp20 = (input, _path, _exceptionable = true) => typeof input["logicalSeed"] === "number" || _report(_exceptionable, {
15668
15777
  path: _path + ".logicalSeed",
15669
15778
  expected: "number",
15670
15779
  value: input["logicalSeed"]
15671
15780
  });
15672
- const _vp20 = (input, _path, _exceptionable = true) => typeof input["engineId"] === "string" || _report(_exceptionable, {
15781
+ const _vp21 = (input, _path, _exceptionable = true) => typeof input["engineId"] === "string" || _report(_exceptionable, {
15673
15782
  path: _path + ".engineId",
15674
15783
  expected: "string",
15675
15784
  value: input["engineId"]
15676
15785
  });
15677
- const _vp21 = (input, _path, _exceptionable = true) => typeof input["engineVersion"] === "string" || _report(_exceptionable, {
15786
+ const _vp22 = (input, _path, _exceptionable = true) => typeof input["engineVersion"] === "string" || _report(_exceptionable, {
15678
15787
  path: _path + ".engineVersion",
15679
15788
  expected: "string",
15680
15789
  value: input["engineVersion"]
15681
15790
  });
15682
- const _vp22 = (input, _path, _exceptionable = true) => typeof input["modelId"] === "string" || _report(_exceptionable, {
15791
+ const _vp23 = (input, _path, _exceptionable = true) => typeof input["modelId"] === "string" || _report(_exceptionable, {
15683
15792
  path: _path + ".modelId",
15684
15793
  expected: "string",
15685
15794
  value: input["modelId"]
15686
15795
  });
15687
- const _vp23 = (input, _path, _exceptionable = true) => typeof input["modelVersion"] === "number" || _report(_exceptionable, {
15796
+ const _vp24 = (input, _path, _exceptionable = true) => typeof input["modelVersion"] === "number" || _report(_exceptionable, {
15688
15797
  path: _path + ".modelVersion",
15689
15798
  expected: "number",
15690
15799
  value: input["modelVersion"]
15691
15800
  });
15692
- const _vp24 = (input, _path, _exceptionable = true) => input["strategyId"] === null || typeof input["strategyId"] === "string" || _report(_exceptionable, {
15801
+ const _vp25 = (input, _path, _exceptionable = true) => input["strategyId"] === null || typeof input["strategyId"] === "string" || _report(_exceptionable, {
15693
15802
  path: _path + ".strategyId",
15694
15803
  expected: "(null | string)",
15695
15804
  value: input["strategyId"]
15696
15805
  });
15697
- const _vp25 = (input, _path, _exceptionable = true) => typeof input["modelParams"] === "string" || _report(_exceptionable, {
15806
+ const _vp26 = (input, _path, _exceptionable = true) => typeof input["modelParams"] === "string" || _report(_exceptionable, {
15698
15807
  path: _path + ".modelParams",
15699
15808
  expected: "string",
15700
15809
  value: input["modelParams"]
15701
15810
  });
15702
- const _vp26 = (input, _path, _exceptionable = true) => typeof input["strategyParams"] === "string" || _report(_exceptionable, {
15811
+ const _vp27 = (input, _path, _exceptionable = true) => typeof input["strategyParams"] === "string" || _report(_exceptionable, {
15703
15812
  path: _path + ".strategyParams",
15704
15813
  expected: "string",
15705
15814
  value: input["strategyParams"]
15706
15815
  });
15707
- const _vp27 = (input, _path, _exceptionable = true) => typeof input["sessionPattern"] === "string" || _report(_exceptionable, {
15816
+ const _vp28 = (input, _path, _exceptionable = true) => typeof input["sessionPattern"] === "string" || _report(_exceptionable, {
15708
15817
  path: _path + ".sessionPattern",
15709
15818
  expected: "string",
15710
15819
  value: input["sessionPattern"]
15711
15820
  });
15712
- const _vp28 = (input, _path, _exceptionable = true) => typeof input["sessionDays"] === "number" || _report(_exceptionable, {
15821
+ const _vp29 = (input, _path, _exceptionable = true) => typeof input["sessionDays"] === "number" || _report(_exceptionable, {
15713
15822
  path: _path + ".sessionDays",
15714
15823
  expected: "number",
15715
15824
  value: input["sessionDays"]
15716
15825
  });
15717
- const _vp29 = (input, _path, _exceptionable = true) => typeof input["horizonSec"] === "number" || _report(_exceptionable, {
15826
+ const _vp30 = (input, _path, _exceptionable = true) => typeof input["horizonSec"] === "number" || _report(_exceptionable, {
15718
15827
  path: _path + ".horizonSec",
15719
15828
  expected: "number",
15720
15829
  value: input["horizonSec"]
15721
15830
  });
15722
- const _vp30 = (input, _path, _exceptionable = true) => typeof input["stepSec"] === "number" || _report(_exceptionable, {
15831
+ const _vp31 = (input, _path, _exceptionable = true) => typeof input["stepSec"] === "number" || _report(_exceptionable, {
15723
15832
  path: _path + ".stepSec",
15724
15833
  expected: "number",
15725
15834
  value: input["stepSec"]
15726
15835
  });
15727
- const _vp31 = (input, _path, _exceptionable = true) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit" || _report(_exceptionable, {
15836
+ const _vp32 = (input, _path, _exceptionable = true) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMilestone" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit" || _report(_exceptionable, {
15728
15837
  path: _path + ".metricId",
15729
- expected: '("endMoney" | "timeToMoney" | "varBenefit")',
15838
+ expected: '("endMoney" | "timeToMilestone" | "timeToMoney" | "varBenefit")',
15730
15839
  value: input["metricId"]
15731
15840
  });
15732
- const _vp32 = (input, _path, _exceptionable = true) => input["status"] === "censored" || input["status"] === "failed" || input["status"] === "observed" || input["status"] === "rejected" || _report(_exceptionable, {
15841
+ const _vp33 = (input, _path, _exceptionable = true) => input["status"] === "censored" || input["status"] === "failed" || input["status"] === "observed" || input["status"] === "rejected" || _report(_exceptionable, {
15733
15842
  path: _path + ".status",
15734
15843
  expected: '("censored" | "failed" | "observed" | "rejected")',
15735
15844
  value: input["status"]
15736
15845
  });
15737
- const _vp33 = (input, _path, _exceptionable = true) => input["value"] === null || typeof input["value"] === "string" || _report(_exceptionable, {
15846
+ const _vp34 = (input, _path, _exceptionable = true) => input["value"] === null || typeof input["value"] === "string" || _report(_exceptionable, {
15738
15847
  path: _path + ".value",
15739
15848
  expected: "(null | string)",
15740
15849
  value: input["value"]
15741
15850
  });
15742
- const _io0 = (input) => _ip0(input) && _ip1(input) && _ip2(input) && _ip3(input) && _ip4(input) && _ip5(input) && _ip6(input) && _ip7(input) && _ip8(input) && _ip9(input) && _ip10(input) && _ip11(input) && _ip12(input) && _ip13(input) && _ip14(input) && _ip15(input) && _ip16(input);
15851
+ const _io0 = (input) => _ip0(input) && _ip1(input) && _ip2(input) && _ip3(input) && _ip4(input) && _ip5(input) && _ip6(input) && _ip7(input) && _ip8(input) && _ip9(input) && _ip10(input) && _ip11(input) && _ip12(input) && _ip13(input) && _ip14(input) && _ip15(input) && _ip16(input) && _ip17(input);
15743
15852
  const _io1 = (input) => typeof input.ref === "string" && typeof input.hash === "string";
15744
15853
  const _io2 = (input) => typeof input.candidates === "number" && typeof input.seeds === "number" && typeof input.usedCandidates === "number" && typeof input.usedSeeds === "number";
15745
- const _io3 = (input) => _ip17(input) && _ip18(input) && _ip19(input) && _ip20(input) && _ip21(input) && _ip22(input) && _ip23(input) && _ip24(input) && _ip25(input) && _ip26(input) && _ip27(input) && _ip28(input) && _ip29(input) && _ip30(input) && _ip31(input) && _ip32(input) && _ip33(input);
15854
+ const _io3 = (input) => _ip18(input) && _ip19(input) && _ip20(input) && _ip21(input) && _ip22(input) && _ip23(input) && _ip24(input) && _ip25(input) && _ip26(input) && _ip27(input) && _ip28(input) && _ip29(input) && _ip30(input) && _ip31(input) && _ip32(input) && _ip33(input) && _ip34(input);
15746
15855
  const _io4 = (input) => typeof input.id === "string" && (Array.isArray(input.metrics) && input.metrics.every((elem) => typeof elem === "object" && elem !== null && _io5(elem))) && (Array.isArray(input.constraintViolations) && input.constraintViolations.every((elem) => typeof elem === "string"));
15747
- const _io5 = (input) => _ip31(input) && _ip32(input) && _ip33(input);
15748
- const _io6 = (input) => typeof input.dimensionId === "string" && _ip18(input) && _ip31(input) && input.method === "one-at-a-time-local" && input.methodVersion === 1 && _ip5(input) && _ip6(input) && (input.status === "observed" || input.status === "unavailable") && (input.elasticity === null || typeof input.elasticity === "string") && (input.absoluteChange === null || typeof input.absoluteChange === "string") && (input.direction === "flat" || input.direction === "higher" || input.direction === "lower" || input.direction === "unavailable");
15856
+ const _io5 = (input) => _ip32(input) && _ip33(input) && _ip34(input);
15857
+ const _io6 = (input) => typeof input.dimensionId === "string" && _ip19(input) && _ip32(input) && input.method === "one-at-a-time-local" && input.methodVersion === 1 && _ip5(input) && _ip6(input) && (input.status === "observed" || input.status === "unavailable") && (input.elasticity === null || typeof input.elasticity === "string") && (input.absoluteChange === null || typeof input.absoluteChange === "string") && (input.direction === "flat" || input.direction === "higher" || input.direction === "lower" || input.direction === "unavailable");
15749
15858
  const _io7 = (input) => input.sense === "per-metric" && (Array.isArray(input.nonDominated) && input.nonDominated.every((elem) => typeof elem === "string")) && (Array.isArray(input.uncompared) && input.uncompared.every((elem) => typeof elem === "string"));
15750
- const _vo0 = (input, _path, _exceptionable = true) => [_vp0(input, _path, _exceptionable), _vp1(input, _path, _exceptionable), _vp2(input, _path, _exceptionable), _vp3(input, _path, _exceptionable), _vp4(input, _path, _exceptionable), _vp5(input, _path, _exceptionable), _vp6(input, _path, _exceptionable), _vp7(input, _path, _exceptionable), _vp8(input, _path, _exceptionable), _vp9(input, _path, _exceptionable), _vp10(input, _path, _exceptionable), _vp11(input, _path, _exceptionable), _vp12(input, _path, _exceptionable), _vp13(input, _path, _exceptionable), _vp14(input, _path, _exceptionable), _vp15(input, _path, _exceptionable), _vp16(input, _path, _exceptionable)].every((flag) => flag);
15859
+ const _vo0 = (input, _path, _exceptionable = true) => [_vp0(input, _path, _exceptionable), _vp1(input, _path, _exceptionable), _vp2(input, _path, _exceptionable), _vp3(input, _path, _exceptionable), _vp4(input, _path, _exceptionable), _vp5(input, _path, _exceptionable), _vp6(input, _path, _exceptionable), _vp7(input, _path, _exceptionable), _vp8(input, _path, _exceptionable), _vp9(input, _path, _exceptionable), _vp10(input, _path, _exceptionable), _vp11(input, _path, _exceptionable), _vp12(input, _path, _exceptionable), _vp13(input, _path, _exceptionable), _vp14(input, _path, _exceptionable), _vp15(input, _path, _exceptionable), _vp16(input, _path, _exceptionable), _vp17(input, _path, _exceptionable)].every((flag) => flag);
15751
15860
  const _vo1 = (input, _path, _exceptionable = true) => [typeof input.ref === "string" || _report(_exceptionable, {
15752
15861
  path: _path + ".ref",
15753
15862
  expected: "string",
@@ -15774,7 +15883,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15774
15883
  expected: "number",
15775
15884
  value: input.usedSeeds
15776
15885
  })].every((flag) => flag);
15777
- const _vo3 = (input, _path, _exceptionable = true) => [_vp17(input, _path, _exceptionable), _vp18(input, _path, _exceptionable), _vp19(input, _path, _exceptionable), _vp20(input, _path, _exceptionable), _vp21(input, _path, _exceptionable), _vp22(input, _path, _exceptionable), _vp23(input, _path, _exceptionable), _vp24(input, _path, _exceptionable), _vp25(input, _path, _exceptionable), _vp26(input, _path, _exceptionable), _vp27(input, _path, _exceptionable), _vp28(input, _path, _exceptionable), _vp29(input, _path, _exceptionable), _vp30(input, _path, _exceptionable), _vp31(input, _path, _exceptionable), _vp32(input, _path, _exceptionable), _vp33(input, _path, _exceptionable)].every((flag) => flag);
15886
+ const _vo3 = (input, _path, _exceptionable = true) => [_vp18(input, _path, _exceptionable), _vp19(input, _path, _exceptionable), _vp20(input, _path, _exceptionable), _vp21(input, _path, _exceptionable), _vp22(input, _path, _exceptionable), _vp23(input, _path, _exceptionable), _vp24(input, _path, _exceptionable), _vp25(input, _path, _exceptionable), _vp26(input, _path, _exceptionable), _vp27(input, _path, _exceptionable), _vp28(input, _path, _exceptionable), _vp29(input, _path, _exceptionable), _vp30(input, _path, _exceptionable), _vp31(input, _path, _exceptionable), _vp32(input, _path, _exceptionable), _vp33(input, _path, _exceptionable), _vp34(input, _path, _exceptionable)].every((flag) => flag);
15778
15887
  const _vo4 = (input, _path, _exceptionable = true) => [typeof input.id === "string" || _report(_exceptionable, {
15779
15888
  path: _path + ".id",
15780
15889
  expected: "string",
@@ -15808,12 +15917,12 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15808
15917
  expected: "ReadonlyArray<string>",
15809
15918
  value: input.constraintViolations
15810
15919
  })].every((flag) => flag);
15811
- const _vo5 = (input, _path, _exceptionable = true) => [_vp31(input, _path, _exceptionable), _vp32(input, _path, _exceptionable), _vp33(input, _path, _exceptionable)].every((flag) => flag);
15920
+ const _vo5 = (input, _path, _exceptionable = true) => [_vp32(input, _path, _exceptionable), _vp33(input, _path, _exceptionable), _vp34(input, _path, _exceptionable)].every((flag) => flag);
15812
15921
  const _vo6 = (input, _path, _exceptionable = true) => [typeof input.dimensionId === "string" || _report(_exceptionable, {
15813
15922
  path: _path + ".dimensionId",
15814
15923
  expected: "string",
15815
15924
  value: input.dimensionId
15816
- }), _vp18(input, _path, _exceptionable), _vp31(input, _path, _exceptionable), input.method === "one-at-a-time-local" || _report(_exceptionable, {
15925
+ }), _vp19(input, _path, _exceptionable), _vp32(input, _path, _exceptionable), input.method === "one-at-a-time-local" || _report(_exceptionable, {
15817
15926
  path: _path + ".method",
15818
15927
  expected: '"one-at-a-time-local"',
15819
15928
  value: input.method
@@ -15899,105 +16008,82 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
15899
16008
  };
15900
16009
  });
15901
16010
  })())(input), validateExperimentSpecValidator, validateExperimentSpec = (input) => (validateExperimentSpecValidator ??= (() => {
15902
- const _ip0 = (input) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit";
15903
- const _ip1 = (input) => typeof input["id"] === "string";
15904
- const _ip2 = (input) => typeof input["min"] === "number";
15905
- const _ip3 = (input) => typeof input["max"] === "number";
15906
- const _ve0 = "Readonly<{ schemaVersion: 1; scenario: Readonly<{ ref: string; hash: string; }>; model: Readonly<{ id: string; version: number; }>; strategy?: Readonly<{ id: string; }> | undefined; ... 10 more ...; session: Readonly<...>; }>";
15907
- const _vp0 = (input, _path, _exceptionable = true) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit" || _report(_exceptionable, {
15908
- path: _path + ".metricId",
15909
- expected: '("endMoney" | "timeToMoney" | "varBenefit")',
15910
- value: input["metricId"]
15911
- });
15912
- const _ve1 = 'Readonly<{ id: string; target: "model" | "session" | "strategy"; path: string; space: ExperimentParamSpace; baseline: ExperimentScalar; probes?: readonly ExperimentScalar[] | undefined; }>';
15913
- const _ve2 = 'ReadonlyArray<Readonly<{ id: string; target: "model" | "session" | "strategy"; path: string; space: ExperimentParamSpace; baseline: ExperimentScalar; probes?: readonly ExperimentScalar[] | undefined; }>>';
15914
- const _ve3 = "(ReadonlyArray<Readonly<{ id: string; assignments: readonly Readonly<{ dimensionId: string; value: ExperimentScalar; }>[]; }>> | undefined)";
15915
- const _vp1 = (input, _path, _exceptionable = true) => typeof input["id"] === "string" || _report(_exceptionable, {
15916
- path: _path + ".id",
15917
- expected: "string",
15918
- value: input["id"]
15919
- });
15920
- const _ve4 = '(Readonly<{ kind: "bool"; }> | Readonly<{ kind: "choice"; values: readonly ExperimentScalar[]; }> | Readonly<{ kind: "int"; min: number; max: number; }> | Readonly<{ kind: "number"; min: number; max: number; scale?: "linear" | "log" | undefined; }>)';
15921
- const _vp2 = (input, _path, _exceptionable = true) => typeof input["min"] === "number" || _report(_exceptionable, {
15922
- path: _path + ".min",
15923
- expected: "number",
15924
- value: input["min"]
15925
- });
15926
- const _vp3 = (input, _path, _exceptionable = true) => typeof input["max"] === "number" || _report(_exceptionable, {
15927
- path: _path + ".max",
15928
- expected: "number",
15929
- value: input["max"]
15930
- });
15931
- const _ve5 = '(Readonly<{ kind: "bool"; }> | Readonly<{ kind: "int"; min: number; max: number; }> | Readonly<{ kind: "number"; min: number; max: number; scale?: "linear" | "log" | undefined; }> | Readonly<{ kind: "choice"; values: readonly ExperimentScalar[]; }>)';
15932
- const _io0 = (input) => input.schemaVersion === 1 && (typeof input.scenario === "object" && input.scenario !== null && _io1(input.scenario)) && (typeof input.model === "object" && input.model !== null && _io2(input.model)) && (input.strategy === undefined || typeof input.strategy === "object" && input.strategy !== null && _io3(input.strategy)) && _ip0(input) && (input.goal === undefined || typeof input.goal === "object" && input.goal !== null && _io4(input.goal)) && (input.objectives === undefined || Array.isArray(input.objectives) && input.objectives.every((elem) => typeof elem === "object" && elem !== null && _io5(elem))) && (input.constraints === undefined || Array.isArray(input.constraints) && input.constraints.every((elem) => typeof elem === "object" && elem !== null && _io6(elem))) && (Array.isArray(input.dimensions) && input.dimensions.every((elem) => typeof elem === "object" && elem !== null && _io7(elem))) && (input.candidates === undefined || Array.isArray(input.candidates) && input.candidates.every((elem) => typeof elem === "object" && elem !== null && _io12(elem))) && (typeof input.budget === "object" && input.budget !== null && _io14(input.budget)) && (Array.isArray(input.seeds) && input.seeds.every((elem) => typeof elem === "number")) && typeof input.horizonSec === "number" && typeof input.stepSec === "number" && (typeof input.session === "object" && input.session !== null && _io15(input.session));
15933
- const _io1 = (input) => typeof input.ref === "string" && typeof input.hash === "string";
15934
- const _io10 = (input) => input.kind === "number" && _ip2(input) && _ip3(input) && (input.scale === undefined || input.scale === "linear" || input.scale === "log");
15935
- const _io11 = (input) => input.kind === "choice" && (Array.isArray(input.values) && input.values.every((elem) => elem === null || typeof elem === "string" || typeof elem === "number" || typeof elem === "boolean"));
15936
- const _io12 = (input) => _ip1(input) && (Array.isArray(input.assignments) && input.assignments.every((elem) => typeof elem === "object" && elem !== null && _io13(elem)));
15937
- const _io13 = (input) => typeof input.dimensionId === "string" && (input.value === null || typeof input.value === "string" || typeof input.value === "number" || typeof input.value === "boolean");
15938
- const _io14 = (input) => typeof input.candidates === "number" && typeof input.seeds === "number";
15939
- const _io15 = (input) => typeof input.pattern === "string" && typeof input.days === "number";
15940
- const _io2 = (input) => _ip1(input) && typeof input.version === "number";
15941
- const _io3 = (input) => _ip1(input);
15942
- const _io4 = (input) => typeof input.target === "number";
15943
- const _io5 = (input) => _ip1(input) && _ip0(input) && (input.sense === "higher" || input.sense === "lower");
15944
- const _io6 = (input) => _ip1(input) && _ip0(input) && (input.op === "gte" || input.op === "lte") && typeof input.limit === "number";
15945
- const _io7 = (input) => _ip1(input) && (input.target === "model" || input.target === "session" || input.target === "strategy") && typeof input.path === "string" && (typeof input.space === "object" && input.space !== null && _iu0(input.space)) && (input.baseline === null || typeof input.baseline === "string" || typeof input.baseline === "number" || typeof input.baseline === "boolean") && (input.probes === undefined || Array.isArray(input.probes) && input.probes.every((elem) => elem === null || typeof elem === "string" || typeof elem === "number" || typeof elem === "boolean"));
15946
- const _io8 = (input) => input.kind === "bool";
15947
- const _io9 = (input) => input.kind === "int" && _ip2(input) && _ip3(input);
15948
- const _iu0 = (input) => (() => {
15949
- if (input.kind === "bool")
15950
- return _io8(input);
15951
- else if (input.kind === "int")
15952
- return _io9(input);
15953
- else if (input.kind === "number")
15954
- return _io10(input);
15955
- else if (input.kind === "choice")
15956
- return _io11(input);
15957
- else
15958
- return false;
15959
- })();
15960
- const _vo0 = (input, _path, _exceptionable = true) => [input.schemaVersion === 1 || _report(_exceptionable, {
16011
+ const _ip0 = (input) => input["schemaVersion"] === 1;
16012
+ const _ip1 = (input) => typeof input["scenario"] === "object" && input["scenario"] !== null && _io1(input["scenario"]);
16013
+ const _ip2 = (input) => typeof input["model"] === "object" && input["model"] !== null && _io2(input["model"]);
16014
+ const _ip3 = (input) => input["strategy"] === undefined || typeof input["strategy"] === "object" && input["strategy"] !== null && _io3(input["strategy"]);
16015
+ const _ip4 = (input) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMilestone" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit";
16016
+ const _ip5 = (input) => input["goal"] === undefined || typeof input["goal"] === "object" && input["goal"] !== null && _io4(input["goal"]);
16017
+ const _ip6 = (input) => input["milestoneKey"] === undefined || typeof input["milestoneKey"] === "string";
16018
+ const _ip7 = (input) => input["objectives"] === undefined || Array.isArray(input["objectives"]) && input["objectives"].every((elem) => typeof elem === "object" && elem !== null && _io5(elem));
16019
+ const _ip8 = (input) => input["constraints"] === undefined || Array.isArray(input["constraints"]) && input["constraints"].every((elem) => typeof elem === "object" && elem !== null && _io6(elem));
16020
+ const _ip9 = (input) => Array.isArray(input["dimensions"]) && input["dimensions"].every((elem) => typeof elem === "object" && elem !== null && _io7(elem));
16021
+ const _ip10 = (input) => input["candidates"] === undefined || Array.isArray(input["candidates"]) && input["candidates"].every((elem) => typeof elem === "object" && elem !== null && _io12(elem));
16022
+ const _ip11 = (input) => typeof input["budget"] === "object" && input["budget"] !== null && _io14(input["budget"]);
16023
+ const _ip12 = (input) => Array.isArray(input["seeds"]) && input["seeds"].every((elem) => typeof elem === "number");
16024
+ const _ip13 = (input) => typeof input["horizonSec"] === "number";
16025
+ const _ip14 = (input) => typeof input["stepSec"] === "number";
16026
+ const _ip15 = (input) => typeof input["session"] === "object" && input["session"] !== null && _io15(input["session"]);
16027
+ const _ip16 = (input) => typeof input["id"] === "string";
16028
+ const _ip17 = (input) => typeof input["min"] === "number";
16029
+ const _ip18 = (input) => typeof input["max"] === "number";
16030
+ const _ve0 = "Readonly<{ schemaVersion: 1; scenario: Readonly<{ ref: string; hash: string; }>; model: Readonly<{ id: string; version: number; }>; strategy?: Readonly<{ id: string; }> | undefined; ... 11 more ...; session: Readonly<...>; }>";
16031
+ const _vp0 = (input, _path, _exceptionable = true) => input["schemaVersion"] === 1 || _report(_exceptionable, {
15961
16032
  path: _path + ".schemaVersion",
15962
16033
  expected: "1",
15963
- value: input.schemaVersion
15964
- }), (typeof input.scenario === "object" && input.scenario !== null || _report(_exceptionable, {
16034
+ value: input["schemaVersion"]
16035
+ });
16036
+ const _vp1 = (input, _path, _exceptionable = true) => (typeof input["scenario"] === "object" && input["scenario"] !== null || _report(_exceptionable, {
15965
16037
  path: _path + ".scenario",
15966
16038
  expected: "Readonly<{ ref: string; hash: string; }>",
15967
- value: input.scenario
15968
- })) && _vo1(input.scenario, _path + ".scenario", _exceptionable) || _report(_exceptionable, {
16039
+ value: input["scenario"]
16040
+ })) && _vo1(input["scenario"], _path + ".scenario", _exceptionable) || _report(_exceptionable, {
15969
16041
  path: _path + ".scenario",
15970
16042
  expected: "Readonly<{ ref: string; hash: string; }>",
15971
- value: input.scenario
15972
- }), (typeof input.model === "object" && input.model !== null || _report(_exceptionable, {
16043
+ value: input["scenario"]
16044
+ });
16045
+ const _vp2 = (input, _path, _exceptionable = true) => (typeof input["model"] === "object" && input["model"] !== null || _report(_exceptionable, {
15973
16046
  path: _path + ".model",
15974
16047
  expected: "Readonly<{ id: string; version: number; }>",
15975
- value: input.model
15976
- })) && _vo2(input.model, _path + ".model", _exceptionable) || _report(_exceptionable, {
16048
+ value: input["model"]
16049
+ })) && _vo2(input["model"], _path + ".model", _exceptionable) || _report(_exceptionable, {
15977
16050
  path: _path + ".model",
15978
16051
  expected: "Readonly<{ id: string; version: number; }>",
15979
- value: input.model
15980
- }), input.strategy === undefined || (typeof input.strategy === "object" && input.strategy !== null || _report(_exceptionable, {
16052
+ value: input["model"]
16053
+ });
16054
+ const _vp3 = (input, _path, _exceptionable = true) => input["strategy"] === undefined || (typeof input["strategy"] === "object" && input["strategy"] !== null || _report(_exceptionable, {
15981
16055
  path: _path + ".strategy",
15982
16056
  expected: "(Readonly<{ id: string; }> | undefined)",
15983
- value: input.strategy
15984
- })) && _vo3(input.strategy, _path + ".strategy", _exceptionable) || _report(_exceptionable, {
16057
+ value: input["strategy"]
16058
+ })) && _vo3(input["strategy"], _path + ".strategy", _exceptionable) || _report(_exceptionable, {
15985
16059
  path: _path + ".strategy",
15986
16060
  expected: "(Readonly<{ id: string; }> | undefined)",
15987
- value: input.strategy
15988
- }), _vp0(input, _path, _exceptionable), input.goal === undefined || (typeof input.goal === "object" && input.goal !== null || _report(_exceptionable, {
16061
+ value: input["strategy"]
16062
+ });
16063
+ const _vp4 = (input, _path, _exceptionable = true) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMilestone" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit" || _report(_exceptionable, {
16064
+ path: _path + ".metricId",
16065
+ expected: '("endMoney" | "timeToMilestone" | "timeToMoney" | "varBenefit")',
16066
+ value: input["metricId"]
16067
+ });
16068
+ const _vp5 = (input, _path, _exceptionable = true) => input["goal"] === undefined || (typeof input["goal"] === "object" && input["goal"] !== null || _report(_exceptionable, {
15989
16069
  path: _path + ".goal",
15990
16070
  expected: "(Readonly<{ target: number; }> | undefined)",
15991
- value: input.goal
15992
- })) && _vo4(input.goal, _path + ".goal", _exceptionable) || _report(_exceptionable, {
16071
+ value: input["goal"]
16072
+ })) && _vo4(input["goal"], _path + ".goal", _exceptionable) || _report(_exceptionable, {
15993
16073
  path: _path + ".goal",
15994
16074
  expected: "(Readonly<{ target: number; }> | undefined)",
15995
- value: input.goal
15996
- }), input.objectives === undefined || (Array.isArray(input.objectives) || _report(_exceptionable, {
16075
+ value: input["goal"]
16076
+ });
16077
+ const _vp6 = (input, _path, _exceptionable = true) => input["milestoneKey"] === undefined || typeof input["milestoneKey"] === "string" || _report(_exceptionable, {
16078
+ path: _path + ".milestoneKey",
16079
+ expected: "(string | undefined)",
16080
+ value: input["milestoneKey"]
16081
+ });
16082
+ const _vp7 = (input, _path, _exceptionable = true) => input["objectives"] === undefined || (Array.isArray(input["objectives"]) || _report(_exceptionable, {
15997
16083
  path: _path + ".objectives",
15998
16084
  expected: '(ReadonlyArray<Readonly<{ id: string; metricId: ExperimentMetricId; sense: "higher" | "lower"; }>> | undefined)',
15999
- value: input.objectives
16000
- })) && input.objectives.map((elem, _index9) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
16085
+ value: input["objectives"]
16086
+ })) && input["objectives"].map((elem, _index9) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
16001
16087
  path: _path + ".objectives[" + _index9 + "]",
16002
16088
  expected: 'Readonly<{ id: string; metricId: ExperimentMetricId; sense: "higher" | "lower"; }>',
16003
16089
  value: elem
@@ -16008,12 +16094,13 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16008
16094
  })).every((flag) => flag) || _report(_exceptionable, {
16009
16095
  path: _path + ".objectives",
16010
16096
  expected: '(ReadonlyArray<Readonly<{ id: string; metricId: ExperimentMetricId; sense: "higher" | "lower"; }>> | undefined)',
16011
- value: input.objectives
16012
- }), input.constraints === undefined || (Array.isArray(input.constraints) || _report(_exceptionable, {
16097
+ value: input["objectives"]
16098
+ });
16099
+ const _vp8 = (input, _path, _exceptionable = true) => input["constraints"] === undefined || (Array.isArray(input["constraints"]) || _report(_exceptionable, {
16013
16100
  path: _path + ".constraints",
16014
16101
  expected: '(ReadonlyArray<Readonly<{ id: string; metricId: ExperimentMetricId; op: "gte" | "lte"; limit: number; }>> | undefined)',
16015
- value: input.constraints
16016
- })) && input.constraints.map((elem, _index10) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
16102
+ value: input["constraints"]
16103
+ })) && input["constraints"].map((elem, _index10) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
16017
16104
  path: _path + ".constraints[" + _index10 + "]",
16018
16105
  expected: 'Readonly<{ id: string; metricId: ExperimentMetricId; op: "gte" | "lte"; limit: number; }>',
16019
16106
  value: elem
@@ -16024,12 +16111,13 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16024
16111
  })).every((flag) => flag) || _report(_exceptionable, {
16025
16112
  path: _path + ".constraints",
16026
16113
  expected: '(ReadonlyArray<Readonly<{ id: string; metricId: ExperimentMetricId; op: "gte" | "lte"; limit: number; }>> | undefined)',
16027
- value: input.constraints
16028
- }), (Array.isArray(input.dimensions) || _report(_exceptionable, {
16114
+ value: input["constraints"]
16115
+ });
16116
+ const _vp9 = (input, _path, _exceptionable = true) => (Array.isArray(input["dimensions"]) || _report(_exceptionable, {
16029
16117
  path: _path + ".dimensions",
16030
16118
  expected: _ve2,
16031
- value: input.dimensions
16032
- })) && input.dimensions.map((elem, _index11) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
16119
+ value: input["dimensions"]
16120
+ })) && input["dimensions"].map((elem, _index11) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
16033
16121
  path: _path + ".dimensions[" + _index11 + "]",
16034
16122
  expected: _ve1,
16035
16123
  value: elem
@@ -16040,12 +16128,15 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16040
16128
  })).every((flag) => flag) || _report(_exceptionable, {
16041
16129
  path: _path + ".dimensions",
16042
16130
  expected: _ve2,
16043
- value: input.dimensions
16044
- }), input.candidates === undefined || (Array.isArray(input.candidates) || _report(_exceptionable, {
16131
+ value: input["dimensions"]
16132
+ });
16133
+ const _ve1 = 'Readonly<{ id: string; target: "model" | "session" | "strategy"; path: string; space: ExperimentParamSpace; baseline: ExperimentScalar; probes?: readonly ExperimentScalar[] | undefined; }>';
16134
+ const _ve2 = 'ReadonlyArray<Readonly<{ id: string; target: "model" | "session" | "strategy"; path: string; space: ExperimentParamSpace; baseline: ExperimentScalar; probes?: readonly ExperimentScalar[] | undefined; }>>';
16135
+ const _vp10 = (input, _path, _exceptionable = true) => input["candidates"] === undefined || (Array.isArray(input["candidates"]) || _report(_exceptionable, {
16045
16136
  path: _path + ".candidates",
16046
16137
  expected: _ve3,
16047
- value: input.candidates
16048
- })) && input.candidates.map((elem, _index12) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
16138
+ value: input["candidates"]
16139
+ })) && input["candidates"].map((elem, _index12) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
16049
16140
  path: _path + ".candidates[" + _index12 + "]",
16050
16141
  expected: "Readonly<{ id: string; assignments: readonly Readonly<{ dimensionId: string; value: ExperimentScalar; }>[]; }>",
16051
16142
  value: elem
@@ -16056,44 +16147,96 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16056
16147
  })).every((flag) => flag) || _report(_exceptionable, {
16057
16148
  path: _path + ".candidates",
16058
16149
  expected: _ve3,
16059
- value: input.candidates
16060
- }), (typeof input.budget === "object" && input.budget !== null || _report(_exceptionable, {
16150
+ value: input["candidates"]
16151
+ });
16152
+ const _ve3 = "(ReadonlyArray<Readonly<{ id: string; assignments: readonly Readonly<{ dimensionId: string; value: ExperimentScalar; }>[]; }>> | undefined)";
16153
+ const _vp11 = (input, _path, _exceptionable = true) => (typeof input["budget"] === "object" && input["budget"] !== null || _report(_exceptionable, {
16061
16154
  path: _path + ".budget",
16062
16155
  expected: "Readonly<{ candidates: number; seeds: number; }>",
16063
- value: input.budget
16064
- })) && _vo14(input.budget, _path + ".budget", _exceptionable) || _report(_exceptionable, {
16156
+ value: input["budget"]
16157
+ })) && _vo14(input["budget"], _path + ".budget", _exceptionable) || _report(_exceptionable, {
16065
16158
  path: _path + ".budget",
16066
16159
  expected: "Readonly<{ candidates: number; seeds: number; }>",
16067
- value: input.budget
16068
- }), (Array.isArray(input.seeds) || _report(_exceptionable, {
16160
+ value: input["budget"]
16161
+ });
16162
+ const _vp12 = (input, _path, _exceptionable = true) => (Array.isArray(input["seeds"]) || _report(_exceptionable, {
16069
16163
  path: _path + ".seeds",
16070
16164
  expected: "ReadonlyArray<number>",
16071
- value: input.seeds
16072
- })) && input.seeds.map((elem, _index13) => typeof elem === "number" || _report(_exceptionable, {
16165
+ value: input["seeds"]
16166
+ })) && input["seeds"].map((elem, _index13) => typeof elem === "number" || _report(_exceptionable, {
16073
16167
  path: _path + ".seeds[" + _index13 + "]",
16074
16168
  expected: "number",
16075
16169
  value: elem
16076
16170
  })).every((flag) => flag) || _report(_exceptionable, {
16077
16171
  path: _path + ".seeds",
16078
16172
  expected: "ReadonlyArray<number>",
16079
- value: input.seeds
16080
- }), typeof input.horizonSec === "number" || _report(_exceptionable, {
16173
+ value: input["seeds"]
16174
+ });
16175
+ const _vp13 = (input, _path, _exceptionable = true) => typeof input["horizonSec"] === "number" || _report(_exceptionable, {
16081
16176
  path: _path + ".horizonSec",
16082
16177
  expected: "number",
16083
- value: input.horizonSec
16084
- }), typeof input.stepSec === "number" || _report(_exceptionable, {
16178
+ value: input["horizonSec"]
16179
+ });
16180
+ const _vp14 = (input, _path, _exceptionable = true) => typeof input["stepSec"] === "number" || _report(_exceptionable, {
16085
16181
  path: _path + ".stepSec",
16086
16182
  expected: "number",
16087
- value: input.stepSec
16088
- }), (typeof input.session === "object" && input.session !== null || _report(_exceptionable, {
16183
+ value: input["stepSec"]
16184
+ });
16185
+ const _vp15 = (input, _path, _exceptionable = true) => (typeof input["session"] === "object" && input["session"] !== null || _report(_exceptionable, {
16089
16186
  path: _path + ".session",
16090
16187
  expected: "Readonly<{ pattern: string; days: number; }>",
16091
- value: input.session
16092
- })) && _vo15(input.session, _path + ".session", _exceptionable) || _report(_exceptionable, {
16188
+ value: input["session"]
16189
+ })) && _vo15(input["session"], _path + ".session", _exceptionable) || _report(_exceptionable, {
16093
16190
  path: _path + ".session",
16094
16191
  expected: "Readonly<{ pattern: string; days: number; }>",
16095
- value: input.session
16096
- })].every((flag) => flag);
16192
+ value: input["session"]
16193
+ });
16194
+ const _vp16 = (input, _path, _exceptionable = true) => typeof input["id"] === "string" || _report(_exceptionable, {
16195
+ path: _path + ".id",
16196
+ expected: "string",
16197
+ value: input["id"]
16198
+ });
16199
+ const _ve4 = '(Readonly<{ kind: "bool"; }> | Readonly<{ kind: "choice"; values: readonly ExperimentScalar[]; }> | Readonly<{ kind: "int"; min: number; max: number; }> | Readonly<{ kind: "number"; min: number; max: number; scale?: "linear" | "log" | undefined; }>)';
16200
+ const _vp17 = (input, _path, _exceptionable = true) => typeof input["min"] === "number" || _report(_exceptionable, {
16201
+ path: _path + ".min",
16202
+ expected: "number",
16203
+ value: input["min"]
16204
+ });
16205
+ const _vp18 = (input, _path, _exceptionable = true) => typeof input["max"] === "number" || _report(_exceptionable, {
16206
+ path: _path + ".max",
16207
+ expected: "number",
16208
+ value: input["max"]
16209
+ });
16210
+ const _ve5 = '(Readonly<{ kind: "bool"; }> | Readonly<{ kind: "int"; min: number; max: number; }> | Readonly<{ kind: "number"; min: number; max: number; scale?: "linear" | "log" | undefined; }> | Readonly<{ kind: "choice"; values: readonly ExperimentScalar[]; }>)';
16211
+ const _io0 = (input) => _ip0(input) && _ip1(input) && _ip2(input) && _ip3(input) && _ip4(input) && _ip5(input) && _ip6(input) && _ip7(input) && _ip8(input) && _ip9(input) && _ip10(input) && _ip11(input) && _ip12(input) && _ip13(input) && _ip14(input) && _ip15(input);
16212
+ const _io1 = (input) => typeof input.ref === "string" && typeof input.hash === "string";
16213
+ const _io10 = (input) => input.kind === "number" && _ip17(input) && _ip18(input) && (input.scale === undefined || input.scale === "linear" || input.scale === "log");
16214
+ const _io11 = (input) => input.kind === "choice" && (Array.isArray(input.values) && input.values.every((elem) => elem === null || typeof elem === "string" || typeof elem === "number" || typeof elem === "boolean"));
16215
+ const _io12 = (input) => _ip16(input) && (Array.isArray(input.assignments) && input.assignments.every((elem) => typeof elem === "object" && elem !== null && _io13(elem)));
16216
+ const _io13 = (input) => typeof input.dimensionId === "string" && (input.value === null || typeof input.value === "string" || typeof input.value === "number" || typeof input.value === "boolean");
16217
+ const _io14 = (input) => typeof input.candidates === "number" && typeof input.seeds === "number";
16218
+ const _io15 = (input) => typeof input.pattern === "string" && typeof input.days === "number";
16219
+ const _io2 = (input) => _ip16(input) && typeof input.version === "number";
16220
+ const _io3 = (input) => _ip16(input);
16221
+ const _io4 = (input) => typeof input.target === "number";
16222
+ const _io5 = (input) => _ip16(input) && _ip4(input) && (input.sense === "higher" || input.sense === "lower");
16223
+ const _io6 = (input) => _ip16(input) && _ip4(input) && (input.op === "gte" || input.op === "lte") && typeof input.limit === "number";
16224
+ const _io7 = (input) => _ip16(input) && (input.target === "model" || input.target === "session" || input.target === "strategy") && typeof input.path === "string" && (typeof input.space === "object" && input.space !== null && _iu0(input.space)) && (input.baseline === null || typeof input.baseline === "string" || typeof input.baseline === "number" || typeof input.baseline === "boolean") && (input.probes === undefined || Array.isArray(input.probes) && input.probes.every((elem) => elem === null || typeof elem === "string" || typeof elem === "number" || typeof elem === "boolean"));
16225
+ const _io8 = (input) => input.kind === "bool";
16226
+ const _io9 = (input) => input.kind === "int" && _ip17(input) && _ip18(input);
16227
+ const _iu0 = (input) => (() => {
16228
+ if (input.kind === "bool")
16229
+ return _io8(input);
16230
+ else if (input.kind === "int")
16231
+ return _io9(input);
16232
+ else if (input.kind === "number")
16233
+ return _io10(input);
16234
+ else if (input.kind === "choice")
16235
+ return _io11(input);
16236
+ else
16237
+ return false;
16238
+ })();
16239
+ const _vo0 = (input, _path, _exceptionable = true) => [_vp0(input, _path, _exceptionable), _vp1(input, _path, _exceptionable), _vp2(input, _path, _exceptionable), _vp3(input, _path, _exceptionable), _vp4(input, _path, _exceptionable), _vp5(input, _path, _exceptionable), _vp6(input, _path, _exceptionable), _vp7(input, _path, _exceptionable), _vp8(input, _path, _exceptionable), _vp9(input, _path, _exceptionable), _vp10(input, _path, _exceptionable), _vp11(input, _path, _exceptionable), _vp12(input, _path, _exceptionable), _vp13(input, _path, _exceptionable), _vp14(input, _path, _exceptionable), _vp15(input, _path, _exceptionable)].every((flag) => flag);
16097
16240
  const _vo1 = (input, _path, _exceptionable = true) => [typeof input.ref === "string" || _report(_exceptionable, {
16098
16241
  path: _path + ".ref",
16099
16242
  expected: "string",
@@ -16107,7 +16250,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16107
16250
  path: _path + ".kind",
16108
16251
  expected: '"number"',
16109
16252
  value: input.kind
16110
- }), _vp2(input, _path, _exceptionable), _vp3(input, _path, _exceptionable), input.scale === undefined || input.scale === "linear" || input.scale === "log" || _report(_exceptionable, {
16253
+ }), _vp17(input, _path, _exceptionable), _vp18(input, _path, _exceptionable), input.scale === undefined || input.scale === "linear" || input.scale === "log" || _report(_exceptionable, {
16111
16254
  path: _path + ".scale",
16112
16255
  expected: '("linear" | "log" | undefined)',
16113
16256
  value: input.scale
@@ -16129,7 +16272,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16129
16272
  expected: "ReadonlyArray<ExperimentScalar>",
16130
16273
  value: input.values
16131
16274
  })].every((flag) => flag);
16132
- const _vo12 = (input, _path, _exceptionable = true) => [_vp1(input, _path, _exceptionable), (Array.isArray(input.assignments) || _report(_exceptionable, {
16275
+ const _vo12 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), (Array.isArray(input.assignments) || _report(_exceptionable, {
16133
16276
  path: _path + ".assignments",
16134
16277
  expected: "ReadonlyArray<Readonly<{ dimensionId: string; value: ExperimentScalar; }>>",
16135
16278
  value: input.assignments
@@ -16173,23 +16316,23 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16173
16316
  expected: "number",
16174
16317
  value: input.days
16175
16318
  })].every((flag) => flag);
16176
- const _vo2 = (input, _path, _exceptionable = true) => [_vp1(input, _path, _exceptionable), typeof input.version === "number" || _report(_exceptionable, {
16319
+ const _vo2 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), typeof input.version === "number" || _report(_exceptionable, {
16177
16320
  path: _path + ".version",
16178
16321
  expected: "number",
16179
16322
  value: input.version
16180
16323
  })].every((flag) => flag);
16181
- const _vo3 = (input, _path, _exceptionable = true) => [_vp1(input, _path, _exceptionable)].every((flag) => flag);
16324
+ const _vo3 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable)].every((flag) => flag);
16182
16325
  const _vo4 = (input, _path, _exceptionable = true) => [typeof input.target === "number" || _report(_exceptionable, {
16183
16326
  path: _path + ".target",
16184
16327
  expected: "number",
16185
16328
  value: input.target
16186
16329
  })].every((flag) => flag);
16187
- const _vo5 = (input, _path, _exceptionable = true) => [_vp1(input, _path, _exceptionable), _vp0(input, _path, _exceptionable), input.sense === "higher" || input.sense === "lower" || _report(_exceptionable, {
16330
+ const _vo5 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), _vp4(input, _path, _exceptionable), input.sense === "higher" || input.sense === "lower" || _report(_exceptionable, {
16188
16331
  path: _path + ".sense",
16189
16332
  expected: '("higher" | "lower")',
16190
16333
  value: input.sense
16191
16334
  })].every((flag) => flag);
16192
- const _vo6 = (input, _path, _exceptionable = true) => [_vp1(input, _path, _exceptionable), _vp0(input, _path, _exceptionable), input.op === "gte" || input.op === "lte" || _report(_exceptionable, {
16335
+ const _vo6 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), _vp4(input, _path, _exceptionable), input.op === "gte" || input.op === "lte" || _report(_exceptionable, {
16193
16336
  path: _path + ".op",
16194
16337
  expected: '("gte" | "lte")',
16195
16338
  value: input.op
@@ -16198,7 +16341,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16198
16341
  expected: "number",
16199
16342
  value: input.limit
16200
16343
  })].every((flag) => flag);
16201
- const _vo7 = (input, _path, _exceptionable = true) => [_vp1(input, _path, _exceptionable), input.target === "model" || input.target === "session" || input.target === "strategy" || _report(_exceptionable, {
16344
+ const _vo7 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), input.target === "model" || input.target === "session" || input.target === "strategy" || _report(_exceptionable, {
16202
16345
  path: _path + ".target",
16203
16346
  expected: '("model" | "session" | "strategy")',
16204
16347
  value: input.target
@@ -16240,7 +16383,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
16240
16383
  path: _path + ".kind",
16241
16384
  expected: '"int"',
16242
16385
  value: input.kind
16243
- }), _vp2(input, _path, _exceptionable), _vp3(input, _path, _exceptionable)].every((flag) => flag);
16386
+ }), _vp17(input, _path, _exceptionable), _vp18(input, _path, _exceptionable)].every((flag) => flag);
16244
16387
  const _vu0 = (input, _path, _exceptionable = true) => (() => {
16245
16388
  if (input.kind === "bool")
16246
16389
  return _vo8(input, _path, _exceptionable);
@@ -18540,7 +18683,7 @@ var init_checks3 = __esm(() => {
18540
18683
  FAIL_ON = ["error", "warn", "inconclusive", "unsupported"];
18541
18684
  });
18542
18685
 
18543
- // ../../node_modules/.bun/typia@15.1.0+367f7514c87f1df1/node_modules/typia/lib/internal/_accessExpressionAsString.mjs
18686
+ // ../../node_modules/.bun/typia@15.2.2+38c91d72aa8392f2/node_modules/typia/lib/internal/_accessExpressionAsString.mjs
18544
18687
  var _accessExpressionAsString = (str) => variable(str) ? `.${str}` : `[${JSON.stringify(str)}]`, variable = (str) => reserved(str) === false && /^[a-zA-Z_$][a-zA-Z_$0-9]*$/g.test(str), reserved = (str) => RESERVED.has(str), RESERVED;
18545
18688
  var init__accessExpressionAsString = __esm(() => {
18546
18689
  RESERVED = /* @__PURE__ */ new Set([
@@ -18604,6 +18747,9 @@ function nonfiniteThresholds(rubric) {
18604
18747
  if (rule.upperThreshold !== null && !Number.isFinite(rule.upperThreshold)) {
18605
18748
  issues.push(`$input.rules[${index}].upperThreshold finite number or null`);
18606
18749
  }
18750
+ if (rule.metricVersion !== undefined && rule.metricVersion !== null && !Number.isFinite(rule.metricVersion)) {
18751
+ issues.push(`$input.rules[${index}].metricVersion finite number or null`);
18752
+ }
18607
18753
  });
18608
18754
  return issues;
18609
18755
  }
@@ -18629,8 +18775,16 @@ function evaluateGroups(failOn, groups, checks) {
18629
18775
  const pass = reports.every((report) => report.pass);
18630
18776
  return { ...first, results, pass, exitCode: pass ? 0 : 2 };
18631
18777
  }
18632
- function findReadings(artifact, metricId) {
18633
- return artifact.metrics.filter((reading) => reading.metricId === metricId);
18778
+ function ruleReadings(artifact, rule) {
18779
+ const pinned = rule.metricVersion ?? null;
18780
+ return artifact.metrics.filter((reading) => reading.metricId === rule.metricId && (pinned === null || reading.metricVersion === pinned));
18781
+ }
18782
+ function metricVersionRef(version) {
18783
+ return `metric-version:${version}`;
18784
+ }
18785
+ function ruleRefLabel(rule) {
18786
+ const pinned = rule.metricVersion ?? null;
18787
+ return pinned === null ? `metric:${rule.metricId}` : `metric:${rule.metricId} ${metricVersionRef(pinned)}`;
18634
18788
  }
18635
18789
  function isUnavailable(reading) {
18636
18790
  return reading.reading === "unavailable" || reading.status !== "ok";
@@ -18797,27 +18951,40 @@ function judgeArtifact(artifact, rubric) {
18797
18951
  const issues = [];
18798
18952
  const groups = new Map;
18799
18953
  const estimatedObservations = [];
18954
+ const estimatedReadings = new Set;
18800
18955
  const prepared = [];
18801
18956
  for (const rule of rubric.rules) {
18802
- const readings = findReadings(artifact, rule.metricId);
18957
+ const label = ruleRefLabel(rule);
18958
+ const readings = ruleReadings(artifact, rule);
18803
18959
  const reading = readings[0];
18804
18960
  if (!reading) {
18805
- issues.push(`missing evidenceRef metric:${rule.metricId}`);
18961
+ const others = artifact.metrics.filter((item) => item.metricId === rule.metricId).map((item) => metricVersionRef(item.metricVersion));
18962
+ issues.push(others.length > 0 ? `missing evidenceRef ${label} (artifact has ${others.join(", ")})` : `missing evidenceRef ${label}`);
18806
18963
  continue;
18807
18964
  }
18808
18965
  if (readings.length > 1) {
18809
- issues.push(`ambiguous evidenceRef metric:${rule.metricId} matches ${readings.length} readings`);
18966
+ issues.push(`ambiguous evidenceRef ${label} matches ${readings.length} readings`);
18810
18967
  continue;
18811
18968
  }
18812
18969
  const mapped = toObservation(artifact, reading, rule);
18813
- const key = JSON.stringify([reading.metricId, mapped.observation.identity.method, mapped.observation.identity.unit]);
18970
+ const key = JSON.stringify([
18971
+ reading.metricId,
18972
+ reading.metricVersion,
18973
+ mapped.observation.identity.method,
18974
+ mapped.observation.identity.unit
18975
+ ]);
18814
18976
  const group = groups.get(key) ?? { observation: mapped.observation, indices: [] };
18815
18977
  group.indices.push(prepared.length);
18816
18978
  groups.set(key, group);
18817
- if (mapped.estimated && !estimatedObservations.some((item) => item.metricId === reading.metricId)) {
18979
+ if (mapped.estimated && !estimatedReadings.has(reading)) {
18980
+ estimatedReadings.add(reading);
18818
18981
  estimatedObservations.push(mapped.estimated);
18819
18982
  }
18820
- prepared.push({ rule, estimated: mapped.estimated, ref: `metric:${rule.metricId}` });
18983
+ prepared.push({
18984
+ rule,
18985
+ estimated: mapped.estimated,
18986
+ refs: [`metric:${rule.metricId}`, metricVersionRef(reading.metricVersion)]
18987
+ });
18821
18988
  }
18822
18989
  if (issues.length > 0)
18823
18990
  return { ok: false, issues };
@@ -18830,7 +18997,7 @@ function judgeArtifact(artifact, rubric) {
18830
18997
  id: item.rule.id,
18831
18998
  category: outcome.category,
18832
18999
  severity: outcome.severity,
18833
- evidenceRefs: [item.ref],
19000
+ evidenceRefs: item.refs,
18834
19001
  assumptionRefs,
18835
19002
  recommendationId: outcome.recommendationId,
18836
19003
  status: outcome.status,
@@ -18854,9 +19021,9 @@ function judgeArtifact(artifact, rubric) {
18854
19021
  return { ok: true, report };
18855
19022
  }
18856
19023
  var JUDGE_ALGORITHM_VERSION = "judge-rules-1", validateRubricValidator, validateRubric = (input) => (validateRubricValidator ??= (() => {
18857
- const _ve0 = 'Readonly<{ schemaVersion: 1; contract: "idlekit.judge.rubric.v1"; rubricVersion: string; failOn: readonly FailOnToken[]; rules: readonly Readonly<{ id: string; metricId: string; operator: CheckOperator; ... 13 more ...; recommendationId: RecommendationId; }>[]; }>';
18858
- const _ve1 = "Readonly<{ id: string; metricId: string; operator: CheckOperator; threshold: number; upperThreshold: number | null; unit: string; severity: CheckSeverity; missingPolicy: MissingPolicy; ... 8 more ...; recommendationId: RecommendationId; }>";
18859
- const _ve2 = "ReadonlyArray<Readonly<{ id: string; metricId: string; operator: CheckOperator; threshold: number; upperThreshold: number | null; unit: string; severity: CheckSeverity; missingPolicy: MissingPolicy; ... 8 more ...; recommendationId: RecommendationId; }>>";
19024
+ const _ve0 = 'Readonly<{ schemaVersion: 1; contract: "idlekit.judge.rubric.v1"; rubricVersion: string; failOn: readonly FailOnToken[]; rules: readonly Readonly<{ id: string; metricId: string; metricVersion?: number | null | undefined; ... 14 more ...; recommendationId: RecommendationId; }>[]; }>';
19025
+ const _ve1 = "Readonly<{ id: string; metricId: string; metricVersion?: number | null | undefined; operator: CheckOperator; threshold: number; upperThreshold: number | null; unit: string; severity: CheckSeverity; ... 9 more ...; recommendationId: RecommendationId; }>";
19026
+ const _ve2 = "ReadonlyArray<Readonly<{ id: string; metricId: string; metricVersion?: number | null | undefined; operator: CheckOperator; threshold: number; upperThreshold: number | null; unit: string; severity: CheckSeverity; ... 9 more ...; recommendationId: RecommendationId; }>>";
18860
19027
  const _ve3 = '("rec.metric.estimate-not-measured" | "rec.metric.identity-mismatch" | "rec.metric.insufficient" | "rec.metric.outside-threshold" | "rec.metric.unsupported" | "rec.metric.within-threshold")';
18861
19028
  const _io0 = (input, _exceptionable = true) => input.schemaVersion === 1 && input.contract === "idlekit.judge.rubric.v1" && typeof input.rubricVersion === "string" && (Array.isArray(input.failOn) && input.failOn.every((elem, _index1) => elem === "error" || elem === "inconclusive" || elem === "unsupported" || elem === "warn")) && (Array.isArray(input.rules) && input.rules.every((elem, _index2) => typeof elem === "object" && elem !== null && _io1(elem, _exceptionable))) && (Object.keys(input).length === 5 || Object.keys(input).every((key) => {
18862
19029
  if (["schemaVersion", "contract", "rubricVersion", "failOn", "rules"].some((prop) => key === prop))
@@ -18866,8 +19033,8 @@ var JUDGE_ALGORITHM_VERSION = "judge-rules-1", validateRubricValidator, validate
18866
19033
  return true;
18867
19034
  return false;
18868
19035
  }));
18869
- const _io1 = (input, _exceptionable = true) => typeof input.id === "string" && typeof input.metricId === "string" && (input.operator === "between" || input.operator === "eq" || input.operator === "gt" || input.operator === "gte" || input.operator === "lt" || input.operator === "lte") && typeof input.threshold === "number" && (input.upperThreshold === null || typeof input.upperThreshold === "number") && typeof input.unit === "string" && (input.severity === "error" || input.severity === "warn") && (input.missingPolicy === "fail" || input.missingPolicy === "inconclusive" || input.missingPolicy === "unsupported") && typeof input.definition === "string" && typeof input.method === "string" && (input.scenarioVersion === null || typeof input.scenarioVersion === "string") && (input.specVersion === null || typeof input.specVersion === "string") && (input.engineId === null || typeof input.engineId === "string") && (input.pluginVersion === null || typeof input.pluginVersion === "string") && (input.seed === null || typeof input.seed === "string") && (input.algorithmVersion === null || typeof input.algorithmVersion === "string") && (input.recommendationId === "rec.metric.estimate-not-measured" || input.recommendationId === "rec.metric.identity-mismatch" || input.recommendationId === "rec.metric.insufficient" || input.recommendationId === "rec.metric.outside-threshold" || input.recommendationId === "rec.metric.unsupported" || input.recommendationId === "rec.metric.within-threshold") && (Object.keys(input).length === 17 || Object.keys(input).every((key) => {
18870
- if (["id", "metricId", "operator", "threshold", "upperThreshold", "unit", "severity", "missingPolicy", "definition", "method", "scenarioVersion", "specVersion", "engineId", "pluginVersion", "seed", "algorithmVersion", "recommendationId"].some((prop) => key === prop))
19036
+ const _io1 = (input, _exceptionable = true) => typeof input.id === "string" && typeof input.metricId === "string" && (input.metricVersion === null || input.metricVersion === undefined || typeof input.metricVersion === "number") && (input.operator === "between" || input.operator === "eq" || input.operator === "gt" || input.operator === "gte" || input.operator === "lt" || input.operator === "lte") && typeof input.threshold === "number" && (input.upperThreshold === null || typeof input.upperThreshold === "number") && typeof input.unit === "string" && (input.severity === "error" || input.severity === "warn") && (input.missingPolicy === "fail" || input.missingPolicy === "inconclusive" || input.missingPolicy === "unsupported") && typeof input.definition === "string" && typeof input.method === "string" && (input.scenarioVersion === null || typeof input.scenarioVersion === "string") && (input.specVersion === null || typeof input.specVersion === "string") && (input.engineId === null || typeof input.engineId === "string") && (input.pluginVersion === null || typeof input.pluginVersion === "string") && (input.seed === null || typeof input.seed === "string") && (input.algorithmVersion === null || typeof input.algorithmVersion === "string") && (input.recommendationId === "rec.metric.estimate-not-measured" || input.recommendationId === "rec.metric.identity-mismatch" || input.recommendationId === "rec.metric.insufficient" || input.recommendationId === "rec.metric.outside-threshold" || input.recommendationId === "rec.metric.unsupported" || input.recommendationId === "rec.metric.within-threshold") && (Object.keys(input).length === 17 || Object.keys(input).every((key) => {
19037
+ if (["id", "metricId", "metricVersion", "operator", "threshold", "upperThreshold", "unit", "severity", "missingPolicy", "definition", "method", "scenarioVersion", "specVersion", "engineId", "pluginVersion", "seed", "algorithmVersion", "recommendationId"].some((prop) => key === prop))
18871
19038
  return true;
18872
19039
  const value = input[key];
18873
19040
  if (value === undefined)
@@ -18940,6 +19107,10 @@ var JUDGE_ALGORITHM_VERSION = "judge-rules-1", validateRubricValidator, validate
18940
19107
  path: _path + ".metricId",
18941
19108
  expected: "string",
18942
19109
  value: input.metricId
19110
+ }), input.metricVersion === null || input.metricVersion === undefined || typeof input.metricVersion === "number" || _report(_exceptionable, {
19111
+ path: _path + ".metricVersion",
19112
+ expected: "(null | number | undefined)",
19113
+ value: input.metricVersion
18943
19114
  }), input.operator === "between" || input.operator === "eq" || input.operator === "gt" || input.operator === "gte" || input.operator === "lt" || input.operator === "lte" || _report(_exceptionable, {
18944
19115
  path: _path + ".operator",
18945
19116
  expected: '("between" | "eq" | "gt" | "gte" | "lt" | "lte")',
@@ -19001,7 +19172,7 @@ var JUDGE_ALGORITHM_VERSION = "judge-rules-1", validateRubricValidator, validate
19001
19172
  expected: _ve3,
19002
19173
  value: input.recommendationId
19003
19174
  }), Object.keys(input).length === 17 || (_exceptionable === false || Object.keys(input).map((key) => {
19004
- if (["id", "metricId", "operator", "threshold", "upperThreshold", "unit", "severity", "missingPolicy", "definition", "method", "scenarioVersion", "specVersion", "engineId", "pluginVersion", "seed", "algorithmVersion", "recommendationId"].some((prop) => key === prop))
19175
+ if (["id", "metricId", "metricVersion", "operator", "threshold", "upperThreshold", "unit", "severity", "missingPolicy", "definition", "method", "scenarioVersion", "specVersion", "engineId", "pluginVersion", "seed", "algorithmVersion", "recommendationId"].some((prop) => key === prop))
19005
19176
  return true;
19006
19177
  const value = input[key];
19007
19178
  if (value === undefined)
@@ -19087,7 +19258,7 @@ var init_judge = __esm(() => {
19087
19258
  // ../core/dist/sim/analysis/flow.js
19088
19259
  var init_flow = () => {};
19089
19260
 
19090
- // ../../node_modules/.bun/typia@15.1.0+367f7514c87f1df1/node_modules/typia/lib/internal/_isTypeUint32.mjs
19261
+ // ../../node_modules/.bun/typia@15.2.2+38c91d72aa8392f2/node_modules/typia/lib/internal/_isTypeUint32.mjs
19091
19262
  var _isTypeUint32 = (value) => Math.floor(value) === value && MINIMUM <= value && value <= MAXIMUM, MINIMUM = 0, MAXIMUM;
19092
19263
  var init__isTypeUint32 = __esm(() => {
19093
19264
  MAXIMUM = 2 ** 32 - 1;
@@ -19554,6 +19725,11 @@ function compareScenarios(args) {
19554
19725
  }
19555
19726
  const measuredA = measuredScore(args.measured?.a, args.metric);
19556
19727
  const measuredB = measuredScore(args.measured?.b, args.metric);
19728
+ for (const value of [measuredA, measuredB]) {
19729
+ if (value !== undefined && !Number.isFinite(value)) {
19730
+ throw new RangeError(`Measured ${args.metric} comparison requires finite values`);
19731
+ }
19732
+ }
19557
19733
  const useMeasured = measuredA !== undefined && measuredB !== undefined;
19558
19734
  const aScore = useMeasured ? measuredA : score(args.a, args.metric);
19559
19735
  const bScore = useMeasured ? measuredB : score(args.b, args.metric);
@@ -19673,12 +19849,12 @@ function estimateLtvPerUser(args) {
19673
19849
  const fullDays = Math.floor(Math.max(0, horizonDays));
19674
19850
  const remainder = Math.max(0, horizonDays - fullDays);
19675
19851
  let gross = 0;
19676
- for (let day = 1;day <= fullDays; day++) {
19852
+ for (let day = 0;day < fullDays; day++) {
19677
19853
  const active = retentionAtDay(config.retention, day);
19678
19854
  gross += active * (payerConversion * arppuDaily + adArpDau);
19679
19855
  }
19680
19856
  if (remainder > 0) {
19681
- const active = retentionAtDay(config.retention, fullDays + 1);
19857
+ const active = retentionAtDay(config.retention, fullDays);
19682
19858
  gross += remainder * active * (payerConversion * arppuDaily + adArpDau);
19683
19859
  }
19684
19860
  const net = gross * (1 - config.revenue.platformFeeRate) * config.revenue.grossMarginRate;
@@ -19800,10 +19976,11 @@ function applyLogNormalShock(mean, sigma, z) {
19800
19976
  }
19801
19977
  function makeUncertainConfig(base, rng) {
19802
19978
  const shock = sampleCorrelatedNormals(rng, base.uncertainty.correlation);
19803
- const d1 = clamp013(applyLogNormalShock(base.retention.d1, base.uncertainty.sigma.retention, shock.retention));
19804
- const d7 = Math.min(d1, clamp013(applyLogNormalShock(base.retention.d7, base.uncertainty.sigma.retention, shock.retention)));
19805
- const d30 = Math.min(d7, clamp013(applyLogNormalShock(base.retention.d30, base.uncertainty.sigma.retention, shock.retention)));
19806
- const d90 = Math.min(d30, clamp013(applyLogNormalShock(base.retention.d90, base.uncertainty.sigma.retention, shock.retention)));
19979
+ const retention = (anchor) => clamp013(applyLogNormalShock(anchor, base.uncertainty.sigma.retention, shock.retention));
19980
+ const d1 = retention(base.retention.d1);
19981
+ const d7 = retention(base.retention.d7);
19982
+ const d30 = retention(base.retention.d30);
19983
+ const d90 = retention(base.retention.d90);
19807
19984
  return {
19808
19985
  ...base,
19809
19986
  retention: {
@@ -19827,6 +20004,23 @@ function quantileFromSorted(sorted, q) {
19827
20004
  const idx = Math.max(0, Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * q)));
19828
20005
  return sorted[idx] ?? 0;
19829
20006
  }
20007
+ function quantileKey(q) {
20008
+ const [mantissa = "0", exponent = "0"] = String(q).split("e");
20009
+ const [whole = "0", fraction = ""] = mantissa.split(".");
20010
+ const digits = whole + fraction;
20011
+ const point = whole.length + Number(exponent) + 2;
20012
+ const shifted = point <= 0 ? `0.${"0".repeat(-point)}${digits}` : point >= digits.length ? digits + "0".repeat(point - digits.length) : `${digits.slice(0, point)}.${digits.slice(point)}`;
20013
+ const [int = "0", frac = ""] = shifted.split(".");
20014
+ let start = 0;
20015
+ while (start < int.length - 1 && int[start] === "0")
20016
+ start++;
20017
+ let end = frac.length;
20018
+ while (end > 0 && frac[end - 1] === "0")
20019
+ end--;
20020
+ const trimmedInt = int.slice(start);
20021
+ const trimmedFrac = frac.slice(0, end);
20022
+ return `q${trimmedFrac ? `${trimmedInt}.${trimmedFrac}` : trimmedInt}`;
20023
+ }
19830
20024
  function estimateLtvDistribution(args) {
19831
20025
  const rng = mulberry32(args.seed);
19832
20026
  const grossSamples = [];
@@ -19848,7 +20042,7 @@ function estimateLtvDistribution(args) {
19848
20042
  const sortedLtv = [...ltvSamples].sort((a, b) => a - b);
19849
20043
  const byQuantile = {};
19850
20044
  for (const q of args.quantiles) {
19851
- byQuantile[`q${Math.round(q * 100)}`] = quantileFromSorted(sortedLtv, q);
20045
+ byQuantile[quantileKey(q)] = quantileFromSorted(sortedLtv, q);
19852
20046
  }
19853
20047
  return {
19854
20048
  mean: {
@@ -19883,8 +20077,7 @@ function assertQuantileValues(quantiles) {
19883
20077
  throw new RangeError("quantiles must be nonempty and in 0..1");
19884
20078
  }
19885
20079
  }
19886
- function assertConfig(config) {
19887
- const { retention, ...other } = config;
20080
+ function assertRetention(retention) {
19888
20081
  for (const day of ["d1", "d7", "d30", "d90"]) {
19889
20082
  if (!Number.isFinite(retention[day]) || retention[day] < 0 || retention[day] > 1) {
19890
20083
  throw new RangeError(`retention.${day} must be finite and in 0..1`);
@@ -19893,6 +20086,10 @@ function assertConfig(config) {
19893
20086
  if (!Number.isFinite(retention.longTailDailyDecay) || retention.longTailDailyDecay < 0) {
19894
20087
  throw new RangeError("retention.longTailDailyDecay must be finite and >= 0");
19895
20088
  }
20089
+ }
20090
+ function assertConfig(config) {
20091
+ const { retention, ...other } = config;
20092
+ assertRetention(retention);
19896
20093
  const { quantiles, ...uncertainty } = other.uncertainty;
19897
20094
  assertQuantileValues(quantiles);
19898
20095
  assertMonetization({ ...other, uncertainty });
@@ -19903,6 +20100,14 @@ function deriveMonetizationConfig2(scenario) {
19903
20100
  assertConfig(config);
19904
20101
  return config;
19905
20102
  }
20103
+ function progressionFactor2(startWorthLog10, endWorthLog10, span) {
20104
+ if (Number.isNaN(startWorthLog10) || Number.isNaN(endWorthLog10)) {
20105
+ throw new RangeError("worth logs must not be NaN");
20106
+ }
20107
+ if (!Number.isFinite(span) || span <= 0)
20108
+ throw new RangeError("span must be finite and > 0");
20109
+ return progressionFactor(startWorthLog10, endWorthLog10, span);
20110
+ }
19906
20111
  function assertPoint(args) {
19907
20112
  assertConfig(args.config);
19908
20113
  if (!Number.isFinite(args.horizonDays) || args.horizonDays < 0 || args.horizonDays > 36500) {
@@ -19923,18 +20128,24 @@ function estimateLtvPerUser2(args) {
19923
20128
  }
19924
20129
  function estimateLtvDistribution2(args) {
19925
20130
  assertPoint(args);
19926
- if (!Number.isSafeInteger(args.draws) || args.draws < 1 || args.draws > 1e5 || args.draws * Math.max(1, Math.ceil(args.horizonDays)) > 1e7) {
20131
+ const draws = args.draws ?? args.config.uncertainty.draws;
20132
+ const quantiles = args.quantiles ?? args.config.uncertainty.quantiles;
20133
+ const seed = args.seed ?? args.config.uncertainty.seed;
20134
+ if (!Number.isSafeInteger(draws) || draws < 1 || draws > 1e5 || draws * Math.max(1, Math.ceil(args.horizonDays)) > 1e7) {
19927
20135
  throw new RangeError("draws must be 1..100000 and draws \xD7 ceil(horizonDays) at most 10000000");
19928
20136
  }
19929
- if (!Number.isFinite(args.seed))
19930
- throw new RangeError("seed must be finite");
19931
- if (args.quantiles.length > 101)
19932
- throw new RangeError("quantiles exceed the 101 distinct percent keys");
19933
- assertQuantileValues(args.quantiles);
19934
- if (new Set(args.quantiles.map((q) => Math.round(q * 100))).size !== args.quantiles.length) {
19935
- throw new RangeError("quantiles must be nonempty, in 0..1 and have distinct rounded percent keys");
20137
+ if (seed === undefined)
20138
+ throw new RangeError("seed is required: pass seed or set config.uncertainty.seed");
20139
+ if (!Number.isInteger(seed) || seed < 0 || seed > 4294967295) {
20140
+ throw new RangeError("seed must be an integer in 0..4294967295");
20141
+ }
20142
+ if (quantiles.length > 101)
20143
+ throw new RangeError("quantiles exceed 101 entries");
20144
+ assertQuantileValues(quantiles);
20145
+ if (new Set(quantiles.map(quantileKey)).size !== quantiles.length) {
20146
+ throw new RangeError("quantiles must be distinct values in 0..1");
19936
20147
  }
19937
- const result = estimateLtvDistribution(args);
20148
+ const result = estimateLtvDistribution({ ...args, draws, quantiles, seed });
19938
20149
  finiteResult(result.mean);
19939
20150
  finiteResult(result.quantiles);
19940
20151
  return result;
@@ -20065,7 +20276,7 @@ function planRetentionPatch(observation, assumptions = {}) {
20065
20276
  if (rate === undefined)
20066
20277
  continue;
20067
20278
  if (previous && previous.rate < rate)
20068
- warnings.push(`D${previous.day}=${previous.rate} is below D${day}=${rate}. LTV requires d1 >= d7 >= d30 >= d90; review observations and retained assumptions before applying a patch.`);
20279
+ warnings.push(`D${previous.day}=${previous.rate} is below D${day}=${rate}. A complete scenario retention curve must satisfy d1 >= d7 >= d30 >= d90, and the LTV model would interpolate a rise as given; review observations and retained assumptions before applying a patch.`);
20069
20280
  previous = { day, rate };
20070
20281
  }
20071
20282
  return warnings.length ? { status: "requires-review", retention: {}, warnings } : { status: "ready", retention: rates, warnings };
@@ -20162,9 +20373,11 @@ var init_dist2 = __esm(() => {
20162
20373
  var {$ } = globalThis.Bun;
20163
20374
  import { dirname } from "path";
20164
20375
  async function readTextFile(path) {
20376
+ recordInputRead(path);
20165
20377
  return Bun.file(path).text();
20166
20378
  }
20167
20379
  async function readJsonFile(path) {
20380
+ recordInputRead(path);
20168
20381
  return Bun.file(path).json();
20169
20382
  }
20170
20383
  async function writeTextFile(path, body) {
@@ -20214,6 +20427,7 @@ function runText(args, opts) {
20214
20427
  var MAX_CAPTURE_BYTES;
20215
20428
  var init_bun = __esm(() => {
20216
20429
  init_errors3();
20430
+ init_invocation();
20217
20431
  MAX_CAPTURE_BYTES = 8 * 1024 * 1024;
20218
20432
  });
20219
20433
 
@@ -20221,7 +20435,7 @@ var init_bun = __esm(() => {
20221
20435
  var require_package = __commonJS(function(exports, module) {
20222
20436
  module.exports = {
20223
20437
  name: "@idlekit/cli",
20224
- version: "0.6.0",
20438
+ version: "0.7.0",
20225
20439
  description: "Bun-first idk CLI for idle game scenario validation, simulation, tuning, and reporting.",
20226
20440
  license: "MIT",
20227
20441
  type: "module",
@@ -20274,7 +20488,7 @@ var require_package = __commonJS(function(exports, module) {
20274
20488
  "@clack/prompts": "1.8.1",
20275
20489
  "@gunshi/plugin-completion": "0.37.3",
20276
20490
  "@gunshi/plugin-suggestion": "0.37.3",
20277
- "@idlekit/core": "0.6.0",
20491
+ "@idlekit/core": "0.7.0",
20278
20492
  ajv: "^8.20.0",
20279
20493
  gunshi: "0.37.3",
20280
20494
  "proper-lockfile": "4.1.2",
@@ -20289,7 +20503,7 @@ var require_package = __commonJS(function(exports, module) {
20289
20503
 
20290
20504
  // src/runtime/selfCli.ts
20291
20505
  import { existsSync } from "fs";
20292
- import { dirname as dirname3, resolve as resolve2 } from "path";
20506
+ import { dirname as dirname3, resolve as resolve3 } from "path";
20293
20507
  function currentEntry() {
20294
20508
  return Bun.main;
20295
20509
  }
@@ -20306,11 +20520,11 @@ function cliPackageRoot(entry = currentEntry()) {
20306
20520
  if (isNativeEntry(entry))
20307
20521
  return process.cwd();
20308
20522
  if (isBundledCliProcess(entry))
20309
- return resolve2(dirname3(entry), "..");
20310
- return resolve2(import.meta.dir, "../..");
20523
+ return resolve3(dirname3(entry), "..");
20524
+ return resolve3(import.meta.dir, "../..");
20311
20525
  }
20312
20526
  function bundledCliConfig(entry) {
20313
- const config = resolve2(dirname3(entry), "../../../tools/bundled-cli-bunfig.toml");
20527
+ const config = resolve3(dirname3(entry), "../../../tools/bundled-cli-bunfig.toml");
20314
20528
  if (!existsSync(config))
20315
20529
  return;
20316
20530
  return config;
@@ -20325,7 +20539,7 @@ function selfCliCommand(args, entry = currentEntry()) {
20325
20539
  return [bun, `--config=${config}`, entry, ...args];
20326
20540
  return [bun, entry, ...args];
20327
20541
  }
20328
- const bunfigApplies = resolve2(process.cwd()) === CLI_ROOT;
20542
+ const bunfigApplies = resolve3(process.cwd()) === CLI_ROOT;
20329
20543
  if (entry.endsWith(".ts") && !bunfigApplies) {
20330
20544
  return [bun, "--preload", "@ttsc/unplugin/bun-register", entry, ...args];
20331
20545
  }
@@ -20347,16 +20561,16 @@ function runSelfCli(args) {
20347
20561
  }
20348
20562
  var CLI_ROOT, MAX_CAPTURE_BYTES2;
20349
20563
  var init_selfCli = __esm(() => {
20350
- CLI_ROOT = resolve2(import.meta.dir, "../..");
20564
+ CLI_ROOT = resolve3(import.meta.dir, "../..");
20351
20565
  MAX_CAPTURE_BYTES2 = 8 * 1024 * 1024;
20352
20566
  });
20353
20567
 
20354
20568
  // src/io/outputMeta.ts
20355
- import { dirname as dirname4, resolve as resolve3 } from "path";
20569
+ import { dirname as dirname4, resolve as resolve4 } from "path";
20356
20570
  function repoRoot() {
20357
20571
  if (isBundledCliProcess())
20358
- return resolve3(dirname4(Bun.main), "../..");
20359
- return resolve3(import.meta.dir, "../../..");
20572
+ return resolve4(dirname4(Bun.main), "../..");
20573
+ return resolve4(import.meta.dir, "../../..");
20360
20574
  }
20361
20575
  function stableStringify(value) {
20362
20576
  if (value === null || typeof value !== "object") {
@@ -29080,7 +29294,7 @@ var init_jev_schema = __esm(() => {
29080
29294
 
29081
29295
  // src/lib/evaluation/providers/jev.ts
29082
29296
  import { closeSync, lstatSync, mkdirSync, openSync, readFileSync, readlinkSync, realpathSync as realpathSync2, renameSync, unlinkSync, writeFileSync } from "fs";
29083
- import { basename as basename2, dirname as dirname5, resolve as resolve6 } from "path";
29297
+ import { basename as basename2, dirname as dirname5, resolve as resolve7 } from "path";
29084
29298
  function pathEnd(value, start, run) {
29085
29299
  const end = start + run.length;
29086
29300
  if (FILE_COMPONENT.test(run))
@@ -29137,19 +29351,18 @@ function isSafeJevReport(report, keyMaterial) {
29137
29351
  return JSON.stringify(redact(report, keyMaterial)) === JSON.stringify(report);
29138
29352
  }
29139
29353
  function projectJevState(artifact, rubric, keyMaterial) {
29140
- const referenced = new Set(rubric.rules.map((rule) => rule.metricId));
29141
- const seenMetricIds = new Set;
29142
- const firstReadings = artifact.metrics.filter((metric) => {
29143
- if (!referenced.has(metric.metricId) || seenMetricIds.has(metric.metricId))
29144
- return false;
29145
- seenMetricIds.add(metric.metricId);
29146
- return true;
29147
- });
29354
+ const rulesByReading = new Map;
29355
+ for (const rule of rubric.rules) {
29356
+ const selected = ruleReadings(artifact, rule)[0];
29357
+ if (selected)
29358
+ rulesByReading.set(selected, [...rulesByReading.get(selected) ?? [], rule]);
29359
+ }
29360
+ const firstReadings = artifact.metrics.filter((metric) => rulesByReading.has(metric));
29148
29361
  const coverage = artifact.observationCoverage;
29149
29362
  const judged = judgeArtifact(artifact, rubric);
29150
29363
  const verdicts = new Map(judged.ok ? judged.report.numerical.results.map((result) => [result.id, result.verdict]) : []);
29151
29364
  const withheld = coverage === "incomplete" || coverage === "unknown" || coverage === "disabled" || artifact.capabilities.metrics !== "statically-known";
29152
- const metrics = firstReadings.flatMap((metric) => rubric.rules.filter((rule) => rule.metricId === metric.metricId).map((rule) => {
29365
+ const metrics = firstReadings.flatMap((metric) => (rulesByReading.get(metric) ?? []).map((rule) => {
29153
29366
  const { observation } = toObservation(artifact, metric, rule);
29154
29367
  return {
29155
29368
  ...observation.identity,
@@ -29385,14 +29598,14 @@ function cacheTarget(path, depth = 0) {
29385
29598
  } catch {
29386
29599
  try {
29387
29600
  if (lstatSync(path).isSymbolicLink())
29388
- return cacheTarget(resolve6(dirname5(path), readlinkSync(path)), depth + 1);
29601
+ return cacheTarget(resolve7(dirname5(path), readlinkSync(path)), depth + 1);
29389
29602
  } catch (error) {
29390
29603
  if (error.code !== "ENOENT")
29391
29604
  throw error;
29392
29605
  }
29393
- const absolute = resolve6(path);
29606
+ const absolute = resolve7(path);
29394
29607
  const parent = dirname5(absolute);
29395
- return parent === absolute ? absolute : resolve6(cacheTarget(parent, depth), basename2(absolute));
29608
+ return parent === absolute ? absolute : resolve7(cacheTarget(parent, depth), basename2(absolute));
29396
29609
  }
29397
29610
  }
29398
29611
  async function writeCache(requestedPath, entry) {
@@ -34346,6 +34559,7 @@ function getTerminalInfo() {
34346
34559
  }
34347
34560
 
34348
34561
  // src/runtime/command.ts
34562
+ init_invocation();
34349
34563
  function option(schema, metadata = {}) {
34350
34564
  return { schema, ...metadata };
34351
34565
  }
@@ -34466,14 +34680,15 @@ async function createCLI(config) {
34466
34680
  throw usageError(`Invalid --${key}: ${parsed.error.message}`);
34467
34681
  flags[key] = parsed.data;
34468
34682
  }
34469
- await selected.handler({
34683
+ const positional = [...ctx.positionals.slice(ctx.commandPath.length), ...ctx.rest];
34684
+ await runWithInvocation({ positional, flags }, () => selected.handler({
34470
34685
  flags,
34471
- positional: [...ctx.positionals.slice(ctx.commandPath.length), ...ctx.rest],
34686
+ positional,
34472
34687
  terminal: getTerminalInfo(),
34473
34688
  prompt,
34474
34689
  cwd: process.cwd(),
34475
34690
  runtime: { args: [...ctx._] }
34476
- });
34691
+ }));
34477
34692
  }
34478
34693
  });
34479
34694
  };
@@ -34544,8 +34759,9 @@ init_zod();
34544
34759
  // src/plugin/load.ts
34545
34760
  init_dist2();
34546
34761
  init_bun();
34762
+ init_invocation();
34547
34763
  import { realpathSync } from "fs";
34548
- import { dirname as dirname2, extname, isAbsolute, relative, resolve, sep } from "path";
34764
+ import { dirname as dirname2, extname, isAbsolute, relative, resolve as resolve2, sep } from "path";
34549
34765
  import { fileURLToPath } from "url";
34550
34766
 
34551
34767
  // src/lib/designObjectives.ts
@@ -34557,7 +34773,7 @@ init_dist2();
34557
34773
  function quantile(values, q) {
34558
34774
  return quantileInclusiveFloor(values, q) ?? undefined;
34559
34775
  }
34560
- function quantileKey(quantiles, q) {
34776
+ function quantileKey2(quantiles, q) {
34561
34777
  const percent = Math.round(q * 100);
34562
34778
  const legacy = `q${percent}`;
34563
34779
  const collided = quantiles.some((other) => other !== q && `q${Math.round(other * 100)}` === legacy);
@@ -34570,7 +34786,7 @@ function summarizeNumeric(values, quantiles) {
34570
34786
  return null;
34571
34787
  return {
34572
34788
  mean: values.reduce((sum, value) => sum + value, 0) / values.length,
34573
- quantiles: Object.fromEntries(quantiles.map((q) => [quantileKey(quantiles, q), quantileInclusiveFloor(values, q) ?? Number.NaN]))
34789
+ quantiles: Object.fromEntries(quantiles.map((q) => [quantileKey2(quantiles, q), quantileInclusiveFloor(values, q) ?? Number.NaN]))
34574
34790
  };
34575
34791
  }
34576
34792
  function resolveSessionPatternSpec(args) {
@@ -35211,10 +35427,11 @@ init_errors3();
35211
35427
  function ownedCount(state) {
35212
35428
  return Number(state?.vars?.owned ?? 0);
35213
35429
  }
35430
+ var NUMBER_ONLY_COMMANDS = ["report", "analyze", "eta", "growth", "prestige-cycle"];
35214
35431
  function finiteLinearAmount(E, value, label) {
35215
35432
  if (!E.isFinite(value)) {
35216
35433
  throw cliError("SCENARIO_INVALID", `linear ${label} exceeds the selected engine's finite range. Use --engine breakInfinity with simulate/evaluate/experience/ltv/compare/tune/balance for a large economy, or reduce the inputs.`, {
35217
- hint: "The report command uses the number engine; reduce its inputs."
35434
+ hint: `${NUMBER_ONLY_COMMANDS.join(", ")} run only the number engine; reduce their inputs.`
35218
35435
  });
35219
35436
  }
35220
35437
  return value;
@@ -35450,7 +35667,7 @@ function normalizeSha256(input) {
35450
35667
  return x;
35451
35668
  }
35452
35669
  function parsePluginRoots(input) {
35453
- const list = parseCommaSeparated(input).map((x) => resolve(x));
35670
+ const list = parseCommaSeparated(input).map((x) => resolve2(x));
35454
35671
  return [...new Set(list)];
35455
35672
  }
35456
35673
  function parsePluginSha256(input) {
@@ -35463,7 +35680,7 @@ function parsePluginSha256(input) {
35463
35680
  }
35464
35681
  const key = entry.slice(0, idx).trim();
35465
35682
  const value = entry.slice(idx + 1).trim();
35466
- const abs = resolve(key);
35683
+ const abs = resolve2(key);
35467
35684
  const digest = normalizeSha256(value);
35468
35685
  if (out[abs] && out[abs] !== digest) {
35469
35686
  throw new Error(`Conflicting sha256 values for plugin path: ${key}`);
@@ -35475,7 +35692,7 @@ function parsePluginSha256(input) {
35475
35692
  function parsePluginSecurityOptions(input) {
35476
35693
  const allowedRoots = parsePluginRoots(input.roots);
35477
35694
  const requiredSha256 = parsePluginSha256(input.sha256);
35478
- const trustFile = typeof input.trustFile === "string" && input.trustFile.trim().length > 0 ? resolve(input.trustFile) : undefined;
35695
+ const trustFile = typeof input.trustFile === "string" && input.trustFile.trim().length > 0 ? resolve2(input.trustFile) : undefined;
35479
35696
  return {
35480
35697
  allowedRoots,
35481
35698
  requiredSha256,
@@ -35497,7 +35714,7 @@ async function loadPluginTrustFile(pathAbs) {
35497
35714
  if (typeof v !== "string")
35498
35715
  continue;
35499
35716
  const digest = normalizeSha256(v);
35500
- const absPath = isAbsolute(k) ? resolve(k) : resolve(baseDir, k);
35717
+ const absPath = isAbsolute(k) ? resolve2(k) : resolve2(baseDir, k);
35501
35718
  out[absPath] = digest;
35502
35719
  }
35503
35720
  return out;
@@ -35523,7 +35740,7 @@ async function loadRegistries(pluginPaths = [], securityOptions = {}) {
35523
35740
  let requiredSha256;
35524
35741
  let requiredClosureSha256;
35525
35742
  try {
35526
- allowedRoots = (securityOptions.allowedRoots ?? []).map((x) => resolve(x));
35743
+ allowedRoots = (securityOptions.allowedRoots ?? []).map((x) => resolve2(x));
35527
35744
  const trustFileSha256 = securityOptions.trustFile !== undefined ? await loadPluginTrustFile(securityOptions.trustFile) : {};
35528
35745
  requiredSha256 = mergeShaPolicies(trustFileSha256, securityOptions.requiredSha256 ?? {});
35529
35746
  requiredClosureSha256 = mergeShaPolicies({}, securityOptions.requiredClosureSha256 ?? {});
@@ -35620,6 +35837,7 @@ function isPathInsideRoot(pathAbs, rootAbs) {
35620
35837
  return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
35621
35838
  }
35622
35839
  async function sha256File(pathAbs) {
35840
+ recordInputRead(pathAbs);
35623
35841
  const buffer = await Bun.file(pathAbs).bytes();
35624
35842
  return sha256Hex(buffer);
35625
35843
  }
@@ -35659,11 +35877,16 @@ async function pluginClosureDigest(entryAbs, entryDigest) {
35659
35877
  return sha256Hex(listing.join(`
35660
35878
  `));
35661
35879
  }
35880
+ async function recordPluginClosureReads(entryAbs) {
35881
+ try {
35882
+ await pluginClosureDigest(entryAbs, await sha256File(entryAbs));
35883
+ } catch {}
35884
+ }
35662
35885
  async function resolveAndValidatePluginPath(input, allowedRoots) {
35663
35886
  if (input.includes("://")) {
35664
35887
  throw new Error(`Plugin path must be a local file path: ${input}`);
35665
35888
  }
35666
- const abs = resolve(input);
35889
+ const abs = resolve2(input);
35667
35890
  const ext = extname(abs).toLowerCase();
35668
35891
  if (!ALLOWED_PLUGIN_EXTENSIONS.has(ext)) {
35669
35892
  throw new Error(`Unsupported plugin extension '${ext}' for ${input}`);
@@ -35713,7 +35936,7 @@ init_outputMeta();
35713
35936
 
35714
35937
  // src/io/readScenario.ts
35715
35938
  init_dist2();
35716
- import { extname as extname2, resolve as resolve4 } from "path";
35939
+ import { extname as extname2, resolve as resolve5 } from "path";
35717
35940
 
35718
35941
  // ../../node_modules/.bun/yaml@2.9.1/node_modules/yaml/dist/index.js
35719
35942
  var exports_dist2 = {};
@@ -35832,7 +36055,7 @@ async function readScenarioFile(path) {
35832
36055
  return out.value;
35833
36056
  }
35834
36057
  async function readScenarioFileWithMeta(path) {
35835
- const abs = resolve4(path);
36058
+ const abs = resolve5(path);
35836
36059
  const raw = await readTextFile(abs).catch((error) => {
35837
36060
  throw scenarioReadFailedError(abs, error);
35838
36061
  });
@@ -35854,7 +36077,8 @@ async function readScenarioFileWithMeta(path) {
35854
36077
  // src/io/writeOutput.ts
35855
36078
  init_errors3();
35856
36079
  init_bun();
35857
- import { resolve as resolve5 } from "path";
36080
+ init_invocation();
36081
+ import { resolve as resolve6 } from "path";
35858
36082
  import { realpath, stat } from "fs/promises";
35859
36083
  function toCsv(data) {
35860
36084
  if (!Array.isArray(data)) {
@@ -35917,6 +36141,39 @@ function renderOutput(format, data) {
35917
36141
  return toMarkdown(data);
35918
36142
  return JSON.stringify(data, null, 2);
35919
36143
  }
36144
+ async function sameFile(output, input) {
36145
+ try {
36146
+ const [outputReal, inputReal, outputStat, inputStat] = await Promise.all([
36147
+ realpath(output),
36148
+ realpath(input),
36149
+ stat(output, { bigint: true }),
36150
+ stat(input, { bigint: true })
36151
+ ]);
36152
+ return outputReal === inputReal || outputStat.ino !== 0n && outputStat.dev === inputStat.dev && outputStat.ino === inputStat.ino;
36153
+ } catch (error) {
36154
+ const code = error.code;
36155
+ if (code !== "ENOENT" && code !== "ENOTDIR")
36156
+ throw error;
36157
+ return false;
36158
+ }
36159
+ }
36160
+ async function exists(path) {
36161
+ return stat(path).then(() => true, () => false);
36162
+ }
36163
+ async function assertOutputNotInput(outPath, options = {}) {
36164
+ const abs = resolve6(outPath);
36165
+ const explicit = (options.protectedInputs ?? []).map((input) => ({ input, required: true }));
36166
+ const implicit = invocationInputCandidates({ allow: options.allowFlags }).map((input) => ({ input, required: false }));
36167
+ for (const { input, required } of [...explicit, ...implicit]) {
36168
+ const source = resolve6(input);
36169
+ if (!required && !await exists(source))
36170
+ continue;
36171
+ if (source === abs || await sameFile(abs, source)) {
36172
+ throw usageError(`Output path must not overwrite an input file: ${input}`);
36173
+ }
36174
+ }
36175
+ return abs;
36176
+ }
35920
36177
  async function writeOutput(args) {
35921
36178
  const dataWithMeta = args.meta && args.format === "json" && typeof args.data === "object" && args.data !== null && !Array.isArray(args.data) ? {
35922
36179
  ...args.data,
@@ -35928,28 +36185,7 @@ async function writeOutput(args) {
35928
36185
  `);
35929
36186
  return;
35930
36187
  }
35931
- const abs = resolve5(args.outPath);
35932
- for (const input of args.protectedInputs ?? []) {
35933
- const source = resolve5(input);
35934
- let same = source === abs;
35935
- if (!same) {
35936
- try {
35937
- const [outputReal, inputReal, outputStat, inputStat] = await Promise.all([
35938
- realpath(abs),
35939
- realpath(source),
35940
- stat(abs, { bigint: true }),
35941
- stat(source, { bigint: true })
35942
- ]);
35943
- same = outputReal === inputReal || outputStat.ino !== 0n && outputStat.dev === inputStat.dev && outputStat.ino === inputStat.ino;
35944
- } catch (error) {
35945
- const code = error.code;
35946
- if (code !== "ENOENT" && code !== "ENOTDIR")
35947
- throw error;
35948
- }
35949
- }
35950
- if (same)
35951
- throw usageError(`Output path must not overwrite an input file: ${input}`);
35952
- }
36188
+ const abs = await assertOutputNotInput(args.outPath, { protectedInputs: args.protectedInputs });
35953
36189
  await writeTextFile(abs, body);
35954
36190
  console.log(`Wrote ${args.format} output to ${abs}`);
35955
36191
  }
@@ -36801,7 +37037,7 @@ init_errors3();
36801
37037
  init_outputMeta();
36802
37038
  init_bun();
36803
37039
  import { closeSync as closeSync2, lstatSync as lstatSync2, openSync as openSync2, readlinkSync as readlinkSync2, realpathSync as realpathSync3, statSync, unlinkSync as unlinkSync2 } from "fs";
36804
- import { basename as basename3, dirname as dirname6, resolve as resolve7 } from "path";
37040
+ import { basename as basename3, dirname as dirname6, resolve as resolve8 } from "path";
36805
37041
 
36806
37042
  // src/lib/evaluation/input.ts
36807
37043
  init_dist2();
@@ -36831,17 +37067,17 @@ function evaluateRules(input) {
36831
37067
 
36832
37068
  // src/commands/judge.ts
36833
37069
  function canonical(path, depth = 0) {
36834
- const absolute = resolve7(path);
37070
+ const absolute = resolve8(path);
36835
37071
  try {
36836
37072
  return realpathSync3(absolute);
36837
37073
  } catch {
36838
37074
  try {
36839
37075
  if (depth < 32 && lstatSync2(absolute).isSymbolicLink()) {
36840
- return canonical(resolve7(dirname6(absolute), readlinkSync2(absolute)), depth + 1);
37076
+ return canonical(resolve8(dirname6(absolute), readlinkSync2(absolute)), depth + 1);
36841
37077
  }
36842
37078
  } catch {}
36843
37079
  const parent = dirname6(absolute);
36844
- return parent === absolute ? absolute : resolve7(canonical(parent, depth), basename3(absolute));
37080
+ return parent === absolute ? absolute : resolve8(canonical(parent, depth), basename3(absolute));
36845
37081
  }
36846
37082
  }
36847
37083
  function existingDirectory(path) {
@@ -36860,12 +37096,12 @@ function existingDirectory(path) {
36860
37096
  }
36861
37097
  function ignoresCase(directory) {
36862
37098
  const name = `.idlekit-case-${crypto.randomUUID()}`;
36863
- const path = resolve7(directory, name);
37099
+ const path = resolve8(directory, name);
36864
37100
  let fd;
36865
37101
  try {
36866
37102
  fd = openSync2(path, "wx");
36867
37103
  const original = statSync(path);
36868
- const folded = statSync(resolve7(directory, name.toUpperCase()));
37104
+ const folded = statSync(resolve8(directory, name.toUpperCase()));
36869
37105
  return original.dev === folded.dev && original.ino === folded.ino;
36870
37106
  } catch {
36871
37107
  return fd === undefined && process.platform === "win32";
@@ -36879,7 +37115,7 @@ function ignoresCase(directory) {
36879
37115
  }
36880
37116
  }
36881
37117
  }
36882
- function sameFile(left, right) {
37118
+ function sameFile2(left, right) {
36883
37119
  const aPath = canonical(left);
36884
37120
  const bPath = canonical(right);
36885
37121
  if (aPath === bPath)
@@ -36899,7 +37135,7 @@ function sameFile(left, right) {
36899
37135
  function ancestorFile(parent, child) {
36900
37136
  let directory = dirname6(canonical(child));
36901
37137
  for (;; ) {
36902
- if (sameFile(parent, directory))
37138
+ if (sameFile2(parent, directory))
36903
37139
  return true;
36904
37140
  const next = dirname6(directory);
36905
37141
  if (next === directory)
@@ -36931,6 +37167,17 @@ function requireFileTarget(path, flag) {
36931
37167
  current = parent;
36932
37168
  }
36933
37169
  }
37170
+ function readMetricVersion(diagnostic) {
37171
+ const ref = diagnostic?.evidenceRefs.find((item) => item.startsWith("metric-version:"));
37172
+ if (ref === undefined)
37173
+ return null;
37174
+ const version = Number(ref.slice("metric-version:".length));
37175
+ return Number.isFinite(version) ? version : null;
37176
+ }
37177
+ function versionLabel(diagnostic) {
37178
+ const version = readMetricVersion(diagnostic);
37179
+ return version === null ? "" : ` (metric version ${version})`;
37180
+ }
36934
37181
  function renderJudgeMarkdown(report) {
36935
37182
  const lines = [
36936
37183
  "# Rules judge",
@@ -36944,9 +37191,10 @@ function renderJudgeMarkdown(report) {
36944
37191
  "## Numerical",
36945
37192
  ""
36946
37193
  ];
36947
- for (const result of report.numerical.results) {
36948
- lines.push(`- ${result.metricId}: ${result.verdict} ${result.evidence.value ?? "none"} ${result.evidence.unit}`);
36949
- }
37194
+ report.numerical.results.forEach((result, index) => {
37195
+ const version = versionLabel(report.diagnostics[index]);
37196
+ lines.push(`- ${result.metricId}${version}: ${result.verdict} ${result.evidence.value ?? "none"} ${result.evidence.unit}`);
37197
+ });
36950
37198
  lines.push("", "## Estimates", "");
36951
37199
  if (report.estimatedObservations.length === 0)
36952
37200
  lines.push("None.");
@@ -36955,7 +37203,7 @@ function renderJudgeMarkdown(report) {
36955
37203
  }
36956
37204
  lines.push("", "## Semantic", "");
36957
37205
  for (const diagnostic of report.diagnostics) {
36958
- lines.push(`- ${diagnostic.status} ${diagnostic.recommendationId}: ${diagnostic.text.en}`);
37206
+ lines.push(`- ${diagnostic.status} ${diagnostic.recommendationId}${versionLabel(diagnostic)}: ${diagnostic.text.en}`);
36959
37207
  }
36960
37208
  return lines.join(`
36961
37209
  `);
@@ -36975,7 +37223,8 @@ function judgeCsvRows(report) {
36975
37223
  threshold: result.evidence.threshold,
36976
37224
  upperThreshold: result.evidence.upperThreshold,
36977
37225
  diagnosticStatus: diagnostic?.status ?? null,
36978
- recommendationId: diagnostic?.recommendationId ?? null
37226
+ recommendationId: diagnostic?.recommendationId ?? null,
37227
+ metricVersion: readMetricVersion(diagnostic)
36979
37228
  };
36980
37229
  });
36981
37230
  }
@@ -36987,14 +37236,17 @@ async function runJudge(flags, analysisPath, hooks) {
36987
37236
  if (flags.provider === "jev" && flags.format === "csv") {
36988
37237
  throw usageError("--provider jev writes json or md. csv cannot hold the rules report and the advisory together.");
36989
37238
  }
37239
+ const overwritten = flags.out ? [analysisPath, flags.rubric].find((input) => sameFile2(flags.out, input)) : undefined;
37240
+ if (overwritten)
37241
+ throw usageError(`Output path must not overwrite an input file: ${overwritten}`);
36990
37242
  if (flags.provider === "jev" && flags.cache) {
36991
- if (flags.out && sameFile(flags.cache, flags.out)) {
37243
+ if (flags.out && sameFile2(flags.cache, flags.out)) {
36992
37244
  throw usageError("--cache and --out name the same file. Give the Jev cache its own path.");
36993
37245
  }
36994
37246
  if (flags.out && (ancestorFile(flags.cache, flags.out) || ancestorFile(flags.out, flags.cache))) {
36995
37247
  throw usageError("--cache and --out cannot be ancestor paths. Give each file a separate target.");
36996
37248
  }
36997
- if (sameFile(flags.cache, analysisPath) || sameFile(flags.cache, flags.rubric)) {
37249
+ if (sameFile2(flags.cache, analysisPath) || sameFile2(flags.cache, flags.rubric)) {
36998
37250
  throw usageError("--cache names an input file. Give the Jev cache its own path.");
36999
37251
  }
37000
37252
  }
@@ -37027,6 +37279,7 @@ async function runJudge(flags, analysisPath, hooks) {
37027
37279
  await writeOutput({
37028
37280
  format: flags.format,
37029
37281
  outPath: flags.out,
37282
+ protectedInputs: [analysisPath, flags.rubric],
37030
37283
  data: flags.format === "md" ? renderJudgeMarkdown(report) : flags.format === "csv" ? judgeCsvRows(report) : report
37031
37284
  });
37032
37285
  return report;
@@ -37066,20 +37319,13 @@ async function runJudge(flags, analysisPath, hooks) {
37066
37319
  ...advisory.answers.length === 0 ? ["None."] : []
37067
37320
  ].join(`
37068
37321
  `);
37069
- if (flags.out) {
37070
- const outPath = resolve7(flags.out);
37071
- await writeTextFile(outPath, `${markdown}
37072
- `);
37073
- console.log(`Wrote md output to ${outPath}`);
37074
- } else {
37075
- await writeStdout(`${markdown}
37076
- `);
37077
- }
37322
+ await writeOutput({ format: "md", outPath: flags.out, data: markdown, protectedInputs: [analysisPath, flags.rubric] });
37078
37323
  return bundle;
37079
37324
  }
37080
37325
  await writeOutput({
37081
37326
  format: flags.format,
37082
37327
  outPath: flags.out,
37328
+ protectedInputs: [analysisPath, flags.rubric],
37083
37329
  data: bundle,
37084
37330
  meta: buildOutputMeta({
37085
37331
  command: "judge",
@@ -37120,7 +37366,7 @@ var judge_default = defineCommand({
37120
37366
  init_zod();
37121
37367
  init_errors3();
37122
37368
  init_outputMeta();
37123
- import { extname as extname3, resolve as resolve8 } from "path";
37369
+ import { extname as extname3, resolve as resolve9 } from "path";
37124
37370
 
37125
37371
  // src/lib/ltvCalibration.ts
37126
37372
  function assertFiniteNumbers(value, path) {
@@ -37151,18 +37397,50 @@ function clampCorrelation2(v) {
37151
37397
  function mean(values) {
37152
37398
  if (values.length === 0)
37153
37399
  return 0;
37154
- return values.reduce((a, b) => a + b, 0) / values.length;
37400
+ const sum = values.reduce((a, b) => a + b, 0);
37401
+ if (Number.isFinite(sum))
37402
+ return sum / values.length;
37403
+ return values.reduce((a, b) => a + b / values.length, 0);
37404
+ }
37405
+ function moments(x, y) {
37406
+ const n = Math.min(x.length, y.length);
37407
+ const mx = mean(x.slice(0, n));
37408
+ const my = mean(y.slice(0, n));
37409
+ const sums = (scaleX, scaleY) => {
37410
+ let cov = 0;
37411
+ let vx = 0;
37412
+ let vy = 0;
37413
+ for (let i = 0;i < n; i++) {
37414
+ const dx = ((x[i] ?? 0) - mx) / scaleX;
37415
+ const dy = ((y[i] ?? 0) - my) / scaleY;
37416
+ cov += dx * dy;
37417
+ vx += dx * dx;
37418
+ vy += dy * dy;
37419
+ }
37420
+ return { cov, vx, vy, scaleX, scaleY };
37421
+ };
37422
+ const plain = sums(1, 1);
37423
+ if (Number.isFinite(plain.cov) && Number.isFinite(plain.vx) && Number.isFinite(plain.vy))
37424
+ return plain;
37425
+ let scaleX = 0;
37426
+ let scaleY = 0;
37427
+ for (let i = 0;i < n; i++) {
37428
+ scaleX = Math.max(scaleX, Math.abs((x[i] ?? 0) - mx));
37429
+ scaleY = Math.max(scaleY, Math.abs((y[i] ?? 0) - my));
37430
+ }
37431
+ return sums(scaleX || 1, scaleY || 1);
37432
+ }
37433
+ function scaledVariance(sum, scale, n) {
37434
+ if (scale === 1)
37435
+ return sum / n;
37436
+ const deviation = scale * Math.sqrt(sum / n);
37437
+ return deviation * deviation;
37155
37438
  }
37156
37439
  function variance(values) {
37157
37440
  if (values.length === 0)
37158
37441
  return 0;
37159
- const m = mean(values);
37160
- let acc = 0;
37161
- for (const v of values) {
37162
- const d = v - m;
37163
- acc += d * d;
37164
- }
37165
- return acc / values.length;
37442
+ const { vx, scaleX } = moments(values, values);
37443
+ return scaledVariance(vx, scaleX, values.length);
37166
37444
  }
37167
37445
  function estimateCorrelation(x, y) {
37168
37446
  const n = Math.min(x.length, y.length);
@@ -37177,23 +37455,11 @@ function estimateCorrelation(x, y) {
37177
37455
  varianceY: 0
37178
37456
  };
37179
37457
  }
37180
- const sx = x.slice(0, n);
37181
- const sy = y.slice(0, n);
37182
- const mx = mean(sx);
37183
- const my = mean(sy);
37184
- let cov = 0;
37185
- let vx = 0;
37186
- let vy = 0;
37187
- for (let i = 0;i < n; i++) {
37188
- const dx = (sx[i] ?? 0) - mx;
37189
- const dy = (sy[i] ?? 0) - my;
37190
- cov += dx * dy;
37191
- vx += dx * dx;
37192
- vy += dy * dy;
37193
- }
37194
- const varianceX = vx / n;
37195
- const varianceY = vy / n;
37196
- if (vx <= 0.000000000001 || vy <= 0.000000000001) {
37458
+ const { cov, vx, vy, scaleX, scaleY } = moments(x.slice(0, n), y.slice(0, n));
37459
+ const varianceX = scaledVariance(vx, scaleX, n);
37460
+ const varianceY = scaledVariance(vy, scaleY, n);
37461
+ const flat = (sum, scale) => scale === 1 ? sum <= 0.000000000001 : scale * Math.sqrt(sum) <= 0.000001;
37462
+ if (flat(vx, scaleX) || flat(vy, scaleY)) {
37197
37463
  return {
37198
37464
  raw: 0,
37199
37465
  value: 0,
@@ -37223,18 +37489,53 @@ function estimateCorrelation(x, y) {
37223
37489
  varianceY
37224
37490
  };
37225
37491
  }
37492
+ var FEATURE_SOURCES = {
37493
+ conversion: ["iapRevenue"],
37494
+ arppu: ["iapRevenue"],
37495
+ adArpDau: ["adRevenue"]
37496
+ };
37497
+ var CORRELATION_SOURCES = {
37498
+ retentionConversion: ["iapRevenue"],
37499
+ retentionArppu: ["iapRevenue"],
37500
+ retentionAd: ["adRevenue"],
37501
+ conversionArppu: ["iapRevenue"],
37502
+ conversionAd: ["iapRevenue", "adRevenue"],
37503
+ arppuAd: ["iapRevenue", "adRevenue"]
37504
+ };
37505
+ function pickMeasured(keys, measured, value) {
37506
+ const out = {};
37507
+ for (const key of Object.keys(keys)) {
37508
+ if (keys[key].every((source) => measured.has(source)))
37509
+ out[key] = value(key);
37510
+ }
37511
+ return out;
37512
+ }
37226
37513
  function calibrateMonetization(rows) {
37227
37514
  if (rows.length === 0) {
37228
37515
  throw new Error("calibration rows cannot be empty");
37229
37516
  }
37517
+ const measured = new Set;
37518
+ for (const source of ["iapRevenue", "adRevenue"]) {
37519
+ const supplied = rows.filter((row) => row[source] !== undefined).length;
37520
+ if (supplied > 0 && supplied < rows.length) {
37521
+ throw new RangeError(`${source} must be supplied on every telemetry row or omitted from every row`);
37522
+ }
37523
+ if (supplied > 0)
37524
+ measured.add(source);
37525
+ }
37526
+ if (rows.some((row) => row.acquisitionCost !== undefined))
37527
+ measured.add("acquisitionCost");
37528
+ const iapMeasured = measured.has("iapRevenue");
37529
+ const adMeasured = measured.has("adRevenue");
37530
+ const revenueMeasured = iapMeasured || adMeasured;
37230
37531
  const users = new Map;
37231
37532
  for (const row of rows) {
37232
37533
  const day = Math.max(0, Math.floor(row.day));
37233
37534
  const u = users.get(row.userId) ?? { days: new Set, iap: 0, ad: 0, acq: undefined };
37234
- if (row.active ?? true)
37535
+ if ((row.active ?? true) || day === 0)
37235
37536
  u.days.add(day);
37236
- u.iap += Math.max(0, row.iapRevenue);
37237
- u.ad += Math.max(0, row.adRevenue);
37537
+ u.iap += Math.max(0, row.iapRevenue ?? 0);
37538
+ u.ad += Math.max(0, row.adRevenue ?? 0);
37238
37539
  if (row.acquisitionCost !== undefined && Number.isFinite(row.acquisitionCost)) {
37239
37540
  u.acq = (u.acq ?? 0) + Math.max(0, row.acquisitionCost);
37240
37541
  }
@@ -37279,52 +37580,25 @@ function calibrateMonetization(rows) {
37279
37580
  const adArpDau = totalAd / Math.max(1, activeUserDays);
37280
37581
  const cpi = totalAcq / Math.max(1, acqUsers);
37281
37582
  const userRetention = [];
37282
- const userConversion = [];
37283
- const userArppu = [];
37284
- const userAdArpDau = [];
37583
+ const features = { conversion: [], arppu: [], adArpDau: [] };
37285
37584
  for (const user of users.values()) {
37286
37585
  const activeDays = Math.max(1, user.days.size);
37287
- const retentionScore = clamp014(activeDays / 30);
37288
- const conversionScore = user.iap > 0 ? 1 : 0;
37289
- const arppuScore = user.iap > 0 ? user.iap / activeDays : 0;
37290
- const adScore = user.ad / activeDays;
37291
- userRetention.push(retentionScore);
37292
- userConversion.push(conversionScore);
37293
- userArppu.push(arppuScore);
37294
- userAdArpDau.push(adScore);
37295
- }
37296
- const estimatedCorrelationPair = {
37297
- retentionConversion: estimateCorrelation(userRetention, userConversion),
37298
- retentionArppu: estimateCorrelation(userRetention, userArppu),
37299
- retentionAd: estimateCorrelation(userRetention, userAdArpDau),
37300
- conversionArppu: estimateCorrelation(userConversion, userArppu),
37301
- conversionAd: estimateCorrelation(userConversion, userAdArpDau),
37302
- arppuAd: estimateCorrelation(userArppu, userAdArpDau)
37303
- };
37304
- const estimatedCorrelation = {
37305
- retentionConversion: estimatedCorrelationPair.retentionConversion.value,
37306
- retentionArppu: estimatedCorrelationPair.retentionArppu.value,
37307
- retentionAd: estimatedCorrelationPair.retentionAd.value,
37308
- conversionArppu: estimatedCorrelationPair.conversionArppu.value,
37309
- conversionAd: estimatedCorrelationPair.conversionAd.value,
37310
- arppuAd: estimatedCorrelationPair.arppuAd.value
37311
- };
37312
- const estimatedCorrelationRaw = {
37313
- retentionConversion: estimatedCorrelationPair.retentionConversion.raw,
37314
- retentionArppu: estimatedCorrelationPair.retentionArppu.raw,
37315
- retentionAd: estimatedCorrelationPair.retentionAd.raw,
37316
- conversionArppu: estimatedCorrelationPair.conversionArppu.raw,
37317
- conversionAd: estimatedCorrelationPair.conversionAd.raw,
37318
- arppuAd: estimatedCorrelationPair.arppuAd.raw
37319
- };
37320
- const correlationConfidence = {
37321
- retentionConversion: estimatedCorrelationPair.retentionConversion.confidence,
37322
- retentionArppu: estimatedCorrelationPair.retentionArppu.confidence,
37323
- retentionAd: estimatedCorrelationPair.retentionAd.confidence,
37324
- conversionArppu: estimatedCorrelationPair.conversionArppu.confidence,
37325
- conversionAd: estimatedCorrelationPair.conversionAd.confidence,
37326
- arppuAd: estimatedCorrelationPair.arppuAd.confidence
37327
- };
37586
+ userRetention.push(clamp014(activeDays / 30));
37587
+ features.conversion.push(user.iap > 0 ? 1 : 0);
37588
+ features.arppu.push(user.iap > 0 ? user.iap / activeDays : 0);
37589
+ features.adArpDau.push(user.ad / activeDays);
37590
+ }
37591
+ const correlationInputs = {
37592
+ retentionConversion: [userRetention, features.conversion],
37593
+ retentionArppu: [userRetention, features.arppu],
37594
+ retentionAd: [userRetention, features.adArpDau],
37595
+ conversionArppu: [features.conversion, features.arppu],
37596
+ conversionAd: [features.conversion, features.adArpDau],
37597
+ arppuAd: [features.arppu, features.adArpDau]
37598
+ };
37599
+ const estimatedCorrelationPair = pickMeasured(CORRELATION_SOURCES, measured, (key) => estimateCorrelation(...correlationInputs[key]));
37600
+ const correlationField = (field) => pickMeasured(CORRELATION_SOURCES, measured, (key) => estimatedCorrelationPair[key][field]);
37601
+ const estimatedCorrelation = correlationField("value");
37328
37602
  const result = {
37329
37603
  monetization: {
37330
37604
  cohorts: {
@@ -37337,44 +37611,38 @@ function calibrateMonetization(rows) {
37337
37611
  d90: clamp014(Math.min(d1, d7, d30, d90)),
37338
37612
  longTailDailyDecay: 0.02
37339
37613
  },
37340
- revenue: {
37341
- payerConversion: clamp014(payerConversion),
37342
- arppuDaily: Math.max(0, arppuDaily),
37343
- adArpDau: Math.max(0, adArpDau),
37344
- platformFeeRate: 0.3,
37345
- grossMarginRate: 0.92
37346
- },
37347
- acquisition: {
37348
- cpi: Math.max(0, cpi)
37349
- },
37350
- uncertainty: {
37351
- enabled: true,
37352
- draws: 300,
37353
- quantiles: [0.5, 0.9],
37354
- sigma: {
37355
- retention: 0.08,
37356
- conversion: 0.12,
37357
- arppu: 0.2,
37358
- ad: 0.15
37359
- },
37360
- correlation: {
37361
- retentionConversion: estimatedCorrelation.retentionConversion,
37362
- retentionArppu: estimatedCorrelation.retentionArppu,
37363
- retentionAd: estimatedCorrelation.retentionAd,
37364
- conversionArppu: estimatedCorrelation.conversionArppu,
37365
- conversionAd: estimatedCorrelation.conversionAd,
37366
- arppuAd: estimatedCorrelation.arppuAd
37614
+ ...revenueMeasured ? {
37615
+ revenue: {
37616
+ ...iapMeasured ? { payerConversion: clamp014(payerConversion), arppuDaily: Math.max(0, arppuDaily) } : {},
37617
+ ...adMeasured ? { adArpDau: Math.max(0, adArpDau) } : {},
37618
+ platformFeeRate: 0.3,
37619
+ grossMarginRate: 0.92
37367
37620
  }
37368
- }
37621
+ } : {},
37622
+ ...measured.has("acquisitionCost") ? { acquisition: { cpi: Math.max(0, cpi) } } : {},
37623
+ ...revenueMeasured ? {
37624
+ uncertainty: {
37625
+ enabled: true,
37626
+ draws: 300,
37627
+ quantiles: [0.5, 0.9],
37628
+ sigma: {
37629
+ retention: 0.08,
37630
+ conversion: 0.12,
37631
+ arppu: 0.2,
37632
+ ad: 0.15
37633
+ },
37634
+ correlation: estimatedCorrelation
37635
+ }
37636
+ } : {}
37369
37637
  },
37370
37638
  diagnostics: {
37371
37639
  users: cohortSize,
37372
37640
  totalRows: rows.length,
37373
- totalIap,
37374
- totalAd,
37641
+ ...iapMeasured ? { totalIap } : {},
37642
+ ...adMeasured ? { totalAd } : {},
37375
37643
  activeUserDays,
37376
- payerUsers,
37377
- payerDays,
37644
+ ...iapMeasured ? { payerUsers, payerDays } : {},
37645
+ ...measured.size < 3 ? { unmeasured: ["iapRevenue", "adRevenue", "acquisitionCost"].filter((source) => !measured.has(source)) } : {},
37378
37646
  retention: {
37379
37647
  d1,
37380
37648
  d7,
@@ -37383,14 +37651,14 @@ function calibrateMonetization(rows) {
37383
37651
  },
37384
37652
  userFeatureVariance: {
37385
37653
  retention: variance(userRetention),
37386
- conversion: variance(userConversion),
37387
- arppu: variance(userArppu),
37388
- adArpDau: variance(userAdArpDau)
37654
+ ...pickMeasured(FEATURE_SOURCES, measured, (key) => variance(features[key]))
37389
37655
  },
37390
- estimatedCorrelation,
37391
- estimatedCorrelationRaw,
37392
- correlationConfidence,
37393
- correlationDiagnostics: estimatedCorrelationPair
37656
+ ...revenueMeasured ? {
37657
+ estimatedCorrelation,
37658
+ estimatedCorrelationRaw: correlationField("raw"),
37659
+ correlationConfidence: correlationField("confidence"),
37660
+ correlationDiagnostics: estimatedCorrelationPair
37661
+ } : {}
37394
37662
  }
37395
37663
  };
37396
37664
  assertFiniteNumbers(result, "calibration");
@@ -37533,13 +37801,14 @@ function parseCsvTelemetry(raw, strictCohort = false) {
37533
37801
  throw usageError("Observed cohort requires explicit user_id and day fields");
37534
37802
  const userId = userInput ?? `anon-${i}`;
37535
37803
  const dayRaw = dayInput ?? "0";
37536
- const iapRaw = pick2(rec, ["iap_revenue", "revenue", "iap", "purchase_revenue"]) ?? "0";
37537
- const adRaw = pick2(rec, ["ad_revenue", "adrevenue", "ads"]) ?? "0";
37804
+ const missingRevenue = strictCohort ? undefined : "0";
37805
+ const iapRaw = pick2(rec, ["iap_revenue", "revenue", "iap", "purchase_revenue"]) ?? missingRevenue;
37806
+ const adRaw = pick2(rec, ["ad_revenue", "adrevenue", "ads"]) ?? missingRevenue;
37538
37807
  const activeRaw = pick2(rec, ["active", "is_active"]);
37539
37808
  const acqRaw = pick2(rec, ["acquisition_cost", "ua_cost", "cpi"]);
37540
37809
  const day = parseNumeric(dayRaw, i + 1, "day");
37541
- const iapRevenue = parseNumeric(iapRaw, i + 1, "revenue");
37542
- const adRevenue = parseNumeric(adRaw, i + 1, "ad_revenue");
37810
+ const iapRevenue = iapRaw === undefined ? undefined : parseNumeric(iapRaw, i + 1, "revenue");
37811
+ const adRevenue = adRaw === undefined ? undefined : parseNumeric(adRaw, i + 1, "ad_revenue");
37543
37812
  const acquisitionCost = acqRaw !== undefined ? parseNumeric(acqRaw, i + 1, "acquisition_cost", { allowEmpty: true }) : undefined;
37544
37813
  const active = parseActive(activeRaw, strictCohort);
37545
37814
  rows.push({
@@ -37575,11 +37844,14 @@ function parseJsonTelemetry(raw, strictCohort = false) {
37575
37844
  }
37576
37845
  const userId = String(userInput ?? `anon-${idx}`);
37577
37846
  const day = Number(dayInput ?? 0);
37578
- const iapRevenue = Number(r.iapRevenue ?? r.iap_revenue ?? r.revenue ?? 0);
37579
- const adRevenue = Number(r.adRevenue ?? r.ad_revenue ?? 0);
37847
+ const missingRevenue = strictCohort ? undefined : 0;
37848
+ const iapInput = r.iapRevenue ?? r.iap_revenue ?? r.revenue ?? missingRevenue;
37849
+ const adInput = r.adRevenue ?? r.ad_revenue ?? missingRevenue;
37850
+ const iapRevenue = iapInput === undefined ? undefined : Number(iapInput);
37851
+ const adRevenue = adInput === undefined ? undefined : Number(adInput);
37580
37852
  const acquisitionCost = r.acquisitionCost !== undefined || r.acquisition_cost !== undefined || r.cpi !== undefined ? Number(r.acquisitionCost ?? r.acquisition_cost ?? r.cpi) : undefined;
37581
37853
  const active = parseActive(r.active, strictCohort);
37582
- if (!Number.isFinite(day) || !Number.isFinite(iapRevenue) || !Number.isFinite(adRevenue)) {
37854
+ if (!Number.isFinite(day) || ![iapRevenue, adRevenue].every((v) => v === undefined || Number.isFinite(v))) {
37583
37855
  throw cliError("CLI_USAGE", `Invalid numeric value in json row ${idx}`);
37584
37856
  }
37585
37857
  rows.push({
@@ -37614,7 +37886,7 @@ var calibrate_default = defineCommand({
37614
37886
  }
37615
37887
  if (flags.scenario && flags["observed-through-day"] === undefined)
37616
37888
  throw usageError("--scenario requires --observed-through-day for a mature cohort comparison");
37617
- const abs = resolve8(process.cwd(), telemetryPath);
37889
+ const abs = resolve9(process.cwd(), telemetryPath);
37618
37890
  const raw = await readTextFile(abs);
37619
37891
  const format = flags["input-format"] === "auto" ? extname3(abs).toLowerCase() : flags["input-format"];
37620
37892
  const rows = format === ".csv" || format === "csv" ? parseCsvTelemetry(raw, flags["observed-through-day"] !== undefined) : parseJsonTelemetry(raw, flags["observed-through-day"] !== undefined);
@@ -37653,12 +37925,12 @@ var calibrate_default = defineCommand({
37653
37925
  command: "calibrate",
37654
37926
  telemetry: observation ? { rows, observedThroughDay: observation.observedThroughDay } : rows,
37655
37927
  scenario,
37656
- scenarioPath: flags.scenario ? resolve8(flags.scenario) : undefined
37928
+ scenarioPath: flags.scenario ? resolve9(flags.scenario) : undefined
37657
37929
  });
37658
37930
  await writeOutput({
37659
37931
  format: flags.format,
37660
37932
  outPath: flags.out,
37661
- protectedInputs: [abs, ...flags.scenario ? [resolve8(flags.scenario)] : []],
37933
+ protectedInputs: [abs, ...flags.scenario ? [resolve9(flags.scenario)] : []],
37662
37934
  data: flags.format === "json" ? {
37663
37935
  ok: true,
37664
37936
  source: abs,
@@ -37698,7 +37970,7 @@ var calibrate_default = defineCommand({
37698
37970
  payerConversion: (calibrated.monetization?.revenue?.payerConversion ?? 0).toFixed(4),
37699
37971
  arppuDaily: (calibrated.monetization?.revenue?.arppuDaily ?? 0).toFixed(4),
37700
37972
  adArpDau: (calibrated.monetization?.revenue?.adArpDau ?? 0).toFixed(4),
37701
- cpi: (calibrated.monetization?.acquisition?.cpi ?? 0).toFixed(4)
37973
+ cpi: calibrated.monetization?.acquisition?.cpi?.toFixed(4) ?? ""
37702
37974
  }
37703
37975
  ],
37704
37976
  meta: outputMeta
@@ -37708,12 +37980,12 @@ var calibrate_default = defineCommand({
37708
37980
 
37709
37981
  // src/commands/balance.ts
37710
37982
  init_zod();
37711
- import { resolve as resolve11 } from "path";
37983
+ import { resolve as resolve12 } from "path";
37712
37984
 
37713
37985
  // src/balance/workflow.ts
37714
37986
  init_dist2();
37715
37987
  init_zod();
37716
- import { resolve as resolve10, dirname as dirname8 } from "path";
37988
+ import { resolve as resolve11, dirname as dirname8 } from "path";
37717
37989
  import { stat as stat2 } from "fs/promises";
37718
37990
 
37719
37991
  // src/cliMeta.ts
@@ -37728,7 +38000,7 @@ init_bun();
37728
38000
 
37729
38001
  // src/balance/pacingAmount.ts
37730
38002
  var MAX_DECIMAL_LENGTH = 200;
37731
- var DECIMAL = /^([+-]?)(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:[eE]([+-]?\d+))?$/;
38003
+ var DECIMAL = /^([+-]?)(?:(\d+)(?:\.(\d+))?|\.(\d+))(?:e([+-]?\d+))?$/i;
37732
38004
  function pacingValue(value) {
37733
38005
  if (typeof value === "number")
37734
38006
  return Number.isFinite(value) ? Object.is(value, -0) ? 0 : value : undefined;
@@ -38004,7 +38276,7 @@ async function runPacingChecks(input, evaluator) {
38004
38276
  init_bun();
38005
38277
  import { constants } from "fs";
38006
38278
  import { lstat, mkdir, open as open2, realpath as realpath2, rename, rm } from "fs/promises";
38007
- import { dirname as dirname7, isAbsolute as isAbsolute2, join, relative as relative2, resolve as resolve9, sep as sep2 } from "path";
38279
+ import { dirname as dirname7, isAbsolute as isAbsolute2, join, relative as relative2, resolve as resolve10, sep as sep2 } from "path";
38008
38280
  var SHEET_LIMITS = Object.freeze({
38009
38281
  maxCsvBytes: 2 * 1024 * 1024,
38010
38282
  maxRows: 10001,
@@ -38376,7 +38648,7 @@ async function snapshotInputs(inputFiles, contextValue, limits) {
38376
38648
  const inputs = Object.create(null);
38377
38649
  let total = 0;
38378
38650
  for (const name of validInputNames(inputFiles, limits)) {
38379
- const path = resolve9(inputFiles[name]);
38651
+ const path = resolve10(inputFiles[name]);
38380
38652
  const realPath = await realpath2(path);
38381
38653
  const bytes = await boundedRead(realPath, Math.min(limits.maxInputBytes, limits.maxTotalInputBytes - total));
38382
38654
  total += bytes.length;
@@ -38402,7 +38674,7 @@ async function snapshotInputs(inputFiles, contextValue, limits) {
38402
38674
  });
38403
38675
  }
38404
38676
  async function canonicalOutput(path) {
38405
- path = resolve9(path);
38677
+ path = resolve10(path);
38406
38678
  try {
38407
38679
  return await realpath2(path);
38408
38680
  } catch (error) {
@@ -38441,7 +38713,7 @@ async function refreshSheetBundle(options) {
38441
38713
  validInputNames(options.inputFiles, limits);
38442
38714
  const output = await canonicalOutput(options.outputDir);
38443
38715
  for (const [name, path] of Object.entries(options.inputFiles)) {
38444
- if (isWithin(output, resolve9(path)) || isWithin(output, await realpath2(path)))
38716
+ if (isWithin(output, resolve10(path)) || isWithin(output, await realpath2(path)))
38445
38717
  throw new Error(`Output/input collision: ${name}`);
38446
38718
  }
38447
38719
  await mkdir(output, { recursive: true });
@@ -38701,7 +38973,7 @@ function normalizeRunDocument(document, strategy, horizon) {
38701
38973
  target.outputs = { ...target.outputs, report: { ...target.outputs?.report, includeTrace: true, traceEverySteps: MAX_STEPS_PER_RUN + 1 } };
38702
38974
  }
38703
38975
  async function refreshBalanceWorkflow(configPath, flags, check = false) {
38704
- const absoluteConfig = resolve10(configPath);
38976
+ const absoluteConfig = resolve11(configPath);
38705
38977
  const configInfo = await stat2(absoluteConfig);
38706
38978
  if (!configInfo.isFile() || configInfo.size > SHEET_LIMITS.maxInputBytes)
38707
38979
  throw new Error("Workflow config is not a bounded regular file");
@@ -38710,18 +38982,18 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
38710
38982
  const base = dirname8(absoluteConfig);
38711
38983
  const inputFiles = {
38712
38984
  config: absoluteConfig,
38713
- sheet: resolve10(base, config.sheet),
38714
- schema: resolve10(base, config.schema),
38715
- scenario: resolve10(base, config.scenario)
38985
+ sheet: resolve11(base, config.sheet),
38986
+ schema: resolve11(base, config.schema),
38987
+ scenario: resolve11(base, config.scenario)
38716
38988
  };
38717
38989
  if (flags["plugin-trust-file"])
38718
- inputFiles.pluginTrust = resolve10(flags["plugin-trust-file"]);
38990
+ inputFiles.pluginTrust = resolve11(flags["plugin-trust-file"]);
38719
38991
  const loaded = await loadRegistriesFromFlags(flags);
38720
38992
  for (const [index, path] of Object.keys(loaded.pluginDigest).entries())
38721
38993
  inputFiles[`plugin${index}`] = path;
38722
38994
  const engine = resolveEffectiveEngine({ requested: flags.engine });
38723
38995
  const context = { cliVersion: CLI_VERSION, bunVersion: Bun.version, pluginDigests: JSON.stringify(loaded.pluginDigest), engine: engine.effectiveId };
38724
- const outputDir = resolve10(base, config.outputDir);
38996
+ const outputDir = resolve11(base, config.outputDir);
38725
38997
  if (check)
38726
38998
  return readCurrentBundle(outputDir, inputFiles, { context });
38727
38999
  let outcome;
@@ -38913,12 +39185,24 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
38913
39185
  function cell(value) {
38914
39186
  return String(value).replaceAll("|", "\\|").replace(/[\r\n]/g, " ");
38915
39187
  }
39188
+ function decimals(value) {
39189
+ const [mantissa = "", exponent = "0"] = String(value).split("e");
39190
+ return Math.max(0, (mantissa.split(".")[1]?.length ?? 0) - Number(exponent));
39191
+ }
39192
+ function gap(larger, smaller) {
39193
+ const difference = larger - smaller;
39194
+ if (!Number.isFinite(difference) || difference === 0)
39195
+ return difference;
39196
+ const lastPlace = Math.max(decimals(larger), decimals(smaller));
39197
+ const digits = lastPlace + Math.floor(Math.log10(Math.abs(difference))) + 1;
39198
+ return Number(difference.toPrecision(Math.min(17, Math.max(1, digits))));
39199
+ }
38916
39200
  function explain(result) {
38917
39201
  if (result.status === "breach" && result.value !== null) {
38918
39202
  if (result.min !== undefined && comparePacingValues(result.value, result.min) < 0)
38919
- return typeof result.min === "number" && typeof result.value === "number" ? `below the minimum by ${result.min - result.value} ${result.unit}` : `below the minimum ${result.min} ${result.unit}`;
39203
+ return typeof result.min === "number" && typeof result.value === "number" ? `below the minimum by ${gap(result.min, result.value)} ${result.unit}` : `below the minimum ${result.min} ${result.unit}`;
38920
39204
  if (result.max !== undefined && comparePacingValues(result.value, result.max) > 0)
38921
- return typeof result.max === "number" && typeof result.value === "number" ? `above the maximum by ${result.value - result.max} ${result.unit}` : `above the maximum ${result.max} ${result.unit}`;
39205
+ return typeof result.max === "number" && typeof result.value === "number" ? `above the maximum by ${gap(result.value, result.max)} ${result.unit}` : `above the maximum ${result.max} ${result.unit}`;
38922
39206
  }
38923
39207
  if (result.status === "pass")
38924
39208
  return "within the inclusive target bounds";
@@ -38965,7 +39249,7 @@ var balance_default = defineCommand({
38965
39249
  if (positional.length !== 1)
38966
39250
  throw usageError("Usage: idk balance <workflow.json> [--check] [plugin options]");
38967
39251
  const result = await refreshBalanceWorkflow(positional[0], flags, flags.check);
38968
- const body = flags.format === "json" ? JSON.stringify(result, null, 2) : ("state" in result) ? renderBalanceFreshness(result) : renderBalanceReport(JSON.parse(await readTextFile(resolve11(result.generationPath, "results.json"))), result.generationPath);
39252
+ const body = flags.format === "json" ? JSON.stringify(result, null, 2) : ("state" in result) ? renderBalanceFreshness(result) : renderBalanceReport(JSON.parse(await readTextFile(resolve12(result.generationPath, "results.json"))), result.generationPath);
38969
39253
  await writeStdout(body + `
38970
39254
  `);
38971
39255
  if (flags.check && "state" in result && result.state !== "current")
@@ -39010,7 +39294,6 @@ import { resolve as resolve13 } from "path";
39010
39294
  // src/io/replayArtifact.ts
39011
39295
  init_outputMeta();
39012
39296
  init_bun();
39013
- import { resolve as resolve12 } from "path";
39014
39297
  var REDACTED_KEYS = new Set([
39015
39298
  "generatedAt",
39016
39299
  "scenario",
@@ -39076,7 +39359,7 @@ function toReplayCommandLine(args) {
39076
39359
  return `bun run --cwd packages/cli dev -- ${rendered}`;
39077
39360
  }
39078
39361
  async function writeReplayArtifact(args) {
39079
- const abs = resolve12(args.outPath);
39362
+ const abs = await assertOutputNotInput(args.outPath);
39080
39363
  const runId = args.meta.runId;
39081
39364
  const seed = args.meta.seed;
39082
39365
  const scenarioHash = args.meta.scenarioHash;
@@ -39422,17 +39705,16 @@ function compareIdentity2(args) {
39422
39705
  milestoneKey: metrics.includes("timeToMilestone") ? compareMilestoneKey(flags) ?? null : null
39423
39706
  };
39424
39707
  }
39708
+ function requireFiniteAmount(E, amount, label) {
39709
+ if (!E.isFinite(amount))
39710
+ throw new RangeError(`compare ${label} must be finite in the selected engine`);
39711
+ return amount;
39712
+ }
39425
39713
  function measureScenario(args) {
39426
- const requireFinite = (amount, label) => {
39427
- if (!args.E.isFinite(amount))
39428
- throw new RangeError(`compare ${label} must be finite in the selected engine`);
39429
- return amount;
39430
- };
39714
+ const requireFinite = (amount, label) => requireFiniteAmount(args.E, amount, label);
39431
39715
  const runInput = args.compiled.fresh("economy");
39432
39716
  const run = runScenario(runInput);
39433
39717
  const endWorth = runInput.model.netWorth?.(runInput.ctx, run.end) ?? run.end.wallet.money;
39434
- requireFinite(run.end.wallet.money.amount, "end money");
39435
- requireFinite(endWorth.amount, "end net worth");
39436
39718
  let etaSeconds;
39437
39719
  let etaReached;
39438
39720
  if (args.targetWorth) {
@@ -39630,9 +39912,9 @@ function bundleMetrics(bundle) {
39630
39912
  function compareDecisionForMetric(args) {
39631
39913
  switch (args.metric) {
39632
39914
  case "endMoney":
39633
- return betterFromCmp(args.E.cmp(args.ma.endMoney, args.mb.endMoney));
39915
+ return betterFromCmp(args.E.cmp(requireFiniteAmount(args.E, args.ma.endMoney, "end money"), requireFiniteAmount(args.E, args.mb.endMoney, "end money")));
39634
39916
  case "endNetWorth":
39635
- return betterFromCmp(args.E.cmp(args.ma.endNetWorth, args.mb.endNetWorth));
39917
+ return betterFromCmp(args.E.cmp(requireFiniteAmount(args.E, args.ma.endNetWorth, "end net worth"), requireFiniteAmount(args.E, args.mb.endNetWorth, "end net worth")));
39636
39918
  case "droppedRate":
39637
39919
  return betterFromCmp(args.ma.droppedRate < args.mb.droppedRate ? 1 : args.ma.droppedRate > args.mb.droppedRate ? -1 : 0);
39638
39920
  case "etaToTargetWorth": {
@@ -39706,7 +39988,7 @@ function buildSingleCompareOutput(args) {
39706
39988
  },
39707
39989
  insights: buildCompareInsights({
39708
39990
  metric: args.metric,
39709
- endNetWorthWinner: betterFromCmp(args.E.cmp(args.ma.endNetWorth, args.mb.endNetWorth)),
39991
+ endNetWorthWinner: args.E.isFinite(args.ma.endNetWorth) && args.E.isFinite(args.mb.endNetWorth) ? betterFromCmp(args.E.cmp(args.ma.endNetWorth, args.mb.endNetWorth)) : "tie",
39710
39992
  better: result.better,
39711
39993
  a: {
39712
39994
  endNetWorth: args.E.toString(args.ma.endNetWorth),
@@ -39885,7 +40167,8 @@ var compare_default = defineCommand({
39885
40167
  a: aScenario,
39886
40168
  b: bScenario
39887
40169
  },
39888
- pluginDigest: loaded.pluginDigest
40170
+ pluginDigest: loaded.pluginDigest,
40171
+ effectiveEngine: engine.effectiveId
39889
40172
  });
39890
40173
  const markdownWarnings = new Set;
39891
40174
  if (selectedMetrics.some((metric) => ["endMoney", "endNetWorth", "droppedRate"].includes(metric))) {
@@ -39895,6 +40178,9 @@ var compare_default = defineCommand({
39895
40178
  markdownWarnings.add(`Economy runs cover different elapsed durations (A: ${aElapsed}s, B: ${bElapsed}s); end values are not normalized to a common horizon.`);
39896
40179
  }
39897
40180
  }
40181
+ if ([ma.endMoney, ma.endNetWorth, mb.endMoney, mb.endNetWorth].some((amount) => !E.isFinite(amount))) {
40182
+ markdownWarnings.add("The full-duration economy run left the selected engine's finite range; its end values are reported but not ranked.");
40183
+ }
39898
40184
  const singleResults = selectedMetrics.map((metric) => {
39899
40185
  const design = getDesignPair(metric);
39900
40186
  if (design) {
@@ -39990,8 +40276,8 @@ init_outputMeta();
39990
40276
  // src/lib/setup.ts
39991
40277
  init_errors3();
39992
40278
  init_bun();
39993
- init_selfCli();
39994
40279
  import { basename as basename4, dirname as dirname9, relative as relative3, resolve as resolve15 } from "path";
40280
+ init_selfCli();
39995
40281
  var START_MARKER = "# >>> idk completions >>>";
39996
40282
  var END_MARKER = "# <<< idk completions <<<";
39997
40283
  function userHome() {
@@ -40132,7 +40418,7 @@ async function writePluginTrust(args) {
40132
40418
  if (args.plugins.length === 0) {
40133
40419
  throw usageError("setup plugin-trust requires at least one --plugin path.");
40134
40420
  }
40135
- const outPath = resolve15(args.outPath);
40421
+ const outPath = await assertOutputNotInput(args.outPath, { protectedInputs: args.plugins });
40136
40422
  if (await fileExists(outPath) && !args.force) {
40137
40423
  throw usageError(`Output file already exists: ${outPath}`, "Pass --force true to overwrite.");
40138
40424
  }
@@ -40633,6 +40919,9 @@ import { resolve as resolve17 } from "path";
40633
40919
  init_errors3();
40634
40920
  init_outputMeta();
40635
40921
  var strategySchema2 = string2().min(1).optional();
40922
+ function uint32Seed(seed) {
40923
+ return Number.isFinite(seed) ? seed >>> 0 : seed;
40924
+ }
40636
40925
  function parseHorizonToken(raw) {
40637
40926
  const token = raw.trim().toLowerCase();
40638
40927
  if (!token)
@@ -40788,7 +41077,7 @@ function runLtvAnalysis(args) {
40788
41077
  }
40789
41078
  const worth = args.compiled.model.netWorth?.(args.compiled.ctx, state) ?? state.wallet.money;
40790
41079
  const endWorthLog10 = args.compiled.ctx.E.absLog10(worth.amount);
40791
- const progression = progressionFactor(startWorthLog10, endWorthLog10, monetizationConfig.revenue.progressionLogSpan);
41080
+ const progression = progressionFactor2(startWorthLog10, endWorthLog10, monetizationConfig.revenue.progressionLogSpan);
40792
41081
  const horizonDays = h.seconds / 86400;
40793
41082
  const point = estimateLtvPerUser2({
40794
41083
  config: monetizationConfig,
@@ -40801,7 +41090,7 @@ function runLtvAnalysis(args) {
40801
41090
  progression,
40802
41091
  draws,
40803
41092
  quantiles: monetizationConfig.uncertainty.quantiles,
40804
- seed: (args.seed ?? monetizationConfig.uncertainty.seed ?? 1) + h.seconds
41093
+ seed: uint32Seed((args.seed ?? monetizationConfig.uncertainty.seed ?? 1) + h.seconds)
40805
41094
  }) : undefined;
40806
41095
  const E = args.compiled.ctx.E;
40807
41096
  const deltaWorth = E.sub(worth.amount, previousWorth.amount);
@@ -41375,6 +41664,8 @@ var evaluate_default = defineCommand({
41375
41664
  files.ltv = resolve18(outDir, "ltv.json");
41376
41665
  const summaryPath = resolve18(process.cwd(), flags["out-dir"], flags.format === "md" ? "summary.md" : "summary.json");
41377
41666
  files.summary = summaryPath;
41667
+ for (const path of [files.simulate, files.experience, files.ltv, summaryPath])
41668
+ await assertOutputNotInput(path);
41378
41669
  await writeTextFile(files.simulate, `${JSON.stringify({ ...simulate, _meta: simulateMeta }, null, 2)}
41379
41670
  `);
41380
41671
  await writeTextFile(files.experience, `${JSON.stringify({ ...experience, _meta: experienceMeta }, null, 2)}
@@ -42109,7 +42400,7 @@ var simulate_default = defineCommand({
42109
42400
  state: strategyState
42110
42401
  } : undefined
42111
42402
  });
42112
- await writeTextFile(stateOutPath, `${JSON.stringify(serialized, null, 2)}
42403
+ await writeTextFile(await assertOutputNotInput(stateOutPath, { allowFlags: ["resume"] }), `${JSON.stringify(serialized, null, 2)}
42113
42404
  `);
42114
42405
  }
42115
42406
  const offlineSummary = buildOfflineSummary(offlineRun);
@@ -42354,6 +42645,13 @@ function readBestScoreFromArtifact(x) {
42354
42645
  }
42355
42646
  return score;
42356
42647
  }
42648
+ function readEngineFromArtifact(x) {
42649
+ const recorded = x?.meta?.effectiveEngine;
42650
+ if (typeof recorded === "string" && recorded.trim())
42651
+ return recorded.trim();
42652
+ const requested = x?.input?.flags?.engine;
42653
+ return typeof requested === "string" && requested.trim() ? requested.trim() : "number";
42654
+ }
42357
42655
  function buildTuneInsights(outputBase) {
42358
42656
  const report = outputBase.report;
42359
42657
  const bestScore = readBestScoreFromTuneResult(outputBase);
@@ -42505,6 +42803,14 @@ var tune_default = defineCommand({
42505
42803
  const baselinePath = flags["baseline-artifact"] ? resolve21(flags["baseline-artifact"]) : undefined;
42506
42804
  const baselineRaw = baselinePath ? await readJsonFile(baselinePath) : undefined;
42507
42805
  const engine = resolveEffectiveEngine({ requested: flags.engine });
42806
+ if (baselineRaw !== undefined) {
42807
+ const baselineEngine = readEngineFromArtifact(baselineRaw);
42808
+ if (baselineEngine !== engine.effectiveId) {
42809
+ throw cliError("CLI_USAGE", `Baseline artifact engine mismatch: expected ${engine.effectiveId}, got ${baselineEngine}`, {
42810
+ hint: `Pass --engine ${baselineEngine} to compare against this baseline, or record a new baseline with --engine ${engine.effectiveId}.`
42811
+ });
42812
+ }
42813
+ }
42508
42814
  const engineIdentity = engine.effectiveId === "number" ? {} : { engineId: engine.effectiveId };
42509
42815
  const seed = flags.seed ?? deriveDeterministicSeed({
42510
42816
  command: "tune",
@@ -42528,7 +42834,8 @@ var tune_default = defineCommand({
42528
42834
  tuneSpec: tuneSpecInput,
42529
42835
  runId,
42530
42836
  seed,
42531
- pluginDigest: loaded.pluginDigest
42837
+ pluginDigest: loaded.pluginDigest,
42838
+ effectiveEngine: engine.effectiveId
42532
42839
  });
42533
42840
  const result = await cmdTune({
42534
42841
  E: engine.engine,
@@ -43920,7 +44227,6 @@ init_zod();
43920
44227
  // src/commands/_shared/listOutput.ts
43921
44228
  init_outputMeta();
43922
44229
  init_bun();
43923
- import { resolve as resolve25 } from "path";
43924
44230
  async function writeListOutput(args) {
43925
44231
  const outputForRender = args.format === "json" ? {
43926
44232
  ...args.payload,
@@ -43931,7 +44237,7 @@ async function writeListOutput(args) {
43931
44237
  process.stdout.write(body);
43932
44238
  return;
43933
44239
  }
43934
- const path = resolve25(args.out);
44240
+ const path = await assertOutputNotInput(args.out);
43935
44241
  await writeTextFile(path, body);
43936
44242
  console.log(`Wrote ${args.format} output to ${path}`);
43937
44243
  }
@@ -44080,8 +44386,9 @@ var objectives_default2 = defineGroup({
44080
44386
  init_zod();
44081
44387
  init_errors3();
44082
44388
  init_outputMeta();
44083
- import { resolve as resolve26 } from "path";
44389
+ import { resolve as resolve25 } from "path";
44084
44390
  init_bun();
44391
+ init_invocation();
44085
44392
  init_selfCli();
44086
44393
  function deepEqual(a, b) {
44087
44394
  return stableStringify(a) === stableStringify(b);
@@ -44101,6 +44408,7 @@ function parseArtifact(input) {
44101
44408
  flags: record(string2(), unknown())
44102
44409
  }),
44103
44410
  replay: object({
44411
+ cwd: string2().optional(),
44104
44412
  args: array(string2()).min(1),
44105
44413
  commandLine: string2(),
44106
44414
  verify: object({
@@ -44147,13 +44455,15 @@ var replayVerify_default = defineCommand({
44147
44455
  if (!artifactPath) {
44148
44456
  throw usageError("Usage: idk replay verify <artifact.json>");
44149
44457
  }
44150
- const artifactAbs = resolve26(process.cwd(), artifactPath);
44458
+ const artifactAbs = resolve25(process.cwd(), artifactPath);
44151
44459
  const raw = await readJsonFile(artifactAbs).catch((error) => {
44152
44460
  if (error instanceof Error && error.name === "CliError")
44153
44461
  throw error;
44154
44462
  throw replayArtifactInvalidError("Invalid replay artifact.", errorDetail(error), error);
44155
44463
  });
44156
44464
  const artifact = parseArtifact(raw);
44465
+ const recordedCwd = artifact.replay.cwd || process.cwd();
44466
+ recordNestedInputs(recordedCwd, artifact.input.positional, artifact.input.flags);
44157
44467
  const requiredChecks = {
44158
44468
  runId: typeof artifact.replay.verify.runId === "string" && artifact.replay.verify.runId.length > 0,
44159
44469
  seed: typeof artifact.replay.verify.seed === "number" && Number.isFinite(artifact.replay.verify.seed),
@@ -44169,6 +44479,15 @@ var replayVerify_default = defineCommand({
44169
44479
  const expectedHash = artifact.replay.verify.resultHash ?? hashReplayResult(expectedCanonical);
44170
44480
  const actualHash = hashReplayResult(actualCanonical);
44171
44481
  const replayMeta = replayOutput && typeof replayOutput === "object" && !Array.isArray(replayOutput) ? replayOutput._meta : undefined;
44482
+ const replayScenarios = replayMeta?.scenarioPath;
44483
+ const replayPlugins = replayMeta?.pluginDigest;
44484
+ const pluginEntries = replayPlugins && typeof replayPlugins === "object" ? Object.keys(replayPlugins) : [];
44485
+ recordNestedInputs(cliPackageRoot(), [
44486
+ ...typeof replayScenarios === "string" ? [replayScenarios] : Array.isArray(replayScenarios) ? replayScenarios.filter((path) => typeof path === "string") : [],
44487
+ ...pluginEntries
44488
+ ], {});
44489
+ for (const entry of pluginEntries)
44490
+ await recordPluginClosureReads(resolve25(cliPackageRoot(), entry));
44172
44491
  const semanticChecks = {
44173
44492
  runId: replayMeta && typeof replayMeta.runId === "string" && replayMeta.runId === artifact.replay.verify.runId,
44174
44493
  seed: replayMeta && typeof replayMeta.seed === "number" && replayMeta.seed === artifact.replay.verify.seed,
@@ -44448,4 +44767,4 @@ export {
44448
44767
  cli2 as cli
44449
44768
  };
44450
44769
 
44451
- //# debugId=0936659FB5366DD764756E2164756E21
44770
+ //# debugId=75B3E1ECDA8A1B6D64756E2164756E21