@idlekit/cli 0.5.1 → 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/README.md +25 -0
- package/dist/main.js +1220 -639
- package/dist/main.js.map +49 -42
- package/dist/runtime/workers/entry.js +758 -269
- package/dist/runtime/workers/entry.js.map +25 -19
- package/package.json +2 -2
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.
|
|
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.
|
|
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?.({
|
|
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
|
-
|
|
10935
|
-
|
|
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;
|
|
@@ -11605,6 +11680,63 @@ function logicalDrawId(drawIndex) {
|
|
|
11605
11680
|
return String(drawIndex);
|
|
11606
11681
|
}
|
|
11607
11682
|
|
|
11683
|
+
// ../core/dist/sim/sessionOffline.js
|
|
11684
|
+
function validateCreditPolicy(policy) {
|
|
11685
|
+
if (!policy || typeof policy !== "object" || Array.isArray(policy) || "actions" in policy) {
|
|
11686
|
+
throw new RangeError("prepareOffline policy must be a credit policy; set actions on scenario.run.offline");
|
|
11687
|
+
}
|
|
11688
|
+
if (policy.maxSec !== undefined && (typeof policy.maxSec !== "number" || !Number.isFinite(policy.maxSec) || policy.maxSec < 0)) {
|
|
11689
|
+
throw new RangeError("prepareOffline policy.maxSec must be finite and nonnegative");
|
|
11690
|
+
}
|
|
11691
|
+
if (policy.overflowPolicy !== undefined && policy.overflowPolicy !== "clamp" && policy.overflowPolicy !== "reject") {
|
|
11692
|
+
throw new RangeError("prepareOffline policy.overflowPolicy must be clamp or reject");
|
|
11693
|
+
}
|
|
11694
|
+
const decay = policy.decay;
|
|
11695
|
+
if (decay !== undefined) {
|
|
11696
|
+
if (!decay || typeof decay !== "object" || Array.isArray(decay) || decay.kind !== "none" && decay.kind !== "linear") {
|
|
11697
|
+
throw new RangeError("prepareOffline policy.decay must select none or linear");
|
|
11698
|
+
}
|
|
11699
|
+
if (decay.floorRatio !== undefined && (typeof decay.floorRatio !== "number" || !Number.isFinite(decay.floorRatio) || decay.floorRatio < 0 || decay.floorRatio > 1)) {
|
|
11700
|
+
throw new RangeError("prepareOffline policy.decay.floorRatio must be finite and in 0..1");
|
|
11701
|
+
}
|
|
11702
|
+
}
|
|
11703
|
+
}
|
|
11704
|
+
function prepareOfflineSegment(args) {
|
|
11705
|
+
const { scenario, prepare } = args;
|
|
11706
|
+
if (!prepare)
|
|
11707
|
+
return { model: scenario.model, policy: scenario.run.offline, stepSec: scenario.run.stepSec };
|
|
11708
|
+
const prepared = prepare({
|
|
11709
|
+
ctx: scenario.ctx,
|
|
11710
|
+
model: scenario.model,
|
|
11711
|
+
state: deepClonePreservingPrototype(args.state),
|
|
11712
|
+
seconds: args.seconds,
|
|
11713
|
+
wallStartT: args.wallStartT,
|
|
11714
|
+
wallEndT: args.wallEndT,
|
|
11715
|
+
...scenario.run.offline ? { policy: deepClonePreservingPrototype(scenario.run.offline) } : {}
|
|
11716
|
+
});
|
|
11717
|
+
if (!prepared || typeof prepared !== "object" || Array.isArray(prepared) || "then" in prepared) {
|
|
11718
|
+
throw new RangeError("prepareOffline must synchronously return a preparation object");
|
|
11719
|
+
}
|
|
11720
|
+
if (prepared.stepSec !== undefined && (typeof prepared.stepSec !== "number" || !Number.isFinite(prepared.stepSec) || prepared.stepSec <= 0)) {
|
|
11721
|
+
throw new RangeError("prepareOffline stepSec must be finite and positive");
|
|
11722
|
+
}
|
|
11723
|
+
if (prepared.policy !== undefined)
|
|
11724
|
+
validateCreditPolicy(prepared.policy);
|
|
11725
|
+
const model = prepared.model === undefined ? scenario.model : prepared.model;
|
|
11726
|
+
if (!model || typeof model !== "object" || typeof model.income !== "function" || typeof model.actions !== "function") {
|
|
11727
|
+
throw new RangeError("prepareOffline model must provide income and actions");
|
|
11728
|
+
}
|
|
11729
|
+
return {
|
|
11730
|
+
model,
|
|
11731
|
+
stepSec: prepared.stepSec ?? scenario.run.stepSec,
|
|
11732
|
+
policy: prepared.policy === undefined ? scenario.run.offline : {
|
|
11733
|
+
...deepClonePreservingPrototype(prepared.policy),
|
|
11734
|
+
actions: scenario.run.offline?.actions
|
|
11735
|
+
}
|
|
11736
|
+
};
|
|
11737
|
+
}
|
|
11738
|
+
var init_sessionOffline = () => {};
|
|
11739
|
+
|
|
11608
11740
|
// ../core/dist/sim/session.js
|
|
11609
11741
|
function buildBlocks(pattern) {
|
|
11610
11742
|
const blocks = [];
|
|
@@ -11700,6 +11832,9 @@ function withClocks(scenario, wallT, wallEndT, rewardT, activeT) {
|
|
|
11700
11832
|
};
|
|
11701
11833
|
}
|
|
11702
11834
|
function simulateSessionPattern(args) {
|
|
11835
|
+
if (args.prepareOffline !== undefined && typeof args.prepareOffline !== "function") {
|
|
11836
|
+
throw new TypeError("prepareOffline must be a function");
|
|
11837
|
+
}
|
|
11703
11838
|
const sc = args.seed === undefined ? args.scenario : { ...args.scenario, ctx: { ...args.scenario.ctx, seed: args.seed } };
|
|
11704
11839
|
const start = sc.initial;
|
|
11705
11840
|
const horizonSec = args.pattern.days * 86400;
|
|
@@ -11786,7 +11921,19 @@ function simulateSessionPattern(args) {
|
|
|
11786
11921
|
return;
|
|
11787
11922
|
const requested = wallEnd - wallT;
|
|
11788
11923
|
const wallStart = wallT;
|
|
11789
|
-
|
|
11924
|
+
let segment = segmentScenario(wallStart, wallEnd);
|
|
11925
|
+
const prepared = prepareOfflineSegment({
|
|
11926
|
+
scenario: segment,
|
|
11927
|
+
state,
|
|
11928
|
+
seconds: requested,
|
|
11929
|
+
wallStartT: wallStart,
|
|
11930
|
+
wallEndT: wallEnd,
|
|
11931
|
+
prepare: args.prepareOffline
|
|
11932
|
+
});
|
|
11933
|
+
if (prepared.model !== segment.model) {
|
|
11934
|
+
const { clocks: _clocks, ...ctx } = segment.ctx;
|
|
11935
|
+
segment = withClocks({ ...segment, ctx, model: prepared.model }, wallStart, wallEnd, state.t, activeSec);
|
|
11936
|
+
}
|
|
11790
11937
|
const offlineRun = applyOfflineSeconds({
|
|
11791
11938
|
scenario: segment,
|
|
11792
11939
|
seconds: requested,
|
|
@@ -11798,15 +11945,16 @@ function simulateSessionPattern(args) {
|
|
|
11798
11945
|
enabled: sc.run.eventLog?.enabled ?? true,
|
|
11799
11946
|
maxEvents: sc.run.eventLog?.maxEvents
|
|
11800
11947
|
},
|
|
11801
|
-
|
|
11948
|
+
stepSec: prepared.stepSec,
|
|
11949
|
+
policy: prepared.policy,
|
|
11802
11950
|
...stopFn ? { until: stopFn } : {}
|
|
11803
11951
|
}
|
|
11804
11952
|
});
|
|
11805
11953
|
const credited = offlineRun.offline.simulatedSec;
|
|
11806
11954
|
const reason = classify();
|
|
11807
|
-
const absence = reason ? offlineAbsenceForCredit(credited, requested,
|
|
11955
|
+
const absence = reason ? offlineAbsenceForCredit(credited, requested, prepared.policy) : requested;
|
|
11808
11956
|
const gapEnd = wallStart + absence;
|
|
11809
|
-
const effective = absence === requested ? offlineRun.offline.effectiveSec : resolveOfflineSeconds(absence,
|
|
11957
|
+
const effective = absence === requested ? offlineRun.offline.effectiveSec : resolveOfflineSeconds(absence, prepared.policy).effectiveSec;
|
|
11810
11958
|
const lost = Math.max(0, absence - effective);
|
|
11811
11959
|
offlineElapsedSec += absence;
|
|
11812
11960
|
offlineCreditedSec += credited;
|
|
@@ -11977,6 +12125,7 @@ var init_session = __esm(() => {
|
|
|
11977
12125
|
init_goalRead();
|
|
11978
12126
|
init_observation();
|
|
11979
12127
|
init_offline();
|
|
12128
|
+
init_sessionOffline();
|
|
11980
12129
|
init_simulator();
|
|
11981
12130
|
});
|
|
11982
12131
|
|
|
@@ -12972,11 +13121,20 @@ var init_params2 = __esm(() => {
|
|
|
12972
13121
|
}));
|
|
12973
13122
|
});
|
|
12974
13123
|
|
|
12975
|
-
// ../core/dist/sim/strategy/opt/
|
|
12976
|
-
function
|
|
12977
|
-
|
|
12978
|
-
|
|
13124
|
+
// ../core/dist/sim/strategy/opt/finiteAmountLog10.js
|
|
13125
|
+
function finiteAmountLog10(E, amount) {
|
|
13126
|
+
if (!E.isFinite(amount))
|
|
13127
|
+
throw new RangeError("Tuning requires finite monetary amounts in the selected engine");
|
|
13128
|
+
const value = E.absLog10(amount);
|
|
13129
|
+
if (value === Number.NEGATIVE_INFINITY)
|
|
13130
|
+
return ZERO_AMOUNT_LOG10_FLOOR;
|
|
13131
|
+
if (!Number.isFinite(value))
|
|
13132
|
+
throw new RangeError("Tuning requires a finite monetary logarithm");
|
|
13133
|
+
return Math.max(ZERO_AMOUNT_LOG10_FLOOR, value);
|
|
12979
13134
|
}
|
|
13135
|
+
var ZERO_AMOUNT_LOG10_FLOOR = -300;
|
|
13136
|
+
|
|
13137
|
+
// ../core/dist/sim/strategy/opt/objectives/builtins.js
|
|
12980
13138
|
var builtinObjectiveFactories;
|
|
12981
13139
|
var init_builtins2 = __esm(() => {
|
|
12982
13140
|
init_parseMoney2();
|
|
@@ -12990,7 +13148,7 @@ var init_builtins2 = __esm(() => {
|
|
|
12990
13148
|
id: "endMoneyLog10",
|
|
12991
13149
|
score: ({ scenario, run }) => {
|
|
12992
13150
|
const { E } = scenario.ctx;
|
|
12993
|
-
return
|
|
13151
|
+
return finiteAmountLog10(E, run.end.wallet.money.amount);
|
|
12994
13152
|
}
|
|
12995
13153
|
})
|
|
12996
13154
|
},
|
|
@@ -13003,7 +13161,7 @@ var init_builtins2 = __esm(() => {
|
|
|
13003
13161
|
score: ({ scenario, run }) => {
|
|
13004
13162
|
const { E } = scenario.ctx;
|
|
13005
13163
|
const worth = scenario.model.netWorth?.(scenario.ctx, run.end) ?? run.end.wallet.money;
|
|
13006
|
-
return
|
|
13164
|
+
return finiteAmountLog10(E, worth.amount);
|
|
13007
13165
|
}
|
|
13008
13166
|
})
|
|
13009
13167
|
},
|
|
@@ -13018,7 +13176,7 @@ var init_builtins2 = __esm(() => {
|
|
|
13018
13176
|
const sec = Math.max(1, runElapsedSec(run));
|
|
13019
13177
|
const hours = sec / 3600;
|
|
13020
13178
|
const worth = scenario.model.netWorth?.(scenario.ctx, run.end) ?? run.end.wallet.money;
|
|
13021
|
-
return
|
|
13179
|
+
return finiteAmountLog10(E, worth.amount) - Math.log10(Math.max(0.000000000001, hours));
|
|
13022
13180
|
}
|
|
13023
13181
|
})
|
|
13024
13182
|
},
|
|
@@ -13032,7 +13190,7 @@ var init_builtins2 = __esm(() => {
|
|
|
13032
13190
|
const { E } = scenario.ctx;
|
|
13033
13191
|
const sec = Math.max(1, runElapsedSec(run));
|
|
13034
13192
|
const hours = sec / 3600;
|
|
13035
|
-
return
|
|
13193
|
+
return finiteAmountLog10(E, run.end.prestige.points) - Math.log10(Math.max(0.000000000001, hours));
|
|
13036
13194
|
}
|
|
13037
13195
|
})
|
|
13038
13196
|
},
|
|
@@ -13047,7 +13205,7 @@ var init_builtins2 = __esm(() => {
|
|
|
13047
13205
|
const sec = Math.max(1, runElapsedSec(run));
|
|
13048
13206
|
const startWorth = scenario.model.netWorth?.(scenario.ctx, run.start) ?? run.start.wallet.money;
|
|
13049
13207
|
const endWorth = scenario.model.netWorth?.(scenario.ctx, run.end) ?? run.end.wallet.money;
|
|
13050
|
-
const deltaLog =
|
|
13208
|
+
const deltaLog = finiteAmountLog10(E, endWorth.amount) - finiteAmountLog10(E, startWorth.amount);
|
|
13051
13209
|
return deltaLog / (sec / 3600);
|
|
13052
13210
|
}
|
|
13053
13211
|
})
|
|
@@ -13073,6 +13231,9 @@ var init_builtins2 = __esm(() => {
|
|
|
13073
13231
|
suffix: { kind: "alphaInfinite", minLen: 2 }
|
|
13074
13232
|
}).amount;
|
|
13075
13233
|
const endWorth = scenario.model.netWorth?.(scenario.ctx, run.end) ?? run.end.wallet.money;
|
|
13234
|
+
if (!E.isFinite(threshold) || !E.isFinite(endWorth.amount)) {
|
|
13235
|
+
throw new RangeError("ETA objective requires finite target and net worth in the selected engine");
|
|
13236
|
+
}
|
|
13076
13237
|
const reached = E.cmp(endWorth.amount, threshold) >= 0;
|
|
13077
13238
|
if (!reached)
|
|
13078
13239
|
return -(params.unreachedPenaltySec ?? 1e9);
|
|
@@ -13102,7 +13263,7 @@ var init_builtins2 = __esm(() => {
|
|
|
13102
13263
|
const sec = Math.max(1, runElapsedSec(run));
|
|
13103
13264
|
const hours = sec / 3600;
|
|
13104
13265
|
const worth = scenario.model.netWorth?.(scenario.ctx, run.end) ?? run.end.wallet.money;
|
|
13105
|
-
const worthLog =
|
|
13266
|
+
const worthLog = finiteAmountLog10(E, worth.amount);
|
|
13106
13267
|
const stats = run.stats;
|
|
13107
13268
|
if (!stats || stats.money.droppedRate === null || stats.actions.status === "missing") {
|
|
13108
13269
|
throw new Error("pacingBalancedLog10 needs observed money and action counters, but this run has none (run.observation.enabled is false)");
|
|
@@ -13301,8 +13462,45 @@ function cloneCandidateInitial(state) {
|
|
|
13301
13462
|
}
|
|
13302
13463
|
var init_freshRun = () => {};
|
|
13303
13464
|
|
|
13465
|
+
// ../core/dist/sim/strategy/opt/finiteMean.js
|
|
13466
|
+
function finiteMean(values) {
|
|
13467
|
+
if (values.length === 0)
|
|
13468
|
+
throw new RangeError("A mean requires at least one value");
|
|
13469
|
+
const bits = new DataView(new ArrayBuffer(8));
|
|
13470
|
+
let total = 0n;
|
|
13471
|
+
for (const value of values) {
|
|
13472
|
+
if (!Number.isFinite(value))
|
|
13473
|
+
throw new RangeError("A mean requires finite values");
|
|
13474
|
+
bits.setFloat64(0, value, false);
|
|
13475
|
+
const high = bits.getUint32(0, false);
|
|
13476
|
+
const low = bits.getUint32(4, false);
|
|
13477
|
+
const exponent = high >>> 20 & 2047;
|
|
13478
|
+
const fraction = BigInt(high & 1048575) << 32n | BigInt(low);
|
|
13479
|
+
const significand = exponent === 0 ? fraction : 1n << 52n | fraction;
|
|
13480
|
+
const units = significand << BigInt(Math.max(0, exponent - 1));
|
|
13481
|
+
total += high >>> 31 ? -units : units;
|
|
13482
|
+
}
|
|
13483
|
+
if (total === 0n)
|
|
13484
|
+
return 0;
|
|
13485
|
+
const negative = total < 0n;
|
|
13486
|
+
const magnitude = negative ? -total : total;
|
|
13487
|
+
const count = BigInt(values.length);
|
|
13488
|
+
const integerMean = magnitude / count;
|
|
13489
|
+
const shift = Math.max(0, integerMean.toString(2).length - 53);
|
|
13490
|
+
const denominator = count << BigInt(shift);
|
|
13491
|
+
let significand = magnitude / denominator;
|
|
13492
|
+
const twiceRemainder = 2n * (magnitude % denominator);
|
|
13493
|
+
if (twiceRemainder > denominator || twiceRemainder === denominator && (significand & 1n) !== 0n) {
|
|
13494
|
+
significand++;
|
|
13495
|
+
}
|
|
13496
|
+
const mean = Number(significand) * 2 ** (shift - 1074);
|
|
13497
|
+
return negative ? -mean : mean;
|
|
13498
|
+
}
|
|
13499
|
+
|
|
13304
13500
|
// ../core/dist/sim/strategy/opt/runner.js
|
|
13305
13501
|
function runCandidateAndScore(args) {
|
|
13502
|
+
if (args.seeds.length === 0)
|
|
13503
|
+
throw new RangeError("Tuning requires at least one seed");
|
|
13306
13504
|
const stratFactory = args.strategyRegistry.get(args.strategyId);
|
|
13307
13505
|
if (!stratFactory)
|
|
13308
13506
|
throw new Error(`Unknown strategy: ${args.strategyId}`);
|
|
@@ -13349,24 +13547,28 @@ function runCandidateAndScore(args) {
|
|
|
13349
13547
|
const sc = openScenario();
|
|
13350
13548
|
const run = runScenario(sc);
|
|
13351
13549
|
assertHorizonReached(run, "runCandidateAndScore");
|
|
13550
|
+
const worth = sc.model.netWorth?.(sc.ctx, run.end) ?? run.end.wallet.money;
|
|
13551
|
+
const endMoneyLog10 = finiteAmountLog10(sc.ctx.E, run.end.wallet.money.amount);
|
|
13552
|
+
const endNetWorthLog10 = finiteAmountLog10(sc.ctx.E, worth.amount);
|
|
13352
13553
|
const s = objective.score({ scenario: sc, run, evaluation: {
|
|
13353
13554
|
open: openScenario,
|
|
13354
13555
|
registries: { models: args.modelRegistry, strategies: args.strategyRegistry },
|
|
13355
13556
|
isolation: { model: args.model, statefulModel: args.statefulModel, strategy: { id: args.strategyId, params: candidateParams } }
|
|
13356
13557
|
} });
|
|
13558
|
+
if (!Number.isFinite(s))
|
|
13559
|
+
throw new RangeError(`Objective ${args.objectiveId} must return a finite score (seed ${seed})`);
|
|
13357
13560
|
seedScores.push(s);
|
|
13358
|
-
const worth = sc.model.netWorth?.(sc.ctx, run.end) ?? run.end.wallet.money;
|
|
13359
13561
|
seedResults.push({
|
|
13360
13562
|
seed,
|
|
13361
13563
|
score: s,
|
|
13362
13564
|
durationSec: Math.max(0, runElapsedSec(run)),
|
|
13363
|
-
endMoneyLog10
|
|
13364
|
-
endNetWorthLog10
|
|
13565
|
+
endMoneyLog10,
|
|
13566
|
+
endNetWorthLog10,
|
|
13365
13567
|
droppedRate: run.stats?.money.droppedRate ?? null,
|
|
13366
13568
|
actionsApplied: run.stats && run.stats.actions.status === "observed" ? run.stats.actions.applied : null
|
|
13367
13569
|
});
|
|
13368
13570
|
}
|
|
13369
|
-
const score =
|
|
13571
|
+
const score = finiteMean(seedScores);
|
|
13370
13572
|
return { score, seedScores, seedResults };
|
|
13371
13573
|
}
|
|
13372
13574
|
var init_runner = __esm(() => {
|
|
@@ -14353,7 +14555,7 @@ function compensatedSum(values, scale) {
|
|
|
14353
14555
|
}
|
|
14354
14556
|
return sum + compensation;
|
|
14355
14557
|
}
|
|
14356
|
-
function
|
|
14558
|
+
function finiteMean2(values) {
|
|
14357
14559
|
let smallest = Number.POSITIVE_INFINITY;
|
|
14358
14560
|
let largest = Number.NEGATIVE_INFINITY;
|
|
14359
14561
|
for (const value of values) {
|
|
@@ -14503,7 +14705,7 @@ function analyzeDistribution(request) {
|
|
|
14503
14705
|
}
|
|
14504
14706
|
const eligible = observed.length + rightCensored;
|
|
14505
14707
|
const completionRate = eligible > 0 ? observed.length / eligible : null;
|
|
14506
|
-
const arithmetic = observed.length > 0 ?
|
|
14708
|
+
const arithmetic = observed.length > 0 ? finiteMean2(observed) : null;
|
|
14507
14709
|
const identical = observed.every((value) => value === observed[0]);
|
|
14508
14710
|
const rawVariance = arithmetic === null ? null : finiteVariance(observed, arithmetic);
|
|
14509
14711
|
const variance = rawVariance === 0 && !identical ? null : rawVariance;
|
|
@@ -15038,15 +15240,16 @@ function readBenefit(vars) {
|
|
|
15038
15240
|
const value = vars.benefit;
|
|
15039
15241
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
15040
15242
|
}
|
|
15041
|
-
function observeMetrics(E, spec, end,
|
|
15243
|
+
function observeMetrics(E, spec, end, moneyElapsedSec, milestoneElapsedSec, elapsedSec) {
|
|
15042
15244
|
const amount = end.wallet.money.amount;
|
|
15043
15245
|
const benefit = readBenefit(end.vars);
|
|
15044
15246
|
return metricIds(spec).map((metricId) => {
|
|
15045
|
-
if (metricId === "timeToMoney") {
|
|
15046
|
-
|
|
15047
|
-
|
|
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 } };
|
|
15048
15252
|
}
|
|
15049
|
-
const elapsed = reachedAt - startT;
|
|
15050
15253
|
return { metricId, status: "observed", value: String(elapsed), num: elapsed };
|
|
15051
15254
|
}
|
|
15052
15255
|
if (metricId === "endMoney") {
|
|
@@ -15069,7 +15272,7 @@ function aggregate(E, rows, metricId) {
|
|
|
15069
15272
|
}
|
|
15070
15273
|
if (picked.some((metric) => metric.status !== "observed" || metric.value === null)) {
|
|
15071
15274
|
const bounded = picked.every((metric) => metric.num !== undefined || metric.lowerBound !== undefined);
|
|
15072
|
-
if (metricId !== "timeToMoney" || !bounded)
|
|
15275
|
+
if (metricId !== "timeToMoney" && metricId !== "timeToMilestone" || !bounded)
|
|
15073
15276
|
return { metricId, status: "censored", value: null };
|
|
15074
15277
|
const bounds = picked.map((metric) => metric.num ?? metric.lowerBound.sec);
|
|
15075
15278
|
const total = bounds.reduce((sum, bound) => sum + bound, 0);
|
|
@@ -15156,6 +15359,10 @@ function prepareExperiment(request) {
|
|
|
15156
15359
|
reject("goal target must be finite");
|
|
15157
15360
|
if (metrics.includes("timeToMoney") && spec.goal === undefined)
|
|
15158
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");
|
|
15159
15366
|
if (!isJsonData(request.spec, new Set, true))
|
|
15160
15367
|
reject("spec must be JSON data, because the spec hashes record it as JSON");
|
|
15161
15368
|
requireScenarioData(request.scenario);
|
|
@@ -15182,7 +15389,8 @@ function checkExperimentSpec(request) {
|
|
|
15182
15389
|
}
|
|
15183
15390
|
function runExperiment(request) {
|
|
15184
15391
|
const { spec, metrics, base, prepared, specHashes } = prepareExperiment(request);
|
|
15185
|
-
const
|
|
15392
|
+
const measuresMoney = metrics.includes("timeToMoney");
|
|
15393
|
+
const measuresMilestone = metrics.includes("timeToMilestone");
|
|
15186
15394
|
const E = request.engine;
|
|
15187
15395
|
const { strategy: _scenarioStrategy, ...withoutStrategy } = request.scenario;
|
|
15188
15396
|
const compiled = compileScenario({
|
|
@@ -15201,7 +15409,7 @@ function runExperiment(request) {
|
|
|
15201
15409
|
models: request.modelRegistry,
|
|
15202
15410
|
strategies: request.strategyRegistry
|
|
15203
15411
|
});
|
|
15204
|
-
const target =
|
|
15412
|
+
const target = measuresMoney && spec.goal !== undefined ? E.from(spec.goal.target) : undefined;
|
|
15205
15413
|
const stopAtReach = metrics.every((metricId) => metricId === "timeToMoney");
|
|
15206
15414
|
const tasks = [];
|
|
15207
15415
|
const perCandidate = [];
|
|
@@ -15226,21 +15434,41 @@ function runExperiment(request) {
|
|
|
15226
15434
|
try {
|
|
15227
15435
|
const opened = binding.fresh({ trialId: taskId, seed, plan });
|
|
15228
15436
|
const scenario = opened.scenario;
|
|
15229
|
-
let
|
|
15437
|
+
let moneyElapsedSec;
|
|
15438
|
+
let milestoneElapsedSec;
|
|
15439
|
+
let observedElapsedSec = 0;
|
|
15440
|
+
let stepStartElapsedSec = 0;
|
|
15230
15441
|
const result = runScenario({
|
|
15231
15442
|
...scenario,
|
|
15232
15443
|
run: {
|
|
15233
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
|
+
} : {},
|
|
15234
15462
|
...target !== undefined ? {
|
|
15235
15463
|
until: (state) => {
|
|
15236
|
-
if (
|
|
15237
|
-
|
|
15238
|
-
return stopAtReach &&
|
|
15464
|
+
if (moneyElapsedSec === undefined && E.cmp(state.wallet.money.amount, target) >= 0)
|
|
15465
|
+
moneyElapsedSec = observedElapsedSec;
|
|
15466
|
+
return stopAtReach && moneyElapsedSec !== undefined;
|
|
15239
15467
|
}
|
|
15240
15468
|
} : {}
|
|
15241
15469
|
}
|
|
15242
15470
|
});
|
|
15243
|
-
readings = observeMetrics(E, spec, result.end,
|
|
15471
|
+
readings = observeMetrics(E, spec, result.end, moneyElapsedSec, milestoneElapsedSec, runElapsedSec(result));
|
|
15244
15472
|
} catch {
|
|
15245
15473
|
readings = failedMetrics(spec);
|
|
15246
15474
|
}
|
|
@@ -15328,6 +15556,7 @@ function runExperiment(request) {
|
|
|
15328
15556
|
originalSpecHash: specHashes.original,
|
|
15329
15557
|
effectiveSpecHash: specHashes.effective,
|
|
15330
15558
|
effectiveRunHash: request.effectiveRunHash,
|
|
15559
|
+
...measuresMilestone ? { milestoneKey: spec.milestoneKey } : {},
|
|
15331
15560
|
budget: {
|
|
15332
15561
|
candidates: spec.budget.candidates,
|
|
15333
15562
|
seeds: spec.budget.seeds,
|
|
@@ -15357,30 +15586,31 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15357
15586
|
const _ip8 = (input) => typeof input["originalSpecHash"] === "string";
|
|
15358
15587
|
const _ip9 = (input) => typeof input["effectiveSpecHash"] === "string";
|
|
15359
15588
|
const _ip10 = (input) => typeof input["effectiveRunHash"] === "string";
|
|
15360
|
-
const _ip11 = (input) =>
|
|
15361
|
-
const _ip12 = (input) =>
|
|
15362
|
-
const _ip13 = (input) => Array.isArray(input["
|
|
15363
|
-
const _ip14 = (input) => Array.isArray(input["
|
|
15364
|
-
const _ip15 = (input) =>
|
|
15365
|
-
const _ip16 = (input) =>
|
|
15366
|
-
const _ip17 = (input) =>
|
|
15367
|
-
const _ip18 = (input) => typeof input["
|
|
15368
|
-
const _ip19 = (input) => typeof input["
|
|
15369
|
-
const _ip20 = (input) => typeof input["
|
|
15370
|
-
const _ip21 = (input) => typeof input["
|
|
15371
|
-
const _ip22 = (input) => typeof input["
|
|
15372
|
-
const _ip23 = (input) => typeof input["
|
|
15373
|
-
const _ip24 = (input) =>
|
|
15374
|
-
const _ip25 = (input) => typeof input["
|
|
15375
|
-
const _ip26 = (input) => typeof input["
|
|
15376
|
-
const _ip27 = (input) => typeof input["
|
|
15377
|
-
const _ip28 = (input) => typeof input["
|
|
15378
|
-
const _ip29 = (input) => typeof input["
|
|
15379
|
-
const _ip30 = (input) => typeof input["
|
|
15380
|
-
const _ip31 = (input) =>
|
|
15381
|
-
const _ip32 = (input) => input["
|
|
15382
|
-
const _ip33 = (input) => input["
|
|
15383
|
-
const
|
|
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[]; }>';
|
|
15384
15614
|
const _vp0 = (input, _path, _exceptionable = true) => input["schemaVersion"] === 1 || _report(_exceptionable, {
|
|
15385
15615
|
path: _path + ".schemaVersion",
|
|
15386
15616
|
expected: "1",
|
|
@@ -15440,7 +15670,12 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15440
15670
|
expected: "string",
|
|
15441
15671
|
value: input["effectiveRunHash"]
|
|
15442
15672
|
});
|
|
15443
|
-
const _vp11 = (input, _path, _exceptionable = true) =>
|
|
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, {
|
|
15444
15679
|
path: _path + ".budget",
|
|
15445
15680
|
expected: "Readonly<{ candidates: number; seeds: number; usedCandidates: number; usedSeeds: number; }>",
|
|
15446
15681
|
value: input["budget"]
|
|
@@ -15449,7 +15684,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15449
15684
|
expected: "Readonly<{ candidates: number; seeds: number; usedCandidates: number; usedSeeds: number; }>",
|
|
15450
15685
|
value: input["budget"]
|
|
15451
15686
|
});
|
|
15452
|
-
const
|
|
15687
|
+
const _vp13 = (input, _path, _exceptionable = true) => (Array.isArray(input["tasks"]) || _report(_exceptionable, {
|
|
15453
15688
|
path: _path + ".tasks",
|
|
15454
15689
|
expected: _ve2,
|
|
15455
15690
|
value: input["tasks"]
|
|
@@ -15468,7 +15703,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15468
15703
|
});
|
|
15469
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; }>";
|
|
15470
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; }>>";
|
|
15471
|
-
const
|
|
15706
|
+
const _vp14 = (input, _path, _exceptionable = true) => (Array.isArray(input["candidates"]) || _report(_exceptionable, {
|
|
15472
15707
|
path: _path + ".candidates",
|
|
15473
15708
|
expected: _ve4,
|
|
15474
15709
|
value: input["candidates"]
|
|
@@ -15487,7 +15722,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15487
15722
|
});
|
|
15488
15723
|
const _ve3 = "Readonly<{ id: string; metrics: readonly Readonly<{ metricId: ExperimentMetricId; status: ExperimentMetricStatus; value: string | null; }>[]; constraintViolations: readonly string[]; }>";
|
|
15489
15724
|
const _ve4 = "ReadonlyArray<Readonly<{ id: string; metrics: readonly Readonly<{ metricId: ExperimentMetricId; status: ExperimentMetricStatus; value: string | null; }>[]; constraintViolations: readonly string[]; }>>";
|
|
15490
|
-
const
|
|
15725
|
+
const _vp15 = (input, _path, _exceptionable = true) => (Array.isArray(input["elasticities"]) || _report(_exceptionable, {
|
|
15491
15726
|
path: _path + ".elasticities",
|
|
15492
15727
|
expected: _ve6,
|
|
15493
15728
|
value: input["elasticities"]
|
|
@@ -15506,7 +15741,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15506
15741
|
});
|
|
15507
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";...';
|
|
15508
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";...>';
|
|
15509
|
-
const
|
|
15744
|
+
const _vp16 = (input, _path, _exceptionable = true) => (typeof input["pareto"] === "object" && input["pareto"] !== null || _report(_exceptionable, {
|
|
15510
15745
|
path: _path + ".pareto",
|
|
15511
15746
|
expected: 'Readonly<{ sense: "per-metric"; nonDominated: readonly string[]; uncompared: readonly string[]; }>',
|
|
15512
15747
|
value: input["pareto"]
|
|
@@ -15515,7 +15750,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15515
15750
|
expected: 'Readonly<{ sense: "per-metric"; nonDominated: readonly string[]; uncompared: readonly string[]; }>',
|
|
15516
15751
|
value: input["pareto"]
|
|
15517
15752
|
});
|
|
15518
|
-
const
|
|
15753
|
+
const _vp17 = (input, _path, _exceptionable = true) => (Array.isArray(input["warnings"]) || _report(_exceptionable, {
|
|
15519
15754
|
path: _path + ".warnings",
|
|
15520
15755
|
expected: "ReadonlyArray<string>",
|
|
15521
15756
|
value: input["warnings"]
|
|
@@ -15528,100 +15763,100 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15528
15763
|
expected: "ReadonlyArray<string>",
|
|
15529
15764
|
value: input["warnings"]
|
|
15530
15765
|
});
|
|
15531
|
-
const
|
|
15766
|
+
const _vp18 = (input, _path, _exceptionable = true) => typeof input["taskId"] === "string" || _report(_exceptionable, {
|
|
15532
15767
|
path: _path + ".taskId",
|
|
15533
15768
|
expected: "string",
|
|
15534
15769
|
value: input["taskId"]
|
|
15535
15770
|
});
|
|
15536
|
-
const
|
|
15771
|
+
const _vp19 = (input, _path, _exceptionable = true) => typeof input["candidateId"] === "string" || _report(_exceptionable, {
|
|
15537
15772
|
path: _path + ".candidateId",
|
|
15538
15773
|
expected: "string",
|
|
15539
15774
|
value: input["candidateId"]
|
|
15540
15775
|
});
|
|
15541
|
-
const
|
|
15776
|
+
const _vp20 = (input, _path, _exceptionable = true) => typeof input["logicalSeed"] === "number" || _report(_exceptionable, {
|
|
15542
15777
|
path: _path + ".logicalSeed",
|
|
15543
15778
|
expected: "number",
|
|
15544
15779
|
value: input["logicalSeed"]
|
|
15545
15780
|
});
|
|
15546
|
-
const
|
|
15781
|
+
const _vp21 = (input, _path, _exceptionable = true) => typeof input["engineId"] === "string" || _report(_exceptionable, {
|
|
15547
15782
|
path: _path + ".engineId",
|
|
15548
15783
|
expected: "string",
|
|
15549
15784
|
value: input["engineId"]
|
|
15550
15785
|
});
|
|
15551
|
-
const
|
|
15786
|
+
const _vp22 = (input, _path, _exceptionable = true) => typeof input["engineVersion"] === "string" || _report(_exceptionable, {
|
|
15552
15787
|
path: _path + ".engineVersion",
|
|
15553
15788
|
expected: "string",
|
|
15554
15789
|
value: input["engineVersion"]
|
|
15555
15790
|
});
|
|
15556
|
-
const
|
|
15791
|
+
const _vp23 = (input, _path, _exceptionable = true) => typeof input["modelId"] === "string" || _report(_exceptionable, {
|
|
15557
15792
|
path: _path + ".modelId",
|
|
15558
15793
|
expected: "string",
|
|
15559
15794
|
value: input["modelId"]
|
|
15560
15795
|
});
|
|
15561
|
-
const
|
|
15796
|
+
const _vp24 = (input, _path, _exceptionable = true) => typeof input["modelVersion"] === "number" || _report(_exceptionable, {
|
|
15562
15797
|
path: _path + ".modelVersion",
|
|
15563
15798
|
expected: "number",
|
|
15564
15799
|
value: input["modelVersion"]
|
|
15565
15800
|
});
|
|
15566
|
-
const
|
|
15801
|
+
const _vp25 = (input, _path, _exceptionable = true) => input["strategyId"] === null || typeof input["strategyId"] === "string" || _report(_exceptionable, {
|
|
15567
15802
|
path: _path + ".strategyId",
|
|
15568
15803
|
expected: "(null | string)",
|
|
15569
15804
|
value: input["strategyId"]
|
|
15570
15805
|
});
|
|
15571
|
-
const
|
|
15806
|
+
const _vp26 = (input, _path, _exceptionable = true) => typeof input["modelParams"] === "string" || _report(_exceptionable, {
|
|
15572
15807
|
path: _path + ".modelParams",
|
|
15573
15808
|
expected: "string",
|
|
15574
15809
|
value: input["modelParams"]
|
|
15575
15810
|
});
|
|
15576
|
-
const
|
|
15811
|
+
const _vp27 = (input, _path, _exceptionable = true) => typeof input["strategyParams"] === "string" || _report(_exceptionable, {
|
|
15577
15812
|
path: _path + ".strategyParams",
|
|
15578
15813
|
expected: "string",
|
|
15579
15814
|
value: input["strategyParams"]
|
|
15580
15815
|
});
|
|
15581
|
-
const
|
|
15816
|
+
const _vp28 = (input, _path, _exceptionable = true) => typeof input["sessionPattern"] === "string" || _report(_exceptionable, {
|
|
15582
15817
|
path: _path + ".sessionPattern",
|
|
15583
15818
|
expected: "string",
|
|
15584
15819
|
value: input["sessionPattern"]
|
|
15585
15820
|
});
|
|
15586
|
-
const
|
|
15821
|
+
const _vp29 = (input, _path, _exceptionable = true) => typeof input["sessionDays"] === "number" || _report(_exceptionable, {
|
|
15587
15822
|
path: _path + ".sessionDays",
|
|
15588
15823
|
expected: "number",
|
|
15589
15824
|
value: input["sessionDays"]
|
|
15590
15825
|
});
|
|
15591
|
-
const
|
|
15826
|
+
const _vp30 = (input, _path, _exceptionable = true) => typeof input["horizonSec"] === "number" || _report(_exceptionable, {
|
|
15592
15827
|
path: _path + ".horizonSec",
|
|
15593
15828
|
expected: "number",
|
|
15594
15829
|
value: input["horizonSec"]
|
|
15595
15830
|
});
|
|
15596
|
-
const
|
|
15831
|
+
const _vp31 = (input, _path, _exceptionable = true) => typeof input["stepSec"] === "number" || _report(_exceptionable, {
|
|
15597
15832
|
path: _path + ".stepSec",
|
|
15598
15833
|
expected: "number",
|
|
15599
15834
|
value: input["stepSec"]
|
|
15600
15835
|
});
|
|
15601
|
-
const
|
|
15836
|
+
const _vp32 = (input, _path, _exceptionable = true) => input["metricId"] === "endMoney" || input["metricId"] === "timeToMilestone" || input["metricId"] === "timeToMoney" || input["metricId"] === "varBenefit" || _report(_exceptionable, {
|
|
15602
15837
|
path: _path + ".metricId",
|
|
15603
|
-
expected: '("endMoney" | "timeToMoney" | "varBenefit")',
|
|
15838
|
+
expected: '("endMoney" | "timeToMilestone" | "timeToMoney" | "varBenefit")',
|
|
15604
15839
|
value: input["metricId"]
|
|
15605
15840
|
});
|
|
15606
|
-
const
|
|
15841
|
+
const _vp33 = (input, _path, _exceptionable = true) => input["status"] === "censored" || input["status"] === "failed" || input["status"] === "observed" || input["status"] === "rejected" || _report(_exceptionable, {
|
|
15607
15842
|
path: _path + ".status",
|
|
15608
15843
|
expected: '("censored" | "failed" | "observed" | "rejected")',
|
|
15609
15844
|
value: input["status"]
|
|
15610
15845
|
});
|
|
15611
|
-
const
|
|
15846
|
+
const _vp34 = (input, _path, _exceptionable = true) => input["value"] === null || typeof input["value"] === "string" || _report(_exceptionable, {
|
|
15612
15847
|
path: _path + ".value",
|
|
15613
15848
|
expected: "(null | string)",
|
|
15614
15849
|
value: input["value"]
|
|
15615
15850
|
});
|
|
15616
|
-
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);
|
|
15617
15852
|
const _io1 = (input) => typeof input.ref === "string" && typeof input.hash === "string";
|
|
15618
15853
|
const _io2 = (input) => typeof input.candidates === "number" && typeof input.seeds === "number" && typeof input.usedCandidates === "number" && typeof input.usedSeeds === "number";
|
|
15619
|
-
const _io3 = (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);
|
|
15620
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"));
|
|
15621
|
-
const _io5 = (input) =>
|
|
15622
|
-
const _io6 = (input) => typeof input.dimensionId === "string" &&
|
|
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");
|
|
15623
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"));
|
|
15624
|
-
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);
|
|
15625
15860
|
const _vo1 = (input, _path, _exceptionable = true) => [typeof input.ref === "string" || _report(_exceptionable, {
|
|
15626
15861
|
path: _path + ".ref",
|
|
15627
15862
|
expected: "string",
|
|
@@ -15648,7 +15883,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15648
15883
|
expected: "number",
|
|
15649
15884
|
value: input.usedSeeds
|
|
15650
15885
|
})].every((flag) => flag);
|
|
15651
|
-
const _vo3 = (input, _path, _exceptionable = true) => [
|
|
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);
|
|
15652
15887
|
const _vo4 = (input, _path, _exceptionable = true) => [typeof input.id === "string" || _report(_exceptionable, {
|
|
15653
15888
|
path: _path + ".id",
|
|
15654
15889
|
expected: "string",
|
|
@@ -15682,12 +15917,12 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15682
15917
|
expected: "ReadonlyArray<string>",
|
|
15683
15918
|
value: input.constraintViolations
|
|
15684
15919
|
})].every((flag) => flag);
|
|
15685
|
-
const _vo5 = (input, _path, _exceptionable = true) => [
|
|
15920
|
+
const _vo5 = (input, _path, _exceptionable = true) => [_vp32(input, _path, _exceptionable), _vp33(input, _path, _exceptionable), _vp34(input, _path, _exceptionable)].every((flag) => flag);
|
|
15686
15921
|
const _vo6 = (input, _path, _exceptionable = true) => [typeof input.dimensionId === "string" || _report(_exceptionable, {
|
|
15687
15922
|
path: _path + ".dimensionId",
|
|
15688
15923
|
expected: "string",
|
|
15689
15924
|
value: input.dimensionId
|
|
15690
|
-
}),
|
|
15925
|
+
}), _vp19(input, _path, _exceptionable), _vp32(input, _path, _exceptionable), input.method === "one-at-a-time-local" || _report(_exceptionable, {
|
|
15691
15926
|
path: _path + ".method",
|
|
15692
15927
|
expected: '"one-at-a-time-local"',
|
|
15693
15928
|
value: input.method
|
|
@@ -15773,105 +16008,82 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15773
16008
|
};
|
|
15774
16009
|
});
|
|
15775
16010
|
})())(input), validateExperimentSpecValidator, validateExperimentSpec = (input) => (validateExperimentSpecValidator ??= (() => {
|
|
15776
|
-
const _ip0 = (input) => input["
|
|
15777
|
-
const _ip1 = (input) => typeof input["
|
|
15778
|
-
const _ip2 = (input) => typeof input["
|
|
15779
|
-
const _ip3 = (input) => typeof input["
|
|
15780
|
-
const
|
|
15781
|
-
const
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
|
|
15786
|
-
const
|
|
15787
|
-
const
|
|
15788
|
-
const
|
|
15789
|
-
const
|
|
15790
|
-
|
|
15791
|
-
|
|
15792
|
-
|
|
15793
|
-
|
|
15794
|
-
const
|
|
15795
|
-
const
|
|
15796
|
-
|
|
15797
|
-
expected: "number",
|
|
15798
|
-
value: input["min"]
|
|
15799
|
-
});
|
|
15800
|
-
const _vp3 = (input, _path, _exceptionable = true) => typeof input["max"] === "number" || _report(_exceptionable, {
|
|
15801
|
-
path: _path + ".max",
|
|
15802
|
-
expected: "number",
|
|
15803
|
-
value: input["max"]
|
|
15804
|
-
});
|
|
15805
|
-
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[]; }>)';
|
|
15806
|
-
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));
|
|
15807
|
-
const _io1 = (input) => typeof input.ref === "string" && typeof input.hash === "string";
|
|
15808
|
-
const _io10 = (input) => input.kind === "number" && _ip2(input) && _ip3(input) && (input.scale === undefined || input.scale === "linear" || input.scale === "log");
|
|
15809
|
-
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"));
|
|
15810
|
-
const _io12 = (input) => _ip1(input) && (Array.isArray(input.assignments) && input.assignments.every((elem) => typeof elem === "object" && elem !== null && _io13(elem)));
|
|
15811
|
-
const _io13 = (input) => typeof input.dimensionId === "string" && (input.value === null || typeof input.value === "string" || typeof input.value === "number" || typeof input.value === "boolean");
|
|
15812
|
-
const _io14 = (input) => typeof input.candidates === "number" && typeof input.seeds === "number";
|
|
15813
|
-
const _io15 = (input) => typeof input.pattern === "string" && typeof input.days === "number";
|
|
15814
|
-
const _io2 = (input) => _ip1(input) && typeof input.version === "number";
|
|
15815
|
-
const _io3 = (input) => _ip1(input);
|
|
15816
|
-
const _io4 = (input) => typeof input.target === "number";
|
|
15817
|
-
const _io5 = (input) => _ip1(input) && _ip0(input) && (input.sense === "higher" || input.sense === "lower");
|
|
15818
|
-
const _io6 = (input) => _ip1(input) && _ip0(input) && (input.op === "gte" || input.op === "lte") && typeof input.limit === "number";
|
|
15819
|
-
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"));
|
|
15820
|
-
const _io8 = (input) => input.kind === "bool";
|
|
15821
|
-
const _io9 = (input) => input.kind === "int" && _ip2(input) && _ip3(input);
|
|
15822
|
-
const _iu0 = (input) => (() => {
|
|
15823
|
-
if (input.kind === "bool")
|
|
15824
|
-
return _io8(input);
|
|
15825
|
-
else if (input.kind === "int")
|
|
15826
|
-
return _io9(input);
|
|
15827
|
-
else if (input.kind === "number")
|
|
15828
|
-
return _io10(input);
|
|
15829
|
-
else if (input.kind === "choice")
|
|
15830
|
-
return _io11(input);
|
|
15831
|
-
else
|
|
15832
|
-
return false;
|
|
15833
|
-
})();
|
|
15834
|
-
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, {
|
|
15835
16032
|
path: _path + ".schemaVersion",
|
|
15836
16033
|
expected: "1",
|
|
15837
|
-
value: input
|
|
15838
|
-
})
|
|
16034
|
+
value: input["schemaVersion"]
|
|
16035
|
+
});
|
|
16036
|
+
const _vp1 = (input, _path, _exceptionable = true) => (typeof input["scenario"] === "object" && input["scenario"] !== null || _report(_exceptionable, {
|
|
15839
16037
|
path: _path + ".scenario",
|
|
15840
16038
|
expected: "Readonly<{ ref: string; hash: string; }>",
|
|
15841
|
-
value: input
|
|
15842
|
-
})) && _vo1(input
|
|
16039
|
+
value: input["scenario"]
|
|
16040
|
+
})) && _vo1(input["scenario"], _path + ".scenario", _exceptionable) || _report(_exceptionable, {
|
|
15843
16041
|
path: _path + ".scenario",
|
|
15844
16042
|
expected: "Readonly<{ ref: string; hash: string; }>",
|
|
15845
|
-
value: input
|
|
15846
|
-
})
|
|
16043
|
+
value: input["scenario"]
|
|
16044
|
+
});
|
|
16045
|
+
const _vp2 = (input, _path, _exceptionable = true) => (typeof input["model"] === "object" && input["model"] !== null || _report(_exceptionable, {
|
|
15847
16046
|
path: _path + ".model",
|
|
15848
16047
|
expected: "Readonly<{ id: string; version: number; }>",
|
|
15849
|
-
value: input
|
|
15850
|
-
})) && _vo2(input
|
|
16048
|
+
value: input["model"]
|
|
16049
|
+
})) && _vo2(input["model"], _path + ".model", _exceptionable) || _report(_exceptionable, {
|
|
15851
16050
|
path: _path + ".model",
|
|
15852
16051
|
expected: "Readonly<{ id: string; version: number; }>",
|
|
15853
|
-
value: input
|
|
15854
|
-
})
|
|
16052
|
+
value: input["model"]
|
|
16053
|
+
});
|
|
16054
|
+
const _vp3 = (input, _path, _exceptionable = true) => input["strategy"] === undefined || (typeof input["strategy"] === "object" && input["strategy"] !== null || _report(_exceptionable, {
|
|
15855
16055
|
path: _path + ".strategy",
|
|
15856
16056
|
expected: "(Readonly<{ id: string; }> | undefined)",
|
|
15857
|
-
value: input
|
|
15858
|
-
})) && _vo3(input
|
|
16057
|
+
value: input["strategy"]
|
|
16058
|
+
})) && _vo3(input["strategy"], _path + ".strategy", _exceptionable) || _report(_exceptionable, {
|
|
15859
16059
|
path: _path + ".strategy",
|
|
15860
16060
|
expected: "(Readonly<{ id: string; }> | undefined)",
|
|
15861
|
-
value: input
|
|
15862
|
-
})
|
|
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, {
|
|
15863
16069
|
path: _path + ".goal",
|
|
15864
16070
|
expected: "(Readonly<{ target: number; }> | undefined)",
|
|
15865
|
-
value: input
|
|
15866
|
-
})) && _vo4(input
|
|
16071
|
+
value: input["goal"]
|
|
16072
|
+
})) && _vo4(input["goal"], _path + ".goal", _exceptionable) || _report(_exceptionable, {
|
|
15867
16073
|
path: _path + ".goal",
|
|
15868
16074
|
expected: "(Readonly<{ target: number; }> | undefined)",
|
|
15869
|
-
value: input
|
|
15870
|
-
})
|
|
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, {
|
|
15871
16083
|
path: _path + ".objectives",
|
|
15872
16084
|
expected: '(ReadonlyArray<Readonly<{ id: string; metricId: ExperimentMetricId; sense: "higher" | "lower"; }>> | undefined)',
|
|
15873
|
-
value: input
|
|
15874
|
-
})) && input
|
|
16085
|
+
value: input["objectives"]
|
|
16086
|
+
})) && input["objectives"].map((elem, _index9) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
|
|
15875
16087
|
path: _path + ".objectives[" + _index9 + "]",
|
|
15876
16088
|
expected: 'Readonly<{ id: string; metricId: ExperimentMetricId; sense: "higher" | "lower"; }>',
|
|
15877
16089
|
value: elem
|
|
@@ -15882,12 +16094,13 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15882
16094
|
})).every((flag) => flag) || _report(_exceptionable, {
|
|
15883
16095
|
path: _path + ".objectives",
|
|
15884
16096
|
expected: '(ReadonlyArray<Readonly<{ id: string; metricId: ExperimentMetricId; sense: "higher" | "lower"; }>> | undefined)',
|
|
15885
|
-
value: input
|
|
15886
|
-
})
|
|
16097
|
+
value: input["objectives"]
|
|
16098
|
+
});
|
|
16099
|
+
const _vp8 = (input, _path, _exceptionable = true) => input["constraints"] === undefined || (Array.isArray(input["constraints"]) || _report(_exceptionable, {
|
|
15887
16100
|
path: _path + ".constraints",
|
|
15888
16101
|
expected: '(ReadonlyArray<Readonly<{ id: string; metricId: ExperimentMetricId; op: "gte" | "lte"; limit: number; }>> | undefined)',
|
|
15889
|
-
value: input
|
|
15890
|
-
})) && input
|
|
16102
|
+
value: input["constraints"]
|
|
16103
|
+
})) && input["constraints"].map((elem, _index10) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
|
|
15891
16104
|
path: _path + ".constraints[" + _index10 + "]",
|
|
15892
16105
|
expected: 'Readonly<{ id: string; metricId: ExperimentMetricId; op: "gte" | "lte"; limit: number; }>',
|
|
15893
16106
|
value: elem
|
|
@@ -15898,12 +16111,13 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15898
16111
|
})).every((flag) => flag) || _report(_exceptionable, {
|
|
15899
16112
|
path: _path + ".constraints",
|
|
15900
16113
|
expected: '(ReadonlyArray<Readonly<{ id: string; metricId: ExperimentMetricId; op: "gte" | "lte"; limit: number; }>> | undefined)',
|
|
15901
|
-
value: input
|
|
15902
|
-
})
|
|
16114
|
+
value: input["constraints"]
|
|
16115
|
+
});
|
|
16116
|
+
const _vp9 = (input, _path, _exceptionable = true) => (Array.isArray(input["dimensions"]) || _report(_exceptionable, {
|
|
15903
16117
|
path: _path + ".dimensions",
|
|
15904
16118
|
expected: _ve2,
|
|
15905
|
-
value: input
|
|
15906
|
-
})) && input
|
|
16119
|
+
value: input["dimensions"]
|
|
16120
|
+
})) && input["dimensions"].map((elem, _index11) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
|
|
15907
16121
|
path: _path + ".dimensions[" + _index11 + "]",
|
|
15908
16122
|
expected: _ve1,
|
|
15909
16123
|
value: elem
|
|
@@ -15914,12 +16128,15 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15914
16128
|
})).every((flag) => flag) || _report(_exceptionable, {
|
|
15915
16129
|
path: _path + ".dimensions",
|
|
15916
16130
|
expected: _ve2,
|
|
15917
|
-
value: input
|
|
15918
|
-
})
|
|
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, {
|
|
15919
16136
|
path: _path + ".candidates",
|
|
15920
16137
|
expected: _ve3,
|
|
15921
|
-
value: input
|
|
15922
|
-
})) && input
|
|
16138
|
+
value: input["candidates"]
|
|
16139
|
+
})) && input["candidates"].map((elem, _index12) => (typeof elem === "object" && elem !== null || _report(_exceptionable, {
|
|
15923
16140
|
path: _path + ".candidates[" + _index12 + "]",
|
|
15924
16141
|
expected: "Readonly<{ id: string; assignments: readonly Readonly<{ dimensionId: string; value: ExperimentScalar; }>[]; }>",
|
|
15925
16142
|
value: elem
|
|
@@ -15930,44 +16147,96 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15930
16147
|
})).every((flag) => flag) || _report(_exceptionable, {
|
|
15931
16148
|
path: _path + ".candidates",
|
|
15932
16149
|
expected: _ve3,
|
|
15933
|
-
value: input
|
|
15934
|
-
})
|
|
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, {
|
|
15935
16154
|
path: _path + ".budget",
|
|
15936
16155
|
expected: "Readonly<{ candidates: number; seeds: number; }>",
|
|
15937
|
-
value: input
|
|
15938
|
-
})) && _vo14(input
|
|
16156
|
+
value: input["budget"]
|
|
16157
|
+
})) && _vo14(input["budget"], _path + ".budget", _exceptionable) || _report(_exceptionable, {
|
|
15939
16158
|
path: _path + ".budget",
|
|
15940
16159
|
expected: "Readonly<{ candidates: number; seeds: number; }>",
|
|
15941
|
-
value: input
|
|
15942
|
-
})
|
|
16160
|
+
value: input["budget"]
|
|
16161
|
+
});
|
|
16162
|
+
const _vp12 = (input, _path, _exceptionable = true) => (Array.isArray(input["seeds"]) || _report(_exceptionable, {
|
|
15943
16163
|
path: _path + ".seeds",
|
|
15944
16164
|
expected: "ReadonlyArray<number>",
|
|
15945
|
-
value: input
|
|
15946
|
-
})) && input
|
|
16165
|
+
value: input["seeds"]
|
|
16166
|
+
})) && input["seeds"].map((elem, _index13) => typeof elem === "number" || _report(_exceptionable, {
|
|
15947
16167
|
path: _path + ".seeds[" + _index13 + "]",
|
|
15948
16168
|
expected: "number",
|
|
15949
16169
|
value: elem
|
|
15950
16170
|
})).every((flag) => flag) || _report(_exceptionable, {
|
|
15951
16171
|
path: _path + ".seeds",
|
|
15952
16172
|
expected: "ReadonlyArray<number>",
|
|
15953
|
-
value: input
|
|
15954
|
-
})
|
|
16173
|
+
value: input["seeds"]
|
|
16174
|
+
});
|
|
16175
|
+
const _vp13 = (input, _path, _exceptionable = true) => typeof input["horizonSec"] === "number" || _report(_exceptionable, {
|
|
15955
16176
|
path: _path + ".horizonSec",
|
|
15956
16177
|
expected: "number",
|
|
15957
|
-
value: input
|
|
15958
|
-
})
|
|
16178
|
+
value: input["horizonSec"]
|
|
16179
|
+
});
|
|
16180
|
+
const _vp14 = (input, _path, _exceptionable = true) => typeof input["stepSec"] === "number" || _report(_exceptionable, {
|
|
15959
16181
|
path: _path + ".stepSec",
|
|
15960
16182
|
expected: "number",
|
|
15961
|
-
value: input
|
|
15962
|
-
})
|
|
16183
|
+
value: input["stepSec"]
|
|
16184
|
+
});
|
|
16185
|
+
const _vp15 = (input, _path, _exceptionable = true) => (typeof input["session"] === "object" && input["session"] !== null || _report(_exceptionable, {
|
|
15963
16186
|
path: _path + ".session",
|
|
15964
16187
|
expected: "Readonly<{ pattern: string; days: number; }>",
|
|
15965
|
-
value: input
|
|
15966
|
-
})) && _vo15(input
|
|
16188
|
+
value: input["session"]
|
|
16189
|
+
})) && _vo15(input["session"], _path + ".session", _exceptionable) || _report(_exceptionable, {
|
|
15967
16190
|
path: _path + ".session",
|
|
15968
16191
|
expected: "Readonly<{ pattern: string; days: number; }>",
|
|
15969
|
-
value: input
|
|
15970
|
-
})
|
|
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);
|
|
15971
16240
|
const _vo1 = (input, _path, _exceptionable = true) => [typeof input.ref === "string" || _report(_exceptionable, {
|
|
15972
16241
|
path: _path + ".ref",
|
|
15973
16242
|
expected: "string",
|
|
@@ -15981,7 +16250,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
15981
16250
|
path: _path + ".kind",
|
|
15982
16251
|
expected: '"number"',
|
|
15983
16252
|
value: input.kind
|
|
15984
|
-
}),
|
|
16253
|
+
}), _vp17(input, _path, _exceptionable), _vp18(input, _path, _exceptionable), input.scale === undefined || input.scale === "linear" || input.scale === "log" || _report(_exceptionable, {
|
|
15985
16254
|
path: _path + ".scale",
|
|
15986
16255
|
expected: '("linear" | "log" | undefined)',
|
|
15987
16256
|
value: input.scale
|
|
@@ -16003,7 +16272,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
16003
16272
|
expected: "ReadonlyArray<ExperimentScalar>",
|
|
16004
16273
|
value: input.values
|
|
16005
16274
|
})].every((flag) => flag);
|
|
16006
|
-
const _vo12 = (input, _path, _exceptionable = true) => [
|
|
16275
|
+
const _vo12 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), (Array.isArray(input.assignments) || _report(_exceptionable, {
|
|
16007
16276
|
path: _path + ".assignments",
|
|
16008
16277
|
expected: "ReadonlyArray<Readonly<{ dimensionId: string; value: ExperimentScalar; }>>",
|
|
16009
16278
|
value: input.assignments
|
|
@@ -16047,23 +16316,23 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
16047
16316
|
expected: "number",
|
|
16048
16317
|
value: input.days
|
|
16049
16318
|
})].every((flag) => flag);
|
|
16050
|
-
const _vo2 = (input, _path, _exceptionable = true) => [
|
|
16319
|
+
const _vo2 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), typeof input.version === "number" || _report(_exceptionable, {
|
|
16051
16320
|
path: _path + ".version",
|
|
16052
16321
|
expected: "number",
|
|
16053
16322
|
value: input.version
|
|
16054
16323
|
})].every((flag) => flag);
|
|
16055
|
-
const _vo3 = (input, _path, _exceptionable = true) => [
|
|
16324
|
+
const _vo3 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable)].every((flag) => flag);
|
|
16056
16325
|
const _vo4 = (input, _path, _exceptionable = true) => [typeof input.target === "number" || _report(_exceptionable, {
|
|
16057
16326
|
path: _path + ".target",
|
|
16058
16327
|
expected: "number",
|
|
16059
16328
|
value: input.target
|
|
16060
16329
|
})].every((flag) => flag);
|
|
16061
|
-
const _vo5 = (input, _path, _exceptionable = true) => [
|
|
16330
|
+
const _vo5 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), _vp4(input, _path, _exceptionable), input.sense === "higher" || input.sense === "lower" || _report(_exceptionable, {
|
|
16062
16331
|
path: _path + ".sense",
|
|
16063
16332
|
expected: '("higher" | "lower")',
|
|
16064
16333
|
value: input.sense
|
|
16065
16334
|
})].every((flag) => flag);
|
|
16066
|
-
const _vo6 = (input, _path, _exceptionable = true) => [
|
|
16335
|
+
const _vo6 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), _vp4(input, _path, _exceptionable), input.op === "gte" || input.op === "lte" || _report(_exceptionable, {
|
|
16067
16336
|
path: _path + ".op",
|
|
16068
16337
|
expected: '("gte" | "lte")',
|
|
16069
16338
|
value: input.op
|
|
@@ -16072,7 +16341,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
16072
16341
|
expected: "number",
|
|
16073
16342
|
value: input.limit
|
|
16074
16343
|
})].every((flag) => flag);
|
|
16075
|
-
const _vo7 = (input, _path, _exceptionable = true) => [
|
|
16344
|
+
const _vo7 = (input, _path, _exceptionable = true) => [_vp16(input, _path, _exceptionable), input.target === "model" || input.target === "session" || input.target === "strategy" || _report(_exceptionable, {
|
|
16076
16345
|
path: _path + ".target",
|
|
16077
16346
|
expected: '("model" | "session" | "strategy")',
|
|
16078
16347
|
value: input.target
|
|
@@ -16114,7 +16383,7 @@ var EXPERIMENT_ALGORITHM_VERSION = "experiment-oat-v1", EXPERIMENT_ESTIMATOR_VER
|
|
|
16114
16383
|
path: _path + ".kind",
|
|
16115
16384
|
expected: '"int"',
|
|
16116
16385
|
value: input.kind
|
|
16117
|
-
}),
|
|
16386
|
+
}), _vp17(input, _path, _exceptionable), _vp18(input, _path, _exceptionable)].every((flag) => flag);
|
|
16118
16387
|
const _vu0 = (input, _path, _exceptionable = true) => (() => {
|
|
16119
16388
|
if (input.kind === "bool")
|
|
16120
16389
|
return _vo8(input, _path, _exceptionable);
|
|
@@ -18414,7 +18683,7 @@ var init_checks3 = __esm(() => {
|
|
|
18414
18683
|
FAIL_ON = ["error", "warn", "inconclusive", "unsupported"];
|
|
18415
18684
|
});
|
|
18416
18685
|
|
|
18417
|
-
// ../../node_modules/.bun/typia@15.
|
|
18686
|
+
// ../../node_modules/.bun/typia@15.2.2+38c91d72aa8392f2/node_modules/typia/lib/internal/_accessExpressionAsString.mjs
|
|
18418
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;
|
|
18419
18688
|
var init__accessExpressionAsString = __esm(() => {
|
|
18420
18689
|
RESERVED = /* @__PURE__ */ new Set([
|
|
@@ -18478,6 +18747,9 @@ function nonfiniteThresholds(rubric) {
|
|
|
18478
18747
|
if (rule.upperThreshold !== null && !Number.isFinite(rule.upperThreshold)) {
|
|
18479
18748
|
issues.push(`$input.rules[${index}].upperThreshold finite number or null`);
|
|
18480
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
|
+
}
|
|
18481
18753
|
});
|
|
18482
18754
|
return issues;
|
|
18483
18755
|
}
|
|
@@ -18503,8 +18775,16 @@ function evaluateGroups(failOn, groups, checks) {
|
|
|
18503
18775
|
const pass = reports.every((report) => report.pass);
|
|
18504
18776
|
return { ...first, results, pass, exitCode: pass ? 0 : 2 };
|
|
18505
18777
|
}
|
|
18506
|
-
function
|
|
18507
|
-
|
|
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)}`;
|
|
18508
18788
|
}
|
|
18509
18789
|
function isUnavailable(reading) {
|
|
18510
18790
|
return reading.reading === "unavailable" || reading.status !== "ok";
|
|
@@ -18671,27 +18951,40 @@ function judgeArtifact(artifact, rubric) {
|
|
|
18671
18951
|
const issues = [];
|
|
18672
18952
|
const groups = new Map;
|
|
18673
18953
|
const estimatedObservations = [];
|
|
18954
|
+
const estimatedReadings = new Set;
|
|
18674
18955
|
const prepared = [];
|
|
18675
18956
|
for (const rule of rubric.rules) {
|
|
18676
|
-
const
|
|
18957
|
+
const label = ruleRefLabel(rule);
|
|
18958
|
+
const readings = ruleReadings(artifact, rule);
|
|
18677
18959
|
const reading = readings[0];
|
|
18678
18960
|
if (!reading) {
|
|
18679
|
-
|
|
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}`);
|
|
18680
18963
|
continue;
|
|
18681
18964
|
}
|
|
18682
18965
|
if (readings.length > 1) {
|
|
18683
|
-
issues.push(`ambiguous evidenceRef
|
|
18966
|
+
issues.push(`ambiguous evidenceRef ${label} matches ${readings.length} readings`);
|
|
18684
18967
|
continue;
|
|
18685
18968
|
}
|
|
18686
18969
|
const mapped = toObservation(artifact, reading, rule);
|
|
18687
|
-
const key = JSON.stringify([
|
|
18970
|
+
const key = JSON.stringify([
|
|
18971
|
+
reading.metricId,
|
|
18972
|
+
reading.metricVersion,
|
|
18973
|
+
mapped.observation.identity.method,
|
|
18974
|
+
mapped.observation.identity.unit
|
|
18975
|
+
]);
|
|
18688
18976
|
const group = groups.get(key) ?? { observation: mapped.observation, indices: [] };
|
|
18689
18977
|
group.indices.push(prepared.length);
|
|
18690
18978
|
groups.set(key, group);
|
|
18691
|
-
if (mapped.estimated && !
|
|
18979
|
+
if (mapped.estimated && !estimatedReadings.has(reading)) {
|
|
18980
|
+
estimatedReadings.add(reading);
|
|
18692
18981
|
estimatedObservations.push(mapped.estimated);
|
|
18693
18982
|
}
|
|
18694
|
-
prepared.push({
|
|
18983
|
+
prepared.push({
|
|
18984
|
+
rule,
|
|
18985
|
+
estimated: mapped.estimated,
|
|
18986
|
+
refs: [`metric:${rule.metricId}`, metricVersionRef(reading.metricVersion)]
|
|
18987
|
+
});
|
|
18695
18988
|
}
|
|
18696
18989
|
if (issues.length > 0)
|
|
18697
18990
|
return { ok: false, issues };
|
|
@@ -18704,7 +18997,7 @@ function judgeArtifact(artifact, rubric) {
|
|
|
18704
18997
|
id: item.rule.id,
|
|
18705
18998
|
category: outcome.category,
|
|
18706
18999
|
severity: outcome.severity,
|
|
18707
|
-
evidenceRefs:
|
|
19000
|
+
evidenceRefs: item.refs,
|
|
18708
19001
|
assumptionRefs,
|
|
18709
19002
|
recommendationId: outcome.recommendationId,
|
|
18710
19003
|
status: outcome.status,
|
|
@@ -18728,9 +19021,9 @@ function judgeArtifact(artifact, rubric) {
|
|
|
18728
19021
|
return { ok: true, report };
|
|
18729
19022
|
}
|
|
18730
19023
|
var JUDGE_ALGORITHM_VERSION = "judge-rules-1", validateRubricValidator, validateRubric = (input) => (validateRubricValidator ??= (() => {
|
|
18731
|
-
const _ve0 = 'Readonly<{ schemaVersion: 1; contract: "idlekit.judge.rubric.v1"; rubricVersion: string; failOn: readonly FailOnToken[]; rules: readonly Readonly<{ id: string; metricId: string;
|
|
18732
|
-
const _ve1 = "Readonly<{ id: string; metricId: string; operator: CheckOperator; threshold: number; upperThreshold: number | null; unit: string; severity: CheckSeverity;
|
|
18733
|
-
const _ve2 = "ReadonlyArray<Readonly<{ id: string; metricId: string; operator: CheckOperator; threshold: number; upperThreshold: number | null; unit: string; severity: CheckSeverity;
|
|
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; }>>";
|
|
18734
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")';
|
|
18735
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) => {
|
|
18736
19029
|
if (["schemaVersion", "contract", "rubricVersion", "failOn", "rules"].some((prop) => key === prop))
|
|
@@ -18740,8 +19033,8 @@ var JUDGE_ALGORITHM_VERSION = "judge-rules-1", validateRubricValidator, validate
|
|
|
18740
19033
|
return true;
|
|
18741
19034
|
return false;
|
|
18742
19035
|
}));
|
|
18743
|
-
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) => {
|
|
18744
|
-
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))
|
|
18745
19038
|
return true;
|
|
18746
19039
|
const value = input[key];
|
|
18747
19040
|
if (value === undefined)
|
|
@@ -18814,6 +19107,10 @@ var JUDGE_ALGORITHM_VERSION = "judge-rules-1", validateRubricValidator, validate
|
|
|
18814
19107
|
path: _path + ".metricId",
|
|
18815
19108
|
expected: "string",
|
|
18816
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
|
|
18817
19114
|
}), input.operator === "between" || input.operator === "eq" || input.operator === "gt" || input.operator === "gte" || input.operator === "lt" || input.operator === "lte" || _report(_exceptionable, {
|
|
18818
19115
|
path: _path + ".operator",
|
|
18819
19116
|
expected: '("between" | "eq" | "gt" | "gte" | "lt" | "lte")',
|
|
@@ -18875,7 +19172,7 @@ var JUDGE_ALGORITHM_VERSION = "judge-rules-1", validateRubricValidator, validate
|
|
|
18875
19172
|
expected: _ve3,
|
|
18876
19173
|
value: input.recommendationId
|
|
18877
19174
|
}), Object.keys(input).length === 17 || (_exceptionable === false || Object.keys(input).map((key) => {
|
|
18878
|
-
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))
|
|
18879
19176
|
return true;
|
|
18880
19177
|
const value = input[key];
|
|
18881
19178
|
if (value === undefined)
|
|
@@ -18961,7 +19258,7 @@ var init_judge = __esm(() => {
|
|
|
18961
19258
|
// ../core/dist/sim/analysis/flow.js
|
|
18962
19259
|
var init_flow = () => {};
|
|
18963
19260
|
|
|
18964
|
-
// ../../node_modules/.bun/typia@15.
|
|
19261
|
+
// ../../node_modules/.bun/typia@15.2.2+38c91d72aa8392f2/node_modules/typia/lib/internal/_isTypeUint32.mjs
|
|
18965
19262
|
var _isTypeUint32 = (value) => Math.floor(value) === value && MINIMUM <= value && value <= MAXIMUM, MINIMUM = 0, MAXIMUM;
|
|
18966
19263
|
var init__isTypeUint32 = __esm(() => {
|
|
18967
19264
|
MAXIMUM = 2 ** 32 - 1;
|
|
@@ -19353,32 +19650,46 @@ function buildTimeline(args) {
|
|
|
19353
19650
|
}
|
|
19354
19651
|
|
|
19355
19652
|
// ../core/dist/report/compare.js
|
|
19356
|
-
function
|
|
19357
|
-
|
|
19358
|
-
|
|
19359
|
-
|
|
19360
|
-
|
|
19361
|
-
|
|
19362
|
-
|
|
19363
|
-
const
|
|
19364
|
-
|
|
19365
|
-
|
|
19366
|
-
|
|
19367
|
-
|
|
19368
|
-
|
|
19369
|
-
|
|
19370
|
-
|
|
19371
|
-
|
|
19372
|
-
|
|
19373
|
-
|
|
19374
|
-
|
|
19653
|
+
function decimalParts(input) {
|
|
19654
|
+
const match = /^([+-]?)(?:(\d+)(?:\.(\d+))?|\.(\d+))(?:e([+-]?\d+))?([a-z]{2,})?$/i.exec(input.trim());
|
|
19655
|
+
if (!match)
|
|
19656
|
+
throw new RangeError("Static monetary comparison requires decimal amounts");
|
|
19657
|
+
let suffixExponent = 0n;
|
|
19658
|
+
if (match[6]) {
|
|
19659
|
+
let index = 0n;
|
|
19660
|
+
for (const ch of match[6].toLowerCase())
|
|
19661
|
+
index = index * 26n + BigInt(ch.charCodeAt(0) - 96);
|
|
19662
|
+
suffixExponent = (index - 26n) * 3n;
|
|
19663
|
+
}
|
|
19664
|
+
const fraction = match[3] ?? match[4] ?? "";
|
|
19665
|
+
const digits = `${match[2] ?? ""}${fraction}`.replace(/^0+/, "");
|
|
19666
|
+
let end = digits.length;
|
|
19667
|
+
while (end > 0 && digits[end - 1] === "0")
|
|
19668
|
+
end--;
|
|
19669
|
+
return {
|
|
19670
|
+
sign: digits.length === 0 ? 0 : match[1] === "-" ? -1 : 1,
|
|
19671
|
+
digits: digits.slice(0, end),
|
|
19672
|
+
magnitude: BigInt(match[5] ?? "0") + suffixExponent - BigInt(fraction.length) + BigInt(digits.length)
|
|
19673
|
+
};
|
|
19674
|
+
}
|
|
19675
|
+
function compareStaticMoney(left, right) {
|
|
19676
|
+
const a = decimalParts(left), b = decimalParts(right);
|
|
19677
|
+
if (a.sign !== b.sign)
|
|
19678
|
+
return a.sign < b.sign ? -1 : 1;
|
|
19679
|
+
if (a.sign === 0)
|
|
19680
|
+
return 0;
|
|
19681
|
+
if (a.magnitude !== b.magnitude)
|
|
19682
|
+
return (a.magnitude < b.magnitude ? -1 : 1) * a.sign;
|
|
19683
|
+
const length = Math.max(a.digits.length, b.digits.length);
|
|
19684
|
+
const ad = a.digits.padEnd(length, "0"), bd = b.digits.padEnd(length, "0");
|
|
19685
|
+
return (ad < bd ? -1 : ad > bd ? 1 : 0) * a.sign;
|
|
19375
19686
|
}
|
|
19376
19687
|
function score(s, metric) {
|
|
19377
19688
|
switch (metric) {
|
|
19378
19689
|
case "endMoney":
|
|
19379
|
-
return
|
|
19690
|
+
return s.initial.wallet.amount;
|
|
19380
19691
|
case "endNetWorth":
|
|
19381
|
-
return
|
|
19692
|
+
return s.initial.maxMoneyEver ?? s.initial.wallet.amount;
|
|
19382
19693
|
case "droppedRate":
|
|
19383
19694
|
return -(s.policy.maxLogGap ?? 0);
|
|
19384
19695
|
case "etaToTargetWorth":
|
|
@@ -19414,9 +19725,21 @@ function compareScenarios(args) {
|
|
|
19414
19725
|
}
|
|
19415
19726
|
const measuredA = measuredScore(args.measured?.a, args.metric);
|
|
19416
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
|
+
}
|
|
19417
19733
|
const useMeasured = measuredA !== undefined && measuredB !== undefined;
|
|
19418
19734
|
const aScore = useMeasured ? measuredA : score(args.a, args.metric);
|
|
19419
19735
|
const bScore = useMeasured ? measuredB : score(args.b, args.metric);
|
|
19736
|
+
if (!useMeasured && (args.metric === "endMoney" || args.metric === "endNetWorth")) {
|
|
19737
|
+
const order = compareStaticMoney(String(aScore), String(bScore));
|
|
19738
|
+
return {
|
|
19739
|
+
better: order === 0 ? "tie" : order > 0 ? "a" : "b",
|
|
19740
|
+
detail: { aScore, bScore, metric: args.metric, source: "static" }
|
|
19741
|
+
};
|
|
19742
|
+
}
|
|
19420
19743
|
const higherBetter = args.metric === "endMoney" || args.metric === "endNetWorth" || args.metric === "visibleChangesPerMinute";
|
|
19421
19744
|
if (aScore === bScore) {
|
|
19422
19745
|
return {
|
|
@@ -19526,12 +19849,12 @@ function estimateLtvPerUser(args) {
|
|
|
19526
19849
|
const fullDays = Math.floor(Math.max(0, horizonDays));
|
|
19527
19850
|
const remainder = Math.max(0, horizonDays - fullDays);
|
|
19528
19851
|
let gross = 0;
|
|
19529
|
-
for (let day =
|
|
19852
|
+
for (let day = 0;day < fullDays; day++) {
|
|
19530
19853
|
const active = retentionAtDay(config.retention, day);
|
|
19531
19854
|
gross += active * (payerConversion * arppuDaily + adArpDau);
|
|
19532
19855
|
}
|
|
19533
19856
|
if (remainder > 0) {
|
|
19534
|
-
const active = retentionAtDay(config.retention, fullDays
|
|
19857
|
+
const active = retentionAtDay(config.retention, fullDays);
|
|
19535
19858
|
gross += remainder * active * (payerConversion * arppuDaily + adArpDau);
|
|
19536
19859
|
}
|
|
19537
19860
|
const net = gross * (1 - config.revenue.platformFeeRate) * config.revenue.grossMarginRate;
|
|
@@ -19653,10 +19976,11 @@ function applyLogNormalShock(mean, sigma, z) {
|
|
|
19653
19976
|
}
|
|
19654
19977
|
function makeUncertainConfig(base, rng) {
|
|
19655
19978
|
const shock = sampleCorrelatedNormals(rng, base.uncertainty.correlation);
|
|
19656
|
-
const
|
|
19657
|
-
const
|
|
19658
|
-
const
|
|
19659
|
-
const
|
|
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);
|
|
19660
19984
|
return {
|
|
19661
19985
|
...base,
|
|
19662
19986
|
retention: {
|
|
@@ -19680,6 +20004,23 @@ function quantileFromSorted(sorted, q) {
|
|
|
19680
20004
|
const idx = Math.max(0, Math.min(sorted.length - 1, Math.floor((sorted.length - 1) * q)));
|
|
19681
20005
|
return sorted[idx] ?? 0;
|
|
19682
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
|
+
}
|
|
19683
20024
|
function estimateLtvDistribution(args) {
|
|
19684
20025
|
const rng = mulberry32(args.seed);
|
|
19685
20026
|
const grossSamples = [];
|
|
@@ -19701,7 +20042,7 @@ function estimateLtvDistribution(args) {
|
|
|
19701
20042
|
const sortedLtv = [...ltvSamples].sort((a, b) => a - b);
|
|
19702
20043
|
const byQuantile = {};
|
|
19703
20044
|
for (const q of args.quantiles) {
|
|
19704
|
-
byQuantile[
|
|
20045
|
+
byQuantile[quantileKey(q)] = quantileFromSorted(sortedLtv, q);
|
|
19705
20046
|
}
|
|
19706
20047
|
return {
|
|
19707
20048
|
mean: {
|
|
@@ -19736,8 +20077,7 @@ function assertQuantileValues(quantiles) {
|
|
|
19736
20077
|
throw new RangeError("quantiles must be nonempty and in 0..1");
|
|
19737
20078
|
}
|
|
19738
20079
|
}
|
|
19739
|
-
function
|
|
19740
|
-
const { retention, ...other } = config;
|
|
20080
|
+
function assertRetention(retention) {
|
|
19741
20081
|
for (const day of ["d1", "d7", "d30", "d90"]) {
|
|
19742
20082
|
if (!Number.isFinite(retention[day]) || retention[day] < 0 || retention[day] > 1) {
|
|
19743
20083
|
throw new RangeError(`retention.${day} must be finite and in 0..1`);
|
|
@@ -19746,6 +20086,10 @@ function assertConfig(config) {
|
|
|
19746
20086
|
if (!Number.isFinite(retention.longTailDailyDecay) || retention.longTailDailyDecay < 0) {
|
|
19747
20087
|
throw new RangeError("retention.longTailDailyDecay must be finite and >= 0");
|
|
19748
20088
|
}
|
|
20089
|
+
}
|
|
20090
|
+
function assertConfig(config) {
|
|
20091
|
+
const { retention, ...other } = config;
|
|
20092
|
+
assertRetention(retention);
|
|
19749
20093
|
const { quantiles, ...uncertainty } = other.uncertainty;
|
|
19750
20094
|
assertQuantileValues(quantiles);
|
|
19751
20095
|
assertMonetization({ ...other, uncertainty });
|
|
@@ -19756,6 +20100,14 @@ function deriveMonetizationConfig2(scenario) {
|
|
|
19756
20100
|
assertConfig(config);
|
|
19757
20101
|
return config;
|
|
19758
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
|
+
}
|
|
19759
20111
|
function assertPoint(args) {
|
|
19760
20112
|
assertConfig(args.config);
|
|
19761
20113
|
if (!Number.isFinite(args.horizonDays) || args.horizonDays < 0 || args.horizonDays > 36500) {
|
|
@@ -19776,18 +20128,24 @@ function estimateLtvPerUser2(args) {
|
|
|
19776
20128
|
}
|
|
19777
20129
|
function estimateLtvDistribution2(args) {
|
|
19778
20130
|
assertPoint(args);
|
|
19779
|
-
|
|
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) {
|
|
19780
20135
|
throw new RangeError("draws must be 1..100000 and draws \xD7 ceil(horizonDays) at most 10000000");
|
|
19781
20136
|
}
|
|
19782
|
-
if (
|
|
19783
|
-
throw new RangeError("seed
|
|
19784
|
-
if (
|
|
19785
|
-
throw new RangeError("
|
|
19786
|
-
|
|
19787
|
-
if (
|
|
19788
|
-
throw new RangeError("quantiles
|
|
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");
|
|
19789
20147
|
}
|
|
19790
|
-
const result = estimateLtvDistribution(args);
|
|
20148
|
+
const result = estimateLtvDistribution({ ...args, draws, quantiles, seed });
|
|
19791
20149
|
finiteResult(result.mean);
|
|
19792
20150
|
finiteResult(result.quantiles);
|
|
19793
20151
|
return result;
|
|
@@ -19797,6 +20155,151 @@ var init_public = __esm(() => {
|
|
|
19797
20155
|
init_uncertainty();
|
|
19798
20156
|
});
|
|
19799
20157
|
|
|
20158
|
+
// ../core/dist/ltv/cohort.js
|
|
20159
|
+
function wilsonInterval(activeUsers, users) {
|
|
20160
|
+
const rate = activeUsers / users;
|
|
20161
|
+
const z2 = 1.959963984540054 ** 2;
|
|
20162
|
+
const denominator = 1 + z2 / users;
|
|
20163
|
+
const center = (rate + z2 / (2 * users)) / denominator;
|
|
20164
|
+
const radius = Math.sqrt(z2 * (rate * (1 - rate) / users + z2 / (4 * users * users))) / denominator;
|
|
20165
|
+
return { min: activeUsers === 0 ? 0 : Math.max(0, center - radius), max: activeUsers === users ? 1 : Math.min(1, center + radius) };
|
|
20166
|
+
}
|
|
20167
|
+
function observeCohort(rows, observedThroughDay) {
|
|
20168
|
+
if (!Number.isSafeInteger(observedThroughDay) || observedThroughDay < 0)
|
|
20169
|
+
throw new Error("observed-through-day must be a nonnegative safe integer");
|
|
20170
|
+
if (!Array.isArray(rows) || rows.length === 0)
|
|
20171
|
+
throw new Error("Observed cohort requires at least one install record");
|
|
20172
|
+
const users = new Map;
|
|
20173
|
+
for (const row of rows) {
|
|
20174
|
+
if (!row || typeof row.userId !== "string" || !row.userId.trim() || !Number.isSafeInteger(row.day) || row.day < 0 || row.day > observedThroughDay) {
|
|
20175
|
+
throw new Error("Observed cohort requires a user ID and integer days within observed-through-day");
|
|
20176
|
+
}
|
|
20177
|
+
if (![row.iapRevenue, row.adRevenue, row.acquisitionCost].every((v) => v === undefined || typeof v === "number" && Number.isFinite(v) && v >= 0)) {
|
|
20178
|
+
throw new Error("Observed cohort revenue and acquisition costs must be finite and nonnegative");
|
|
20179
|
+
}
|
|
20180
|
+
if (row.active !== undefined && typeof row.active !== "boolean")
|
|
20181
|
+
throw new Error("Observed cohort active must be boolean");
|
|
20182
|
+
const user = users.get(row.userId) ?? { days: new Set, active: new Set };
|
|
20183
|
+
if (user.days.has(row.day))
|
|
20184
|
+
throw new Error("Observed cohort requires one aggregated row per user and day");
|
|
20185
|
+
user.days.add(row.day);
|
|
20186
|
+
if (row.active ?? true)
|
|
20187
|
+
user.active.add(row.day);
|
|
20188
|
+
users.set(row.userId, user);
|
|
20189
|
+
}
|
|
20190
|
+
for (const user of users.values()) {
|
|
20191
|
+
if (!user.days.has(0))
|
|
20192
|
+
throw new Error("Observed cohort requires a day 0 install record for every user, including inactive users");
|
|
20193
|
+
}
|
|
20194
|
+
const n = users.size;
|
|
20195
|
+
const observation = {
|
|
20196
|
+
observedThroughDay,
|
|
20197
|
+
users: n,
|
|
20198
|
+
retention: RETENTION_DAYS.map((day) => {
|
|
20199
|
+
if (day > observedThroughDay)
|
|
20200
|
+
return { day, status: "not-observed", users: n, activeUsers: null, rate: null, interval95: null };
|
|
20201
|
+
const activeUsers = [...users.values()].filter((user) => user.active.has(day)).length;
|
|
20202
|
+
const rate = activeUsers / n;
|
|
20203
|
+
return { day, status: "observed", users: n, activeUsers, rate, interval95: wilsonInterval(activeUsers, n) };
|
|
20204
|
+
})
|
|
20205
|
+
};
|
|
20206
|
+
assertCohortObservation(observation);
|
|
20207
|
+
return observation;
|
|
20208
|
+
}
|
|
20209
|
+
function object2(value) {
|
|
20210
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20211
|
+
}
|
|
20212
|
+
function assertCohortObservation(observation) {
|
|
20213
|
+
if (!object2(observation) || typeof observation.users !== "number" || !Number.isSafeInteger(observation.users) || observation.users < 1 || typeof observation.observedThroughDay !== "number" || !Number.isSafeInteger(observation.observedThroughDay) || observation.observedThroughDay < 0) {
|
|
20214
|
+
throw new Error("Invalid cohort population or observation cutoff");
|
|
20215
|
+
}
|
|
20216
|
+
if (!Array.isArray(observation.retention) || observation.retention.length !== RETENTION_DAYS.length)
|
|
20217
|
+
throw new Error("Cohort retention must contain D1, D7, D30 and D90");
|
|
20218
|
+
for (const [index, value] of observation.retention.entries()) {
|
|
20219
|
+
const point = value;
|
|
20220
|
+
if (!object2(point) || typeof point.day !== "number" || point.day !== RETENTION_DAYS[index] || point.users !== observation.users)
|
|
20221
|
+
throw new Error("Cohort retention days and population must match the observation");
|
|
20222
|
+
const observed = point.day <= observation.observedThroughDay;
|
|
20223
|
+
if (point.status !== (observed ? "observed" : "not-observed"))
|
|
20224
|
+
throw new Error("Cohort retention status must match the observation cutoff");
|
|
20225
|
+
if (!observed) {
|
|
20226
|
+
if (point.activeUsers !== null || point.rate !== null || point.interval95 !== null)
|
|
20227
|
+
throw new Error("Future retention must remain unobserved");
|
|
20228
|
+
continue;
|
|
20229
|
+
}
|
|
20230
|
+
if (typeof point.activeUsers !== "number" || !Number.isSafeInteger(point.activeUsers) || point.activeUsers < 0 || point.activeUsers > observation.users || point.rate !== point.activeUsers / observation.users) {
|
|
20231
|
+
throw new Error("Retained users and retention rate must match the installed population");
|
|
20232
|
+
}
|
|
20233
|
+
const interval = point.interval95;
|
|
20234
|
+
if (typeof point.rate !== "number" || !object2(interval) || typeof interval.min !== "number" || typeof interval.max !== "number" || !Number.isFinite(interval.min) || !Number.isFinite(interval.max) || interval.min < 0 || interval.max > 1 || interval.min > point.rate || interval.max < point.rate) {
|
|
20235
|
+
throw new Error("Retention confidence interval must be finite and contain the observed rate");
|
|
20236
|
+
}
|
|
20237
|
+
const expected = wilsonInterval(point.activeUsers, observation.users);
|
|
20238
|
+
if (interval.min !== expected.min || interval.max !== expected.max) {
|
|
20239
|
+
throw new Error("Retention confidence interval must match the Wilson 95% bounds for the observed population");
|
|
20240
|
+
}
|
|
20241
|
+
}
|
|
20242
|
+
}
|
|
20243
|
+
function observedRetentionRates(observation) {
|
|
20244
|
+
assertCohortObservation(observation);
|
|
20245
|
+
const rates = {};
|
|
20246
|
+
for (const row of observation.retention) {
|
|
20247
|
+
if (row.rate !== null)
|
|
20248
|
+
rates[`d${row.day}`] = row.rate;
|
|
20249
|
+
}
|
|
20250
|
+
return rates;
|
|
20251
|
+
}
|
|
20252
|
+
function assertRetentionAssumptions(assumptions) {
|
|
20253
|
+
if (!object2(assumptions))
|
|
20254
|
+
throw new RangeError("Retention assumptions must be an object");
|
|
20255
|
+
for (const day of RETENTION_DAYS) {
|
|
20256
|
+
const rate = assumptions[`d${day}`];
|
|
20257
|
+
if (rate !== undefined && (typeof rate !== "number" || !Number.isFinite(rate) || rate < 0 || rate > 1)) {
|
|
20258
|
+
throw new RangeError(`Retention assumption d${day} must be finite and in 0..1`);
|
|
20259
|
+
}
|
|
20260
|
+
}
|
|
20261
|
+
}
|
|
20262
|
+
function planRetentionPatch(observation, assumptions = {}) {
|
|
20263
|
+
assertRetentionAssumptions(assumptions);
|
|
20264
|
+
const rates = observedRetentionRates(observation);
|
|
20265
|
+
if (Object.keys(rates).length === 0)
|
|
20266
|
+
return { status: "unavailable", retention: {}, warnings: ["No retention day has been fully observed."] };
|
|
20267
|
+
const merged = { ...assumptions, ...rates };
|
|
20268
|
+
const warnings = [];
|
|
20269
|
+
for (const day of RETENTION_DAYS) {
|
|
20270
|
+
if (merged[`d${day}`] === undefined)
|
|
20271
|
+
warnings.push(`Unobserved D${day} has no explicit retained assumption. An LTV default could conflict with the observations; supply monetization.retention.d${day} in the scenario or observe this day before applying a patch.`);
|
|
20272
|
+
}
|
|
20273
|
+
let previous;
|
|
20274
|
+
for (const day of RETENTION_DAYS) {
|
|
20275
|
+
const rate = merged[`d${day}`];
|
|
20276
|
+
if (rate === undefined)
|
|
20277
|
+
continue;
|
|
20278
|
+
if (previous && previous.rate < rate)
|
|
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.`);
|
|
20280
|
+
previous = { day, rate };
|
|
20281
|
+
}
|
|
20282
|
+
return warnings.length ? { status: "requires-review", retention: {}, warnings } : { status: "ready", retention: rates, warnings };
|
|
20283
|
+
}
|
|
20284
|
+
function compareRetention(observation, assumptions) {
|
|
20285
|
+
assertCohortObservation(observation);
|
|
20286
|
+
assertRetentionAssumptions(assumptions);
|
|
20287
|
+
return observation.retention.map((row) => {
|
|
20288
|
+
const assumption = assumptions[`d${row.day}`] ?? null;
|
|
20289
|
+
return {
|
|
20290
|
+
day: row.day,
|
|
20291
|
+
assumption,
|
|
20292
|
+
observed: row.rate,
|
|
20293
|
+
differencePercentagePoints: row.rate === null || assumption === null ? null : (row.rate - assumption) * 100,
|
|
20294
|
+
status: row.rate === null ? "not-observed" : assumption === null ? "unconfigured" : "compared"
|
|
20295
|
+
};
|
|
20296
|
+
});
|
|
20297
|
+
}
|
|
20298
|
+
var RETENTION_DAYS;
|
|
20299
|
+
var init_cohort = __esm(() => {
|
|
20300
|
+
RETENTION_DAYS = Object.freeze([1, 7, 30, 90]);
|
|
20301
|
+
});
|
|
20302
|
+
|
|
19800
20303
|
// ../core/dist/index.js
|
|
19801
20304
|
var init_dist2 = __esm(() => {
|
|
19802
20305
|
init_types();
|
|
@@ -19863,15 +20366,18 @@ var init_dist2 = __esm(() => {
|
|
|
19863
20366
|
init_flow();
|
|
19864
20367
|
init_jevAdvisory();
|
|
19865
20368
|
init_public();
|
|
20369
|
+
init_cohort();
|
|
19866
20370
|
});
|
|
19867
20371
|
|
|
19868
20372
|
// src/runtime/bun.ts
|
|
19869
20373
|
var {$ } = globalThis.Bun;
|
|
19870
20374
|
import { dirname } from "path";
|
|
19871
20375
|
async function readTextFile(path) {
|
|
20376
|
+
recordInputRead(path);
|
|
19872
20377
|
return Bun.file(path).text();
|
|
19873
20378
|
}
|
|
19874
20379
|
async function readJsonFile(path) {
|
|
20380
|
+
recordInputRead(path);
|
|
19875
20381
|
return Bun.file(path).json();
|
|
19876
20382
|
}
|
|
19877
20383
|
async function writeTextFile(path, body) {
|
|
@@ -19921,6 +20427,7 @@ function runText(args, opts) {
|
|
|
19921
20427
|
var MAX_CAPTURE_BYTES;
|
|
19922
20428
|
var init_bun = __esm(() => {
|
|
19923
20429
|
init_errors3();
|
|
20430
|
+
init_invocation();
|
|
19924
20431
|
MAX_CAPTURE_BYTES = 8 * 1024 * 1024;
|
|
19925
20432
|
});
|
|
19926
20433
|
|
|
@@ -19928,7 +20435,7 @@ var init_bun = __esm(() => {
|
|
|
19928
20435
|
var require_package = __commonJS(function(exports, module) {
|
|
19929
20436
|
module.exports = {
|
|
19930
20437
|
name: "@idlekit/cli",
|
|
19931
|
-
version: "0.
|
|
20438
|
+
version: "0.7.0",
|
|
19932
20439
|
description: "Bun-first idk CLI for idle game scenario validation, simulation, tuning, and reporting.",
|
|
19933
20440
|
license: "MIT",
|
|
19934
20441
|
type: "module",
|
|
@@ -19981,7 +20488,7 @@ var require_package = __commonJS(function(exports, module) {
|
|
|
19981
20488
|
"@clack/prompts": "1.8.1",
|
|
19982
20489
|
"@gunshi/plugin-completion": "0.37.3",
|
|
19983
20490
|
"@gunshi/plugin-suggestion": "0.37.3",
|
|
19984
|
-
"@idlekit/core": "0.
|
|
20491
|
+
"@idlekit/core": "0.7.0",
|
|
19985
20492
|
ajv: "^8.20.0",
|
|
19986
20493
|
gunshi: "0.37.3",
|
|
19987
20494
|
"proper-lockfile": "4.1.2",
|
|
@@ -19996,7 +20503,7 @@ var require_package = __commonJS(function(exports, module) {
|
|
|
19996
20503
|
|
|
19997
20504
|
// src/runtime/selfCli.ts
|
|
19998
20505
|
import { existsSync } from "fs";
|
|
19999
|
-
import { dirname as dirname3, resolve as
|
|
20506
|
+
import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
20000
20507
|
function currentEntry() {
|
|
20001
20508
|
return Bun.main;
|
|
20002
20509
|
}
|
|
@@ -20013,11 +20520,11 @@ function cliPackageRoot(entry = currentEntry()) {
|
|
|
20013
20520
|
if (isNativeEntry(entry))
|
|
20014
20521
|
return process.cwd();
|
|
20015
20522
|
if (isBundledCliProcess(entry))
|
|
20016
|
-
return
|
|
20017
|
-
return
|
|
20523
|
+
return resolve3(dirname3(entry), "..");
|
|
20524
|
+
return resolve3(import.meta.dir, "../..");
|
|
20018
20525
|
}
|
|
20019
20526
|
function bundledCliConfig(entry) {
|
|
20020
|
-
const config =
|
|
20527
|
+
const config = resolve3(dirname3(entry), "../../../tools/bundled-cli-bunfig.toml");
|
|
20021
20528
|
if (!existsSync(config))
|
|
20022
20529
|
return;
|
|
20023
20530
|
return config;
|
|
@@ -20032,7 +20539,7 @@ function selfCliCommand(args, entry = currentEntry()) {
|
|
|
20032
20539
|
return [bun, `--config=${config}`, entry, ...args];
|
|
20033
20540
|
return [bun, entry, ...args];
|
|
20034
20541
|
}
|
|
20035
|
-
const bunfigApplies =
|
|
20542
|
+
const bunfigApplies = resolve3(process.cwd()) === CLI_ROOT;
|
|
20036
20543
|
if (entry.endsWith(".ts") && !bunfigApplies) {
|
|
20037
20544
|
return [bun, "--preload", "@ttsc/unplugin/bun-register", entry, ...args];
|
|
20038
20545
|
}
|
|
@@ -20054,16 +20561,16 @@ function runSelfCli(args) {
|
|
|
20054
20561
|
}
|
|
20055
20562
|
var CLI_ROOT, MAX_CAPTURE_BYTES2;
|
|
20056
20563
|
var init_selfCli = __esm(() => {
|
|
20057
|
-
CLI_ROOT =
|
|
20564
|
+
CLI_ROOT = resolve3(import.meta.dir, "../..");
|
|
20058
20565
|
MAX_CAPTURE_BYTES2 = 8 * 1024 * 1024;
|
|
20059
20566
|
});
|
|
20060
20567
|
|
|
20061
20568
|
// src/io/outputMeta.ts
|
|
20062
|
-
import { dirname as dirname4, resolve as
|
|
20569
|
+
import { dirname as dirname4, resolve as resolve4 } from "path";
|
|
20063
20570
|
function repoRoot() {
|
|
20064
20571
|
if (isBundledCliProcess())
|
|
20065
|
-
return
|
|
20066
|
-
return
|
|
20572
|
+
return resolve4(dirname4(Bun.main), "../..");
|
|
20573
|
+
return resolve4(import.meta.dir, "../../..");
|
|
20067
20574
|
}
|
|
20068
20575
|
function stableStringify(value) {
|
|
20069
20576
|
if (value === null || typeof value !== "object") {
|
|
@@ -28787,7 +29294,7 @@ var init_jev_schema = __esm(() => {
|
|
|
28787
29294
|
|
|
28788
29295
|
// src/lib/evaluation/providers/jev.ts
|
|
28789
29296
|
import { closeSync, lstatSync, mkdirSync, openSync, readFileSync, readlinkSync, realpathSync as realpathSync2, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
28790
|
-
import { basename as basename2, dirname as dirname5, resolve as
|
|
29297
|
+
import { basename as basename2, dirname as dirname5, resolve as resolve7 } from "path";
|
|
28791
29298
|
function pathEnd(value, start, run) {
|
|
28792
29299
|
const end = start + run.length;
|
|
28793
29300
|
if (FILE_COMPONENT.test(run))
|
|
@@ -28844,19 +29351,18 @@ function isSafeJevReport(report, keyMaterial) {
|
|
|
28844
29351
|
return JSON.stringify(redact(report, keyMaterial)) === JSON.stringify(report);
|
|
28845
29352
|
}
|
|
28846
29353
|
function projectJevState(artifact, rubric, keyMaterial) {
|
|
28847
|
-
const
|
|
28848
|
-
const
|
|
28849
|
-
|
|
28850
|
-
if (
|
|
28851
|
-
|
|
28852
|
-
|
|
28853
|
-
|
|
28854
|
-
});
|
|
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));
|
|
28855
29361
|
const coverage = artifact.observationCoverage;
|
|
28856
29362
|
const judged = judgeArtifact(artifact, rubric);
|
|
28857
29363
|
const verdicts = new Map(judged.ok ? judged.report.numerical.results.map((result) => [result.id, result.verdict]) : []);
|
|
28858
29364
|
const withheld = coverage === "incomplete" || coverage === "unknown" || coverage === "disabled" || artifact.capabilities.metrics !== "statically-known";
|
|
28859
|
-
const metrics = firstReadings.flatMap((metric) =>
|
|
29365
|
+
const metrics = firstReadings.flatMap((metric) => (rulesByReading.get(metric) ?? []).map((rule) => {
|
|
28860
29366
|
const { observation } = toObservation(artifact, metric, rule);
|
|
28861
29367
|
return {
|
|
28862
29368
|
...observation.identity,
|
|
@@ -29092,14 +29598,14 @@ function cacheTarget(path, depth = 0) {
|
|
|
29092
29598
|
} catch {
|
|
29093
29599
|
try {
|
|
29094
29600
|
if (lstatSync(path).isSymbolicLink())
|
|
29095
|
-
return cacheTarget(
|
|
29601
|
+
return cacheTarget(resolve7(dirname5(path), readlinkSync(path)), depth + 1);
|
|
29096
29602
|
} catch (error) {
|
|
29097
29603
|
if (error.code !== "ENOENT")
|
|
29098
29604
|
throw error;
|
|
29099
29605
|
}
|
|
29100
|
-
const absolute =
|
|
29606
|
+
const absolute = resolve7(path);
|
|
29101
29607
|
const parent = dirname5(absolute);
|
|
29102
|
-
return parent === absolute ? absolute :
|
|
29608
|
+
return parent === absolute ? absolute : resolve7(cacheTarget(parent, depth), basename2(absolute));
|
|
29103
29609
|
}
|
|
29104
29610
|
}
|
|
29105
29611
|
async function writeCache(requestedPath, entry) {
|
|
@@ -34053,6 +34559,7 @@ function getTerminalInfo() {
|
|
|
34053
34559
|
}
|
|
34054
34560
|
|
|
34055
34561
|
// src/runtime/command.ts
|
|
34562
|
+
init_invocation();
|
|
34056
34563
|
function option(schema, metadata = {}) {
|
|
34057
34564
|
return { schema, ...metadata };
|
|
34058
34565
|
}
|
|
@@ -34173,14 +34680,15 @@ async function createCLI(config) {
|
|
|
34173
34680
|
throw usageError(`Invalid --${key}: ${parsed.error.message}`);
|
|
34174
34681
|
flags[key] = parsed.data;
|
|
34175
34682
|
}
|
|
34176
|
-
|
|
34683
|
+
const positional = [...ctx.positionals.slice(ctx.commandPath.length), ...ctx.rest];
|
|
34684
|
+
await runWithInvocation({ positional, flags }, () => selected.handler({
|
|
34177
34685
|
flags,
|
|
34178
|
-
positional
|
|
34686
|
+
positional,
|
|
34179
34687
|
terminal: getTerminalInfo(),
|
|
34180
34688
|
prompt,
|
|
34181
34689
|
cwd: process.cwd(),
|
|
34182
34690
|
runtime: { args: [...ctx._] }
|
|
34183
|
-
});
|
|
34691
|
+
}));
|
|
34184
34692
|
}
|
|
34185
34693
|
});
|
|
34186
34694
|
};
|
|
@@ -34251,8 +34759,9 @@ init_zod();
|
|
|
34251
34759
|
// src/plugin/load.ts
|
|
34252
34760
|
init_dist2();
|
|
34253
34761
|
init_bun();
|
|
34762
|
+
init_invocation();
|
|
34254
34763
|
import { realpathSync } from "fs";
|
|
34255
|
-
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";
|
|
34256
34765
|
import { fileURLToPath } from "url";
|
|
34257
34766
|
|
|
34258
34767
|
// src/lib/designObjectives.ts
|
|
@@ -34264,7 +34773,7 @@ init_dist2();
|
|
|
34264
34773
|
function quantile(values, q) {
|
|
34265
34774
|
return quantileInclusiveFloor(values, q) ?? undefined;
|
|
34266
34775
|
}
|
|
34267
|
-
function
|
|
34776
|
+
function quantileKey2(quantiles, q) {
|
|
34268
34777
|
const percent = Math.round(q * 100);
|
|
34269
34778
|
const legacy = `q${percent}`;
|
|
34270
34779
|
const collided = quantiles.some((other) => other !== q && `q${Math.round(other * 100)}` === legacy);
|
|
@@ -34277,7 +34786,7 @@ function summarizeNumeric(values, quantiles) {
|
|
|
34277
34786
|
return null;
|
|
34278
34787
|
return {
|
|
34279
34788
|
mean: values.reduce((sum, value) => sum + value, 0) / values.length,
|
|
34280
|
-
quantiles: Object.fromEntries(quantiles.map((q) => [
|
|
34789
|
+
quantiles: Object.fromEntries(quantiles.map((q) => [quantileKey2(quantiles, q), quantileInclusiveFloor(values, q) ?? Number.NaN]))
|
|
34281
34790
|
};
|
|
34282
34791
|
}
|
|
34283
34792
|
function resolveSessionPatternSpec(args) {
|
|
@@ -34918,10 +35427,11 @@ init_errors3();
|
|
|
34918
35427
|
function ownedCount(state) {
|
|
34919
35428
|
return Number(state?.vars?.owned ?? 0);
|
|
34920
35429
|
}
|
|
35430
|
+
var NUMBER_ONLY_COMMANDS = ["report", "analyze", "eta", "growth", "prestige-cycle"];
|
|
34921
35431
|
function finiteLinearAmount(E, value, label) {
|
|
34922
35432
|
if (!E.isFinite(value)) {
|
|
34923
|
-
throw cliError("SCENARIO_INVALID", `linear ${label} exceeds the selected engine's finite range. Use --engine breakInfinity with simulate/evaluate/experience/ltv for a large economy, or reduce the inputs.`, {
|
|
34924
|
-
hint: "
|
|
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.`, {
|
|
35434
|
+
hint: `${NUMBER_ONLY_COMMANDS.join(", ")} run only the number engine; reduce their inputs.`
|
|
34925
35435
|
});
|
|
34926
35436
|
}
|
|
34927
35437
|
return value;
|
|
@@ -35157,7 +35667,7 @@ function normalizeSha256(input) {
|
|
|
35157
35667
|
return x;
|
|
35158
35668
|
}
|
|
35159
35669
|
function parsePluginRoots(input) {
|
|
35160
|
-
const list = parseCommaSeparated(input).map((x) =>
|
|
35670
|
+
const list = parseCommaSeparated(input).map((x) => resolve2(x));
|
|
35161
35671
|
return [...new Set(list)];
|
|
35162
35672
|
}
|
|
35163
35673
|
function parsePluginSha256(input) {
|
|
@@ -35170,7 +35680,7 @@ function parsePluginSha256(input) {
|
|
|
35170
35680
|
}
|
|
35171
35681
|
const key = entry.slice(0, idx).trim();
|
|
35172
35682
|
const value = entry.slice(idx + 1).trim();
|
|
35173
|
-
const abs =
|
|
35683
|
+
const abs = resolve2(key);
|
|
35174
35684
|
const digest = normalizeSha256(value);
|
|
35175
35685
|
if (out[abs] && out[abs] !== digest) {
|
|
35176
35686
|
throw new Error(`Conflicting sha256 values for plugin path: ${key}`);
|
|
@@ -35182,7 +35692,7 @@ function parsePluginSha256(input) {
|
|
|
35182
35692
|
function parsePluginSecurityOptions(input) {
|
|
35183
35693
|
const allowedRoots = parsePluginRoots(input.roots);
|
|
35184
35694
|
const requiredSha256 = parsePluginSha256(input.sha256);
|
|
35185
|
-
const trustFile = typeof input.trustFile === "string" && input.trustFile.trim().length > 0 ?
|
|
35695
|
+
const trustFile = typeof input.trustFile === "string" && input.trustFile.trim().length > 0 ? resolve2(input.trustFile) : undefined;
|
|
35186
35696
|
return {
|
|
35187
35697
|
allowedRoots,
|
|
35188
35698
|
requiredSha256,
|
|
@@ -35204,7 +35714,7 @@ async function loadPluginTrustFile(pathAbs) {
|
|
|
35204
35714
|
if (typeof v !== "string")
|
|
35205
35715
|
continue;
|
|
35206
35716
|
const digest = normalizeSha256(v);
|
|
35207
|
-
const absPath = isAbsolute(k) ?
|
|
35717
|
+
const absPath = isAbsolute(k) ? resolve2(k) : resolve2(baseDir, k);
|
|
35208
35718
|
out[absPath] = digest;
|
|
35209
35719
|
}
|
|
35210
35720
|
return out;
|
|
@@ -35230,7 +35740,7 @@ async function loadRegistries(pluginPaths = [], securityOptions = {}) {
|
|
|
35230
35740
|
let requiredSha256;
|
|
35231
35741
|
let requiredClosureSha256;
|
|
35232
35742
|
try {
|
|
35233
|
-
allowedRoots = (securityOptions.allowedRoots ?? []).map((x) =>
|
|
35743
|
+
allowedRoots = (securityOptions.allowedRoots ?? []).map((x) => resolve2(x));
|
|
35234
35744
|
const trustFileSha256 = securityOptions.trustFile !== undefined ? await loadPluginTrustFile(securityOptions.trustFile) : {};
|
|
35235
35745
|
requiredSha256 = mergeShaPolicies(trustFileSha256, securityOptions.requiredSha256 ?? {});
|
|
35236
35746
|
requiredClosureSha256 = mergeShaPolicies({}, securityOptions.requiredClosureSha256 ?? {});
|
|
@@ -35327,6 +35837,7 @@ function isPathInsideRoot(pathAbs, rootAbs) {
|
|
|
35327
35837
|
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
35328
35838
|
}
|
|
35329
35839
|
async function sha256File(pathAbs) {
|
|
35840
|
+
recordInputRead(pathAbs);
|
|
35330
35841
|
const buffer = await Bun.file(pathAbs).bytes();
|
|
35331
35842
|
return sha256Hex(buffer);
|
|
35332
35843
|
}
|
|
@@ -35366,11 +35877,16 @@ async function pluginClosureDigest(entryAbs, entryDigest) {
|
|
|
35366
35877
|
return sha256Hex(listing.join(`
|
|
35367
35878
|
`));
|
|
35368
35879
|
}
|
|
35880
|
+
async function recordPluginClosureReads(entryAbs) {
|
|
35881
|
+
try {
|
|
35882
|
+
await pluginClosureDigest(entryAbs, await sha256File(entryAbs));
|
|
35883
|
+
} catch {}
|
|
35884
|
+
}
|
|
35369
35885
|
async function resolveAndValidatePluginPath(input, allowedRoots) {
|
|
35370
35886
|
if (input.includes("://")) {
|
|
35371
35887
|
throw new Error(`Plugin path must be a local file path: ${input}`);
|
|
35372
35888
|
}
|
|
35373
|
-
const abs =
|
|
35889
|
+
const abs = resolve2(input);
|
|
35374
35890
|
const ext = extname(abs).toLowerCase();
|
|
35375
35891
|
if (!ALLOWED_PLUGIN_EXTENSIONS.has(ext)) {
|
|
35376
35892
|
throw new Error(`Unsupported plugin extension '${ext}' for ${input}`);
|
|
@@ -35420,7 +35936,7 @@ init_outputMeta();
|
|
|
35420
35936
|
|
|
35421
35937
|
// src/io/readScenario.ts
|
|
35422
35938
|
init_dist2();
|
|
35423
|
-
import { extname as extname2, resolve as
|
|
35939
|
+
import { extname as extname2, resolve as resolve5 } from "path";
|
|
35424
35940
|
|
|
35425
35941
|
// ../../node_modules/.bun/yaml@2.9.1/node_modules/yaml/dist/index.js
|
|
35426
35942
|
var exports_dist2 = {};
|
|
@@ -35539,7 +36055,7 @@ async function readScenarioFile(path) {
|
|
|
35539
36055
|
return out.value;
|
|
35540
36056
|
}
|
|
35541
36057
|
async function readScenarioFileWithMeta(path) {
|
|
35542
|
-
const abs =
|
|
36058
|
+
const abs = resolve5(path);
|
|
35543
36059
|
const raw = await readTextFile(abs).catch((error) => {
|
|
35544
36060
|
throw scenarioReadFailedError(abs, error);
|
|
35545
36061
|
});
|
|
@@ -35561,7 +36077,8 @@ async function readScenarioFileWithMeta(path) {
|
|
|
35561
36077
|
// src/io/writeOutput.ts
|
|
35562
36078
|
init_errors3();
|
|
35563
36079
|
init_bun();
|
|
35564
|
-
|
|
36080
|
+
init_invocation();
|
|
36081
|
+
import { resolve as resolve6 } from "path";
|
|
35565
36082
|
import { realpath, stat } from "fs/promises";
|
|
35566
36083
|
function toCsv(data) {
|
|
35567
36084
|
if (!Array.isArray(data)) {
|
|
@@ -35624,6 +36141,39 @@ function renderOutput(format, data) {
|
|
|
35624
36141
|
return toMarkdown(data);
|
|
35625
36142
|
return JSON.stringify(data, null, 2);
|
|
35626
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
|
+
}
|
|
35627
36177
|
async function writeOutput(args) {
|
|
35628
36178
|
const dataWithMeta = args.meta && args.format === "json" && typeof args.data === "object" && args.data !== null && !Array.isArray(args.data) ? {
|
|
35629
36179
|
...args.data,
|
|
@@ -35635,28 +36185,7 @@ async function writeOutput(args) {
|
|
|
35635
36185
|
`);
|
|
35636
36186
|
return;
|
|
35637
36187
|
}
|
|
35638
|
-
const abs =
|
|
35639
|
-
for (const input of args.protectedInputs ?? []) {
|
|
35640
|
-
const source = resolve5(input);
|
|
35641
|
-
let same = source === abs;
|
|
35642
|
-
if (!same) {
|
|
35643
|
-
try {
|
|
35644
|
-
const [outputReal, inputReal, outputStat, inputStat] = await Promise.all([
|
|
35645
|
-
realpath(abs),
|
|
35646
|
-
realpath(source),
|
|
35647
|
-
stat(abs, { bigint: true }),
|
|
35648
|
-
stat(source, { bigint: true })
|
|
35649
|
-
]);
|
|
35650
|
-
same = outputReal === inputReal || outputStat.ino !== 0n && outputStat.dev === inputStat.dev && outputStat.ino === inputStat.ino;
|
|
35651
|
-
} catch (error) {
|
|
35652
|
-
const code = error.code;
|
|
35653
|
-
if (code !== "ENOENT" && code !== "ENOTDIR")
|
|
35654
|
-
throw error;
|
|
35655
|
-
}
|
|
35656
|
-
}
|
|
35657
|
-
if (same)
|
|
35658
|
-
throw usageError(`Output path must not overwrite an input file: ${input}`);
|
|
35659
|
-
}
|
|
36188
|
+
const abs = await assertOutputNotInput(args.outPath, { protectedInputs: args.protectedInputs });
|
|
35660
36189
|
await writeTextFile(abs, body);
|
|
35661
36190
|
console.log(`Wrote ${args.format} output to ${abs}`);
|
|
35662
36191
|
}
|
|
@@ -36508,7 +37037,7 @@ init_errors3();
|
|
|
36508
37037
|
init_outputMeta();
|
|
36509
37038
|
init_bun();
|
|
36510
37039
|
import { closeSync as closeSync2, lstatSync as lstatSync2, openSync as openSync2, readlinkSync as readlinkSync2, realpathSync as realpathSync3, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
36511
|
-
import { basename as basename3, dirname as dirname6, resolve as
|
|
37040
|
+
import { basename as basename3, dirname as dirname6, resolve as resolve8 } from "path";
|
|
36512
37041
|
|
|
36513
37042
|
// src/lib/evaluation/input.ts
|
|
36514
37043
|
init_dist2();
|
|
@@ -36538,17 +37067,17 @@ function evaluateRules(input) {
|
|
|
36538
37067
|
|
|
36539
37068
|
// src/commands/judge.ts
|
|
36540
37069
|
function canonical(path, depth = 0) {
|
|
36541
|
-
const absolute =
|
|
37070
|
+
const absolute = resolve8(path);
|
|
36542
37071
|
try {
|
|
36543
37072
|
return realpathSync3(absolute);
|
|
36544
37073
|
} catch {
|
|
36545
37074
|
try {
|
|
36546
37075
|
if (depth < 32 && lstatSync2(absolute).isSymbolicLink()) {
|
|
36547
|
-
return canonical(
|
|
37076
|
+
return canonical(resolve8(dirname6(absolute), readlinkSync2(absolute)), depth + 1);
|
|
36548
37077
|
}
|
|
36549
37078
|
} catch {}
|
|
36550
37079
|
const parent = dirname6(absolute);
|
|
36551
|
-
return parent === absolute ? absolute :
|
|
37080
|
+
return parent === absolute ? absolute : resolve8(canonical(parent, depth), basename3(absolute));
|
|
36552
37081
|
}
|
|
36553
37082
|
}
|
|
36554
37083
|
function existingDirectory(path) {
|
|
@@ -36567,12 +37096,12 @@ function existingDirectory(path) {
|
|
|
36567
37096
|
}
|
|
36568
37097
|
function ignoresCase(directory) {
|
|
36569
37098
|
const name = `.idlekit-case-${crypto.randomUUID()}`;
|
|
36570
|
-
const path =
|
|
37099
|
+
const path = resolve8(directory, name);
|
|
36571
37100
|
let fd;
|
|
36572
37101
|
try {
|
|
36573
37102
|
fd = openSync2(path, "wx");
|
|
36574
37103
|
const original = statSync(path);
|
|
36575
|
-
const folded = statSync(
|
|
37104
|
+
const folded = statSync(resolve8(directory, name.toUpperCase()));
|
|
36576
37105
|
return original.dev === folded.dev && original.ino === folded.ino;
|
|
36577
37106
|
} catch {
|
|
36578
37107
|
return fd === undefined && process.platform === "win32";
|
|
@@ -36586,7 +37115,7 @@ function ignoresCase(directory) {
|
|
|
36586
37115
|
}
|
|
36587
37116
|
}
|
|
36588
37117
|
}
|
|
36589
|
-
function
|
|
37118
|
+
function sameFile2(left, right) {
|
|
36590
37119
|
const aPath = canonical(left);
|
|
36591
37120
|
const bPath = canonical(right);
|
|
36592
37121
|
if (aPath === bPath)
|
|
@@ -36606,7 +37135,7 @@ function sameFile(left, right) {
|
|
|
36606
37135
|
function ancestorFile(parent, child) {
|
|
36607
37136
|
let directory = dirname6(canonical(child));
|
|
36608
37137
|
for (;; ) {
|
|
36609
|
-
if (
|
|
37138
|
+
if (sameFile2(parent, directory))
|
|
36610
37139
|
return true;
|
|
36611
37140
|
const next = dirname6(directory);
|
|
36612
37141
|
if (next === directory)
|
|
@@ -36638,6 +37167,17 @@ function requireFileTarget(path, flag) {
|
|
|
36638
37167
|
current = parent;
|
|
36639
37168
|
}
|
|
36640
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
|
+
}
|
|
36641
37181
|
function renderJudgeMarkdown(report) {
|
|
36642
37182
|
const lines = [
|
|
36643
37183
|
"# Rules judge",
|
|
@@ -36651,9 +37191,10 @@ function renderJudgeMarkdown(report) {
|
|
|
36651
37191
|
"## Numerical",
|
|
36652
37192
|
""
|
|
36653
37193
|
];
|
|
36654
|
-
|
|
36655
|
-
|
|
36656
|
-
|
|
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
|
+
});
|
|
36657
37198
|
lines.push("", "## Estimates", "");
|
|
36658
37199
|
if (report.estimatedObservations.length === 0)
|
|
36659
37200
|
lines.push("None.");
|
|
@@ -36662,7 +37203,7 @@ function renderJudgeMarkdown(report) {
|
|
|
36662
37203
|
}
|
|
36663
37204
|
lines.push("", "## Semantic", "");
|
|
36664
37205
|
for (const diagnostic of report.diagnostics) {
|
|
36665
|
-
lines.push(`- ${diagnostic.status} ${diagnostic.recommendationId}: ${diagnostic.text.en}`);
|
|
37206
|
+
lines.push(`- ${diagnostic.status} ${diagnostic.recommendationId}${versionLabel(diagnostic)}: ${diagnostic.text.en}`);
|
|
36666
37207
|
}
|
|
36667
37208
|
return lines.join(`
|
|
36668
37209
|
`);
|
|
@@ -36682,7 +37223,8 @@ function judgeCsvRows(report) {
|
|
|
36682
37223
|
threshold: result.evidence.threshold,
|
|
36683
37224
|
upperThreshold: result.evidence.upperThreshold,
|
|
36684
37225
|
diagnosticStatus: diagnostic?.status ?? null,
|
|
36685
|
-
recommendationId: diagnostic?.recommendationId ?? null
|
|
37226
|
+
recommendationId: diagnostic?.recommendationId ?? null,
|
|
37227
|
+
metricVersion: readMetricVersion(diagnostic)
|
|
36686
37228
|
};
|
|
36687
37229
|
});
|
|
36688
37230
|
}
|
|
@@ -36694,14 +37236,17 @@ async function runJudge(flags, analysisPath, hooks) {
|
|
|
36694
37236
|
if (flags.provider === "jev" && flags.format === "csv") {
|
|
36695
37237
|
throw usageError("--provider jev writes json or md. csv cannot hold the rules report and the advisory together.");
|
|
36696
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}`);
|
|
36697
37242
|
if (flags.provider === "jev" && flags.cache) {
|
|
36698
|
-
if (flags.out &&
|
|
37243
|
+
if (flags.out && sameFile2(flags.cache, flags.out)) {
|
|
36699
37244
|
throw usageError("--cache and --out name the same file. Give the Jev cache its own path.");
|
|
36700
37245
|
}
|
|
36701
37246
|
if (flags.out && (ancestorFile(flags.cache, flags.out) || ancestorFile(flags.out, flags.cache))) {
|
|
36702
37247
|
throw usageError("--cache and --out cannot be ancestor paths. Give each file a separate target.");
|
|
36703
37248
|
}
|
|
36704
|
-
if (
|
|
37249
|
+
if (sameFile2(flags.cache, analysisPath) || sameFile2(flags.cache, flags.rubric)) {
|
|
36705
37250
|
throw usageError("--cache names an input file. Give the Jev cache its own path.");
|
|
36706
37251
|
}
|
|
36707
37252
|
}
|
|
@@ -36734,6 +37279,7 @@ async function runJudge(flags, analysisPath, hooks) {
|
|
|
36734
37279
|
await writeOutput({
|
|
36735
37280
|
format: flags.format,
|
|
36736
37281
|
outPath: flags.out,
|
|
37282
|
+
protectedInputs: [analysisPath, flags.rubric],
|
|
36737
37283
|
data: flags.format === "md" ? renderJudgeMarkdown(report) : flags.format === "csv" ? judgeCsvRows(report) : report
|
|
36738
37284
|
});
|
|
36739
37285
|
return report;
|
|
@@ -36773,20 +37319,13 @@ async function runJudge(flags, analysisPath, hooks) {
|
|
|
36773
37319
|
...advisory.answers.length === 0 ? ["None."] : []
|
|
36774
37320
|
].join(`
|
|
36775
37321
|
`);
|
|
36776
|
-
|
|
36777
|
-
const outPath = resolve7(flags.out);
|
|
36778
|
-
await writeTextFile(outPath, `${markdown}
|
|
36779
|
-
`);
|
|
36780
|
-
console.log(`Wrote md output to ${outPath}`);
|
|
36781
|
-
} else {
|
|
36782
|
-
await writeStdout(`${markdown}
|
|
36783
|
-
`);
|
|
36784
|
-
}
|
|
37322
|
+
await writeOutput({ format: "md", outPath: flags.out, data: markdown, protectedInputs: [analysisPath, flags.rubric] });
|
|
36785
37323
|
return bundle;
|
|
36786
37324
|
}
|
|
36787
37325
|
await writeOutput({
|
|
36788
37326
|
format: flags.format,
|
|
36789
37327
|
outPath: flags.out,
|
|
37328
|
+
protectedInputs: [analysisPath, flags.rubric],
|
|
36790
37329
|
data: bundle,
|
|
36791
37330
|
meta: buildOutputMeta({
|
|
36792
37331
|
command: "judge",
|
|
@@ -36827,7 +37366,7 @@ var judge_default = defineCommand({
|
|
|
36827
37366
|
init_zod();
|
|
36828
37367
|
init_errors3();
|
|
36829
37368
|
init_outputMeta();
|
|
36830
|
-
import { extname as extname3, resolve as
|
|
37369
|
+
import { extname as extname3, resolve as resolve9 } from "path";
|
|
36831
37370
|
|
|
36832
37371
|
// src/lib/ltvCalibration.ts
|
|
36833
37372
|
function assertFiniteNumbers(value, path) {
|
|
@@ -36858,18 +37397,50 @@ function clampCorrelation2(v) {
|
|
|
36858
37397
|
function mean(values) {
|
|
36859
37398
|
if (values.length === 0)
|
|
36860
37399
|
return 0;
|
|
36861
|
-
|
|
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;
|
|
36862
37438
|
}
|
|
36863
37439
|
function variance(values) {
|
|
36864
37440
|
if (values.length === 0)
|
|
36865
37441
|
return 0;
|
|
36866
|
-
const
|
|
36867
|
-
|
|
36868
|
-
for (const v of values) {
|
|
36869
|
-
const d = v - m;
|
|
36870
|
-
acc += d * d;
|
|
36871
|
-
}
|
|
36872
|
-
return acc / values.length;
|
|
37442
|
+
const { vx, scaleX } = moments(values, values);
|
|
37443
|
+
return scaledVariance(vx, scaleX, values.length);
|
|
36873
37444
|
}
|
|
36874
37445
|
function estimateCorrelation(x, y) {
|
|
36875
37446
|
const n = Math.min(x.length, y.length);
|
|
@@ -36884,23 +37455,11 @@ function estimateCorrelation(x, y) {
|
|
|
36884
37455
|
varianceY: 0
|
|
36885
37456
|
};
|
|
36886
37457
|
}
|
|
36887
|
-
const
|
|
36888
|
-
const
|
|
36889
|
-
const
|
|
36890
|
-
const
|
|
36891
|
-
|
|
36892
|
-
let vx = 0;
|
|
36893
|
-
let vy = 0;
|
|
36894
|
-
for (let i = 0;i < n; i++) {
|
|
36895
|
-
const dx = (sx[i] ?? 0) - mx;
|
|
36896
|
-
const dy = (sy[i] ?? 0) - my;
|
|
36897
|
-
cov += dx * dy;
|
|
36898
|
-
vx += dx * dx;
|
|
36899
|
-
vy += dy * dy;
|
|
36900
|
-
}
|
|
36901
|
-
const varianceX = vx / n;
|
|
36902
|
-
const varianceY = vy / n;
|
|
36903
|
-
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)) {
|
|
36904
37463
|
return {
|
|
36905
37464
|
raw: 0,
|
|
36906
37465
|
value: 0,
|
|
@@ -36930,18 +37489,53 @@ function estimateCorrelation(x, y) {
|
|
|
36930
37489
|
varianceY
|
|
36931
37490
|
};
|
|
36932
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
|
+
}
|
|
36933
37513
|
function calibrateMonetization(rows) {
|
|
36934
37514
|
if (rows.length === 0) {
|
|
36935
37515
|
throw new Error("calibration rows cannot be empty");
|
|
36936
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;
|
|
36937
37531
|
const users = new Map;
|
|
36938
37532
|
for (const row of rows) {
|
|
36939
37533
|
const day = Math.max(0, Math.floor(row.day));
|
|
36940
37534
|
const u = users.get(row.userId) ?? { days: new Set, iap: 0, ad: 0, acq: undefined };
|
|
36941
|
-
if (row.active ?? true)
|
|
37535
|
+
if ((row.active ?? true) || day === 0)
|
|
36942
37536
|
u.days.add(day);
|
|
36943
|
-
u.iap += Math.max(0, row.iapRevenue);
|
|
36944
|
-
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);
|
|
36945
37539
|
if (row.acquisitionCost !== undefined && Number.isFinite(row.acquisitionCost)) {
|
|
36946
37540
|
u.acq = (u.acq ?? 0) + Math.max(0, row.acquisitionCost);
|
|
36947
37541
|
}
|
|
@@ -36986,52 +37580,25 @@ function calibrateMonetization(rows) {
|
|
|
36986
37580
|
const adArpDau = totalAd / Math.max(1, activeUserDays);
|
|
36987
37581
|
const cpi = totalAcq / Math.max(1, acqUsers);
|
|
36988
37582
|
const userRetention = [];
|
|
36989
|
-
const
|
|
36990
|
-
const userArppu = [];
|
|
36991
|
-
const userAdArpDau = [];
|
|
37583
|
+
const features = { conversion: [], arppu: [], adArpDau: [] };
|
|
36992
37584
|
for (const user of users.values()) {
|
|
36993
37585
|
const activeDays = Math.max(1, user.days.size);
|
|
36994
|
-
|
|
36995
|
-
|
|
36996
|
-
|
|
36997
|
-
|
|
36998
|
-
|
|
36999
|
-
|
|
37000
|
-
|
|
37001
|
-
|
|
37002
|
-
|
|
37003
|
-
|
|
37004
|
-
|
|
37005
|
-
|
|
37006
|
-
|
|
37007
|
-
|
|
37008
|
-
|
|
37009
|
-
|
|
37010
|
-
};
|
|
37011
|
-
const estimatedCorrelation = {
|
|
37012
|
-
retentionConversion: estimatedCorrelationPair.retentionConversion.value,
|
|
37013
|
-
retentionArppu: estimatedCorrelationPair.retentionArppu.value,
|
|
37014
|
-
retentionAd: estimatedCorrelationPair.retentionAd.value,
|
|
37015
|
-
conversionArppu: estimatedCorrelationPair.conversionArppu.value,
|
|
37016
|
-
conversionAd: estimatedCorrelationPair.conversionAd.value,
|
|
37017
|
-
arppuAd: estimatedCorrelationPair.arppuAd.value
|
|
37018
|
-
};
|
|
37019
|
-
const estimatedCorrelationRaw = {
|
|
37020
|
-
retentionConversion: estimatedCorrelationPair.retentionConversion.raw,
|
|
37021
|
-
retentionArppu: estimatedCorrelationPair.retentionArppu.raw,
|
|
37022
|
-
retentionAd: estimatedCorrelationPair.retentionAd.raw,
|
|
37023
|
-
conversionArppu: estimatedCorrelationPair.conversionArppu.raw,
|
|
37024
|
-
conversionAd: estimatedCorrelationPair.conversionAd.raw,
|
|
37025
|
-
arppuAd: estimatedCorrelationPair.arppuAd.raw
|
|
37026
|
-
};
|
|
37027
|
-
const correlationConfidence = {
|
|
37028
|
-
retentionConversion: estimatedCorrelationPair.retentionConversion.confidence,
|
|
37029
|
-
retentionArppu: estimatedCorrelationPair.retentionArppu.confidence,
|
|
37030
|
-
retentionAd: estimatedCorrelationPair.retentionAd.confidence,
|
|
37031
|
-
conversionArppu: estimatedCorrelationPair.conversionArppu.confidence,
|
|
37032
|
-
conversionAd: estimatedCorrelationPair.conversionAd.confidence,
|
|
37033
|
-
arppuAd: estimatedCorrelationPair.arppuAd.confidence
|
|
37034
|
-
};
|
|
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");
|
|
37035
37602
|
const result = {
|
|
37036
37603
|
monetization: {
|
|
37037
37604
|
cohorts: {
|
|
@@ -37044,44 +37611,38 @@ function calibrateMonetization(rows) {
|
|
|
37044
37611
|
d90: clamp014(Math.min(d1, d7, d30, d90)),
|
|
37045
37612
|
longTailDailyDecay: 0.02
|
|
37046
37613
|
},
|
|
37047
|
-
|
|
37048
|
-
|
|
37049
|
-
|
|
37050
|
-
|
|
37051
|
-
|
|
37052
|
-
|
|
37053
|
-
},
|
|
37054
|
-
acquisition: {
|
|
37055
|
-
cpi: Math.max(0, cpi)
|
|
37056
|
-
},
|
|
37057
|
-
uncertainty: {
|
|
37058
|
-
enabled: true,
|
|
37059
|
-
draws: 300,
|
|
37060
|
-
quantiles: [0.5, 0.9],
|
|
37061
|
-
sigma: {
|
|
37062
|
-
retention: 0.08,
|
|
37063
|
-
conversion: 0.12,
|
|
37064
|
-
arppu: 0.2,
|
|
37065
|
-
ad: 0.15
|
|
37066
|
-
},
|
|
37067
|
-
correlation: {
|
|
37068
|
-
retentionConversion: estimatedCorrelation.retentionConversion,
|
|
37069
|
-
retentionArppu: estimatedCorrelation.retentionArppu,
|
|
37070
|
-
retentionAd: estimatedCorrelation.retentionAd,
|
|
37071
|
-
conversionArppu: estimatedCorrelation.conversionArppu,
|
|
37072
|
-
conversionAd: estimatedCorrelation.conversionAd,
|
|
37073
|
-
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
|
|
37074
37620
|
}
|
|
37075
|
-
}
|
|
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
|
+
} : {}
|
|
37076
37637
|
},
|
|
37077
37638
|
diagnostics: {
|
|
37078
37639
|
users: cohortSize,
|
|
37079
37640
|
totalRows: rows.length,
|
|
37080
|
-
totalIap,
|
|
37081
|
-
totalAd,
|
|
37641
|
+
...iapMeasured ? { totalIap } : {},
|
|
37642
|
+
...adMeasured ? { totalAd } : {},
|
|
37082
37643
|
activeUserDays,
|
|
37083
|
-
payerUsers,
|
|
37084
|
-
|
|
37644
|
+
...iapMeasured ? { payerUsers, payerDays } : {},
|
|
37645
|
+
...measured.size < 3 ? { unmeasured: ["iapRevenue", "adRevenue", "acquisitionCost"].filter((source) => !measured.has(source)) } : {},
|
|
37085
37646
|
retention: {
|
|
37086
37647
|
d1,
|
|
37087
37648
|
d7,
|
|
@@ -37090,14 +37651,14 @@ function calibrateMonetization(rows) {
|
|
|
37090
37651
|
},
|
|
37091
37652
|
userFeatureVariance: {
|
|
37092
37653
|
retention: variance(userRetention),
|
|
37093
|
-
|
|
37094
|
-
arppu: variance(userArppu),
|
|
37095
|
-
adArpDau: variance(userAdArpDau)
|
|
37654
|
+
...pickMeasured(FEATURE_SOURCES, measured, (key) => variance(features[key]))
|
|
37096
37655
|
},
|
|
37097
|
-
|
|
37098
|
-
|
|
37099
|
-
|
|
37100
|
-
|
|
37656
|
+
...revenueMeasured ? {
|
|
37657
|
+
estimatedCorrelation,
|
|
37658
|
+
estimatedCorrelationRaw: correlationField("raw"),
|
|
37659
|
+
correlationConfidence: correlationField("confidence"),
|
|
37660
|
+
correlationDiagnostics: estimatedCorrelationPair
|
|
37661
|
+
} : {}
|
|
37101
37662
|
}
|
|
37102
37663
|
};
|
|
37103
37664
|
assertFiniteNumbers(result, "calibration");
|
|
@@ -37108,115 +37669,7 @@ init_dist2();
|
|
|
37108
37669
|
// src/lib/ltvUncertainty.ts
|
|
37109
37670
|
init_dist2();
|
|
37110
37671
|
// src/lib/cohortObservation.ts
|
|
37111
|
-
|
|
37112
|
-
function observeCohort(rows, observedThroughDay) {
|
|
37113
|
-
if (!Number.isSafeInteger(observedThroughDay) || observedThroughDay < 0)
|
|
37114
|
-
throw new Error("observed-through-day must be a nonnegative safe integer");
|
|
37115
|
-
if (rows.length === 0)
|
|
37116
|
-
throw new Error("Observed cohort requires at least one install record");
|
|
37117
|
-
const users = new Map;
|
|
37118
|
-
for (const row of rows) {
|
|
37119
|
-
if (!row.userId.trim() || !Number.isSafeInteger(row.day) || row.day < 0 || row.day > observedThroughDay) {
|
|
37120
|
-
throw new Error("Observed cohort requires a user ID and integer days within observed-through-day");
|
|
37121
|
-
}
|
|
37122
|
-
if (![row.iapRevenue, row.adRevenue, ...row.acquisitionCost === undefined ? [] : [row.acquisitionCost]].every((v) => Number.isFinite(v) && v >= 0)) {
|
|
37123
|
-
throw new Error("Observed cohort revenue and acquisition costs must be finite and nonnegative");
|
|
37124
|
-
}
|
|
37125
|
-
if (row.active !== undefined && typeof row.active !== "boolean")
|
|
37126
|
-
throw new Error("Observed cohort active must be boolean");
|
|
37127
|
-
const user = users.get(row.userId) ?? { days: new Set, active: new Set };
|
|
37128
|
-
if (user.days.has(row.day))
|
|
37129
|
-
throw new Error("Observed cohort requires one aggregated row per user and day");
|
|
37130
|
-
user.days.add(row.day);
|
|
37131
|
-
if (row.active ?? true)
|
|
37132
|
-
user.active.add(row.day);
|
|
37133
|
-
users.set(row.userId, user);
|
|
37134
|
-
}
|
|
37135
|
-
for (const user of users.values()) {
|
|
37136
|
-
if (!user.days.has(0))
|
|
37137
|
-
throw new Error("Observed cohort requires a day 0 install record for every user, including inactive users");
|
|
37138
|
-
}
|
|
37139
|
-
const n = users.size;
|
|
37140
|
-
const observation = {
|
|
37141
|
-
observedThroughDay,
|
|
37142
|
-
users: n,
|
|
37143
|
-
retention: RETENTION_DAYS.map((day) => {
|
|
37144
|
-
if (day > observedThroughDay)
|
|
37145
|
-
return { day, status: "not-observed", users: n, activeUsers: null, rate: null, interval95: null };
|
|
37146
|
-
const activeUsers = [...users.values()].filter((user) => user.active.has(day)).length;
|
|
37147
|
-
const rate = activeUsers / n;
|
|
37148
|
-
const z2 = 1.959963984540054 ** 2;
|
|
37149
|
-
const denominator = 1 + z2 / n;
|
|
37150
|
-
const center = (rate + z2 / (2 * n)) / denominator;
|
|
37151
|
-
const radius = Math.sqrt(z2 * (rate * (1 - rate) / n + z2 / (4 * n * n))) / denominator;
|
|
37152
|
-
return { day, status: "observed", users: n, activeUsers, rate, interval95: { min: activeUsers === 0 ? 0 : Math.max(0, center - radius), max: activeUsers === n ? 1 : Math.min(1, center + radius) } };
|
|
37153
|
-
})
|
|
37154
|
-
};
|
|
37155
|
-
assertCohortObservation(observation);
|
|
37156
|
-
return observation;
|
|
37157
|
-
}
|
|
37158
|
-
function assertCohortObservation(observation) {
|
|
37159
|
-
if (!Number.isSafeInteger(observation.users) || observation.users < 1 || !Number.isSafeInteger(observation.observedThroughDay) || observation.observedThroughDay < 0) {
|
|
37160
|
-
throw new Error("Invalid cohort population or observation cutoff");
|
|
37161
|
-
}
|
|
37162
|
-
if (observation.retention.length !== RETENTION_DAYS.length)
|
|
37163
|
-
throw new Error("Cohort retention must contain D1, D7, D30 and D90");
|
|
37164
|
-
for (const [index, point] of observation.retention.entries()) {
|
|
37165
|
-
if (point.day !== RETENTION_DAYS[index] || point.users !== observation.users)
|
|
37166
|
-
throw new Error("Cohort retention days and population must match the observation");
|
|
37167
|
-
const observed = point.day <= observation.observedThroughDay;
|
|
37168
|
-
if (point.status !== (observed ? "observed" : "not-observed"))
|
|
37169
|
-
throw new Error("Cohort retention status must match the observation cutoff");
|
|
37170
|
-
if (!observed) {
|
|
37171
|
-
if (point.activeUsers !== null || point.rate !== null || point.interval95 !== null)
|
|
37172
|
-
throw new Error("Future retention must remain unobserved");
|
|
37173
|
-
continue;
|
|
37174
|
-
}
|
|
37175
|
-
if (point.activeUsers === null || !Number.isSafeInteger(point.activeUsers) || point.activeUsers < 0 || point.activeUsers > point.users || point.rate !== point.activeUsers / point.users) {
|
|
37176
|
-
throw new Error("Retained users and retention rate must match the installed population");
|
|
37177
|
-
}
|
|
37178
|
-
const interval = point.interval95;
|
|
37179
|
-
if (point.rate === null || !interval || !Number.isFinite(interval.min) || !Number.isFinite(interval.max) || interval.min < 0 || interval.max > 1 || interval.min > point.rate || interval.max < point.rate) {
|
|
37180
|
-
throw new Error("Retention confidence interval must be finite and contain the observed rate");
|
|
37181
|
-
}
|
|
37182
|
-
}
|
|
37183
|
-
}
|
|
37184
|
-
function observedRetentionRates(observation) {
|
|
37185
|
-
return Object.fromEntries(observation.retention.filter((row) => row.rate !== null).map((row) => [`d${row.day}`, row.rate]));
|
|
37186
|
-
}
|
|
37187
|
-
function planRetentionPatch(observation, assumptions = {}) {
|
|
37188
|
-
const rates = observedRetentionRates(observation);
|
|
37189
|
-
if (Object.keys(rates).length === 0)
|
|
37190
|
-
return { status: "unavailable", retention: {}, warnings: ["No retention day has been fully observed."] };
|
|
37191
|
-
const merged = { ...assumptions, ...rates };
|
|
37192
|
-
const warnings = [];
|
|
37193
|
-
for (const day of RETENTION_DAYS) {
|
|
37194
|
-
if (merged[`d${day}`] === undefined)
|
|
37195
|
-
warnings.push(`Unobserved D${day} has no explicit retained assumption. An LTV default could conflict with the observations; supply this assumption in --scenario or observe this day before applying a patch.`);
|
|
37196
|
-
}
|
|
37197
|
-
let previous;
|
|
37198
|
-
for (const day of RETENTION_DAYS) {
|
|
37199
|
-
const rate = merged[`d${day}`];
|
|
37200
|
-
if (rate === undefined)
|
|
37201
|
-
continue;
|
|
37202
|
-
if (previous && previous.rate < rate)
|
|
37203
|
-
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.`);
|
|
37204
|
-
previous = { day, rate };
|
|
37205
|
-
}
|
|
37206
|
-
return warnings.length ? { status: "requires-review", retention: {}, warnings } : { status: "ready", retention: rates, warnings };
|
|
37207
|
-
}
|
|
37208
|
-
function compareRetention(observation, assumptions) {
|
|
37209
|
-
return observation.retention.map((row) => {
|
|
37210
|
-
const assumption = assumptions[`d${row.day}`] ?? null;
|
|
37211
|
-
return {
|
|
37212
|
-
day: row.day,
|
|
37213
|
-
assumption,
|
|
37214
|
-
observed: row.rate,
|
|
37215
|
-
differencePercentagePoints: row.rate === null || assumption === null ? null : (row.rate - assumption) * 100,
|
|
37216
|
-
status: row.rate === null ? "not-observed" : assumption === null ? "unconfigured" : "compared"
|
|
37217
|
-
};
|
|
37218
|
-
});
|
|
37219
|
-
}
|
|
37672
|
+
init_dist2();
|
|
37220
37673
|
function renderCohortMarkdown(observation, comparison, patch) {
|
|
37221
37674
|
const percent = (value) => value === null ? "unavailable" : `${(value * 100).toFixed(2)}%`;
|
|
37222
37675
|
const lines = [
|
|
@@ -37348,13 +37801,14 @@ function parseCsvTelemetry(raw, strictCohort = false) {
|
|
|
37348
37801
|
throw usageError("Observed cohort requires explicit user_id and day fields");
|
|
37349
37802
|
const userId = userInput ?? `anon-${i}`;
|
|
37350
37803
|
const dayRaw = dayInput ?? "0";
|
|
37351
|
-
const
|
|
37352
|
-
const
|
|
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;
|
|
37353
37807
|
const activeRaw = pick2(rec, ["active", "is_active"]);
|
|
37354
37808
|
const acqRaw = pick2(rec, ["acquisition_cost", "ua_cost", "cpi"]);
|
|
37355
37809
|
const day = parseNumeric(dayRaw, i + 1, "day");
|
|
37356
|
-
const iapRevenue = parseNumeric(iapRaw, i + 1, "revenue");
|
|
37357
|
-
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");
|
|
37358
37812
|
const acquisitionCost = acqRaw !== undefined ? parseNumeric(acqRaw, i + 1, "acquisition_cost", { allowEmpty: true }) : undefined;
|
|
37359
37813
|
const active = parseActive(activeRaw, strictCohort);
|
|
37360
37814
|
rows.push({
|
|
@@ -37390,11 +37844,14 @@ function parseJsonTelemetry(raw, strictCohort = false) {
|
|
|
37390
37844
|
}
|
|
37391
37845
|
const userId = String(userInput ?? `anon-${idx}`);
|
|
37392
37846
|
const day = Number(dayInput ?? 0);
|
|
37393
|
-
const
|
|
37394
|
-
const
|
|
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);
|
|
37395
37852
|
const acquisitionCost = r.acquisitionCost !== undefined || r.acquisition_cost !== undefined || r.cpi !== undefined ? Number(r.acquisitionCost ?? r.acquisition_cost ?? r.cpi) : undefined;
|
|
37396
37853
|
const active = parseActive(r.active, strictCohort);
|
|
37397
|
-
if (!Number.isFinite(day) || !
|
|
37854
|
+
if (!Number.isFinite(day) || ![iapRevenue, adRevenue].every((v) => v === undefined || Number.isFinite(v))) {
|
|
37398
37855
|
throw cliError("CLI_USAGE", `Invalid numeric value in json row ${idx}`);
|
|
37399
37856
|
}
|
|
37400
37857
|
rows.push({
|
|
@@ -37429,7 +37886,7 @@ var calibrate_default = defineCommand({
|
|
|
37429
37886
|
}
|
|
37430
37887
|
if (flags.scenario && flags["observed-through-day"] === undefined)
|
|
37431
37888
|
throw usageError("--scenario requires --observed-through-day for a mature cohort comparison");
|
|
37432
|
-
const abs =
|
|
37889
|
+
const abs = resolve9(process.cwd(), telemetryPath);
|
|
37433
37890
|
const raw = await readTextFile(abs);
|
|
37434
37891
|
const format = flags["input-format"] === "auto" ? extname3(abs).toLowerCase() : flags["input-format"];
|
|
37435
37892
|
const rows = format === ".csv" || format === "csv" ? parseCsvTelemetry(raw, flags["observed-through-day"] !== undefined) : parseJsonTelemetry(raw, flags["observed-through-day"] !== undefined);
|
|
@@ -37468,12 +37925,12 @@ var calibrate_default = defineCommand({
|
|
|
37468
37925
|
command: "calibrate",
|
|
37469
37926
|
telemetry: observation ? { rows, observedThroughDay: observation.observedThroughDay } : rows,
|
|
37470
37927
|
scenario,
|
|
37471
|
-
scenarioPath: flags.scenario ?
|
|
37928
|
+
scenarioPath: flags.scenario ? resolve9(flags.scenario) : undefined
|
|
37472
37929
|
});
|
|
37473
37930
|
await writeOutput({
|
|
37474
37931
|
format: flags.format,
|
|
37475
37932
|
outPath: flags.out,
|
|
37476
|
-
protectedInputs: [abs, ...flags.scenario ? [
|
|
37933
|
+
protectedInputs: [abs, ...flags.scenario ? [resolve9(flags.scenario)] : []],
|
|
37477
37934
|
data: flags.format === "json" ? {
|
|
37478
37935
|
ok: true,
|
|
37479
37936
|
source: abs,
|
|
@@ -37513,7 +37970,7 @@ var calibrate_default = defineCommand({
|
|
|
37513
37970
|
payerConversion: (calibrated.monetization?.revenue?.payerConversion ?? 0).toFixed(4),
|
|
37514
37971
|
arppuDaily: (calibrated.monetization?.revenue?.arppuDaily ?? 0).toFixed(4),
|
|
37515
37972
|
adArpDau: (calibrated.monetization?.revenue?.adArpDau ?? 0).toFixed(4),
|
|
37516
|
-
cpi:
|
|
37973
|
+
cpi: calibrated.monetization?.acquisition?.cpi?.toFixed(4) ?? ""
|
|
37517
37974
|
}
|
|
37518
37975
|
],
|
|
37519
37976
|
meta: outputMeta
|
|
@@ -37523,12 +37980,12 @@ var calibrate_default = defineCommand({
|
|
|
37523
37980
|
|
|
37524
37981
|
// src/commands/balance.ts
|
|
37525
37982
|
init_zod();
|
|
37526
|
-
import { resolve as
|
|
37983
|
+
import { resolve as resolve12 } from "path";
|
|
37527
37984
|
|
|
37528
37985
|
// src/balance/workflow.ts
|
|
37529
37986
|
init_dist2();
|
|
37530
37987
|
init_zod();
|
|
37531
|
-
import { resolve as
|
|
37988
|
+
import { resolve as resolve11, dirname as dirname8 } from "path";
|
|
37532
37989
|
import { stat as stat2 } from "fs/promises";
|
|
37533
37990
|
|
|
37534
37991
|
// src/cliMeta.ts
|
|
@@ -37541,6 +37998,42 @@ var CLI_DESCRIPTION = import_package2.default.description ?? "Bun-first idle gam
|
|
|
37541
37998
|
// src/balance/workflow.ts
|
|
37542
37999
|
init_bun();
|
|
37543
38000
|
|
|
38001
|
+
// src/balance/pacingAmount.ts
|
|
38002
|
+
var MAX_DECIMAL_LENGTH = 200;
|
|
38003
|
+
var DECIMAL = /^([+-]?)(?:(\d+)(?:\.(\d+))?|\.(\d+))(?:e([+-]?\d+))?$/i;
|
|
38004
|
+
function pacingValue(value) {
|
|
38005
|
+
if (typeof value === "number")
|
|
38006
|
+
return Number.isFinite(value) ? Object.is(value, -0) ? 0 : value : undefined;
|
|
38007
|
+
return typeof value === "string" && value.length <= MAX_DECIMAL_LENGTH && DECIMAL.test(value) ? value : undefined;
|
|
38008
|
+
}
|
|
38009
|
+
function parts(value) {
|
|
38010
|
+
if (pacingValue(value) === undefined)
|
|
38011
|
+
throw new RangeError("Pacing value must be finite or bounded decimal text");
|
|
38012
|
+
const match = DECIMAL.exec(String(value));
|
|
38013
|
+
const fraction = match[3] ?? match[4] ?? "";
|
|
38014
|
+
const digits = `${match[2] ?? ""}${fraction}`.replace(/^0+/, "");
|
|
38015
|
+
const sign = digits.length === 0 ? 0 : match[1] === "-" ? -1 : 1;
|
|
38016
|
+
return {
|
|
38017
|
+
sign,
|
|
38018
|
+
digits: digits.replace(/0+$/, ""),
|
|
38019
|
+
magnitude: BigInt(match[5] ?? "0") - BigInt(fraction.length) + BigInt(digits.length)
|
|
38020
|
+
};
|
|
38021
|
+
}
|
|
38022
|
+
function comparePacingValues(left, right) {
|
|
38023
|
+
if (typeof left === "number" && typeof right === "number")
|
|
38024
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
38025
|
+
const a = parts(left), b = parts(right);
|
|
38026
|
+
if (a.sign !== b.sign)
|
|
38027
|
+
return a.sign < b.sign ? -1 : 1;
|
|
38028
|
+
if (a.sign === 0)
|
|
38029
|
+
return 0;
|
|
38030
|
+
if (a.magnitude !== b.magnitude)
|
|
38031
|
+
return (a.magnitude < b.magnitude ? -1 : 1) * a.sign;
|
|
38032
|
+
const length = Math.max(a.digits.length, b.digits.length);
|
|
38033
|
+
const ad = a.digits.padEnd(length, "0"), bd = b.digits.padEnd(length, "0");
|
|
38034
|
+
return (ad < bd ? -1 : ad > bd ? 1 : 0) * a.sign;
|
|
38035
|
+
}
|
|
38036
|
+
|
|
37544
38037
|
// src/balance/pacing.ts
|
|
37545
38038
|
var PACING_LIMITS = Object.freeze({
|
|
37546
38039
|
maxRuns: 1000,
|
|
@@ -37582,6 +38075,12 @@ function finite2(value, label) {
|
|
|
37582
38075
|
invalid(`${label} must be finite`);
|
|
37583
38076
|
return Object.is(value, -0) ? 0 : value;
|
|
37584
38077
|
}
|
|
38078
|
+
function bound(value, label) {
|
|
38079
|
+
const parsed = pacingValue(value);
|
|
38080
|
+
if (parsed === undefined)
|
|
38081
|
+
invalid(`${label} must be finite or decimal text of at most 200 characters`);
|
|
38082
|
+
return parsed;
|
|
38083
|
+
}
|
|
37585
38084
|
function limit(value, maximum, label) {
|
|
37586
38085
|
if (value === undefined)
|
|
37587
38086
|
return maximum;
|
|
@@ -37640,11 +38139,11 @@ function planPacingRuns(input) {
|
|
|
37640
38139
|
if (metrics.has(metric))
|
|
37641
38140
|
invalid(`duplicate target metric ${metric}`);
|
|
37642
38141
|
metrics.add(metric);
|
|
37643
|
-
const min = raw.min === undefined ? undefined :
|
|
37644
|
-
const max = raw.max === undefined ? undefined :
|
|
38142
|
+
const min = raw.min === undefined ? undefined : bound(raw.min, `targets[${index}].min`);
|
|
38143
|
+
const max = raw.max === undefined ? undefined : bound(raw.max, `targets[${index}].max`);
|
|
37645
38144
|
if (min === undefined && max === undefined)
|
|
37646
38145
|
invalid(`target ${metric} needs min or max`);
|
|
37647
|
-
if (min !== undefined && max !== undefined && min >
|
|
38146
|
+
if (min !== undefined && max !== undefined && comparePacingValues(min, max) > 0)
|
|
37648
38147
|
invalid(`target ${metric} min exceeds max`);
|
|
37649
38148
|
return Object.freeze({ metric, unit, ...min !== undefined ? { min } : {}, ...max !== undefined ? { max } : {} });
|
|
37650
38149
|
}).sort((left, right) => compareText(left.metric, right.metric));
|
|
@@ -37723,11 +38222,12 @@ function checkTarget(target, metrics) {
|
|
|
37723
38222
|
const value = metrics[target.metric];
|
|
37724
38223
|
if (value === null)
|
|
37725
38224
|
return { ...target, value, status: "unreached", message: "Metric not reached within the run horizon" };
|
|
37726
|
-
|
|
37727
|
-
|
|
38225
|
+
const parsed = pacingValue(value);
|
|
38226
|
+
if (parsed === undefined) {
|
|
38227
|
+
return { ...target, value: null, status: "error", message: "Evaluator metric must be a finite number, bounded decimal text or null" };
|
|
37728
38228
|
}
|
|
37729
|
-
const breached = target.min !== undefined &&
|
|
37730
|
-
return { ...target, value:
|
|
38229
|
+
const breached = target.min !== undefined && comparePacingValues(parsed, target.min) < 0 || target.max !== undefined && comparePacingValues(parsed, target.max) > 0;
|
|
38230
|
+
return { ...target, value: parsed, status: breached ? "breach" : "pass" };
|
|
37731
38231
|
}
|
|
37732
38232
|
async function runPacingChecks(input, evaluator) {
|
|
37733
38233
|
const plan = planPacingRuns(input);
|
|
@@ -37776,7 +38276,7 @@ async function runPacingChecks(input, evaluator) {
|
|
|
37776
38276
|
init_bun();
|
|
37777
38277
|
import { constants } from "fs";
|
|
37778
38278
|
import { lstat, mkdir, open as open2, realpath as realpath2, rename, rm } from "fs/promises";
|
|
37779
|
-
import { dirname as dirname7, isAbsolute as isAbsolute2, join, relative as relative2, resolve as
|
|
38279
|
+
import { dirname as dirname7, isAbsolute as isAbsolute2, join, relative as relative2, resolve as resolve10, sep as sep2 } from "path";
|
|
37780
38280
|
var SHEET_LIMITS = Object.freeze({
|
|
37781
38281
|
maxCsvBytes: 2 * 1024 * 1024,
|
|
37782
38282
|
maxRows: 10001,
|
|
@@ -38148,7 +38648,7 @@ async function snapshotInputs(inputFiles, contextValue, limits) {
|
|
|
38148
38648
|
const inputs = Object.create(null);
|
|
38149
38649
|
let total = 0;
|
|
38150
38650
|
for (const name of validInputNames(inputFiles, limits)) {
|
|
38151
|
-
const path =
|
|
38651
|
+
const path = resolve10(inputFiles[name]);
|
|
38152
38652
|
const realPath = await realpath2(path);
|
|
38153
38653
|
const bytes = await boundedRead(realPath, Math.min(limits.maxInputBytes, limits.maxTotalInputBytes - total));
|
|
38154
38654
|
total += bytes.length;
|
|
@@ -38174,7 +38674,7 @@ async function snapshotInputs(inputFiles, contextValue, limits) {
|
|
|
38174
38674
|
});
|
|
38175
38675
|
}
|
|
38176
38676
|
async function canonicalOutput(path) {
|
|
38177
|
-
path =
|
|
38677
|
+
path = resolve10(path);
|
|
38178
38678
|
try {
|
|
38179
38679
|
return await realpath2(path);
|
|
38180
38680
|
} catch (error) {
|
|
@@ -38213,7 +38713,7 @@ async function refreshSheetBundle(options) {
|
|
|
38213
38713
|
validInputNames(options.inputFiles, limits);
|
|
38214
38714
|
const output = await canonicalOutput(options.outputDir);
|
|
38215
38715
|
for (const [name, path] of Object.entries(options.inputFiles)) {
|
|
38216
|
-
if (isWithin(output,
|
|
38716
|
+
if (isWithin(output, resolve10(path)) || isWithin(output, await realpath2(path)))
|
|
38217
38717
|
throw new Error(`Output/input collision: ${name}`);
|
|
38218
38718
|
}
|
|
38219
38719
|
await mkdir(output, { recursive: true });
|
|
@@ -38473,7 +38973,7 @@ function normalizeRunDocument(document, strategy, horizon) {
|
|
|
38473
38973
|
target.outputs = { ...target.outputs, report: { ...target.outputs?.report, includeTrace: true, traceEverySteps: MAX_STEPS_PER_RUN + 1 } };
|
|
38474
38974
|
}
|
|
38475
38975
|
async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
38476
|
-
const absoluteConfig =
|
|
38976
|
+
const absoluteConfig = resolve11(configPath);
|
|
38477
38977
|
const configInfo = await stat2(absoluteConfig);
|
|
38478
38978
|
if (!configInfo.isFile() || configInfo.size > SHEET_LIMITS.maxInputBytes)
|
|
38479
38979
|
throw new Error("Workflow config is not a bounded regular file");
|
|
@@ -38482,17 +38982,18 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
|
38482
38982
|
const base = dirname8(absoluteConfig);
|
|
38483
38983
|
const inputFiles = {
|
|
38484
38984
|
config: absoluteConfig,
|
|
38485
|
-
sheet:
|
|
38486
|
-
schema:
|
|
38487
|
-
scenario:
|
|
38985
|
+
sheet: resolve11(base, config.sheet),
|
|
38986
|
+
schema: resolve11(base, config.schema),
|
|
38987
|
+
scenario: resolve11(base, config.scenario)
|
|
38488
38988
|
};
|
|
38489
38989
|
if (flags["plugin-trust-file"])
|
|
38490
|
-
inputFiles.pluginTrust =
|
|
38990
|
+
inputFiles.pluginTrust = resolve11(flags["plugin-trust-file"]);
|
|
38491
38991
|
const loaded = await loadRegistriesFromFlags(flags);
|
|
38492
38992
|
for (const [index, path] of Object.keys(loaded.pluginDigest).entries())
|
|
38493
38993
|
inputFiles[`plugin${index}`] = path;
|
|
38494
|
-
const
|
|
38495
|
-
const
|
|
38994
|
+
const engine = resolveEffectiveEngine({ requested: flags.engine });
|
|
38995
|
+
const context = { cliVersion: CLI_VERSION, bunVersion: Bun.version, pluginDigests: JSON.stringify(loaded.pluginDigest), engine: engine.effectiveId };
|
|
38996
|
+
const outputDir = resolve11(base, config.outputDir);
|
|
38496
38997
|
if (check)
|
|
38497
38998
|
return readCurrentBundle(outputDir, inputFiles, { context });
|
|
38498
38999
|
let outcome;
|
|
@@ -38528,7 +39029,7 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
|
38528
39029
|
const metricIds = new Set(config.metrics.map((metric) => metric.id));
|
|
38529
39030
|
if (metricIds.size !== config.metrics.length)
|
|
38530
39031
|
throw new Error("Metric IDs must be unique");
|
|
38531
|
-
const targets =
|
|
39032
|
+
const targets = plan.targets;
|
|
38532
39033
|
for (const target of targets)
|
|
38533
39034
|
if (!metricIds.has(target.metric))
|
|
38534
39035
|
throw new Error(`Unknown target metric: ${target.metric}`);
|
|
@@ -38550,6 +39051,9 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
|
38550
39051
|
const unit = metric.kind === "firstAction" || metric.kind === "firstActionPrefix" ? "seconds" : metric.kind === "endWallet" || metric.kind === "endNetWorth" ? baselineDocument.unit.code : "count";
|
|
38551
39052
|
if (target.unit !== unit)
|
|
38552
39053
|
throw new Error(`Target ${target.metric} must use unit '${unit}'`);
|
|
39054
|
+
if (metric.kind !== "endWallet" && metric.kind !== "endNetWorth" && (typeof target.min === "string" || typeof target.max === "string")) {
|
|
39055
|
+
throw new Error(`Target ${target.metric} requires finite numeric time or count bounds`);
|
|
39056
|
+
}
|
|
38553
39057
|
}
|
|
38554
39058
|
const materialize = (patches) => {
|
|
38555
39059
|
const candidate = applySheetCsv(template, schema, overlayCsv(canonicalCsv, patches));
|
|
@@ -38567,7 +39071,7 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
|
38567
39071
|
modelRegistry: loaded.modelRegistry,
|
|
38568
39072
|
strategyRegistry: loaded.strategyRegistry,
|
|
38569
39073
|
pluginDigest: loaded.pluginDigest,
|
|
38570
|
-
engineRequest:
|
|
39074
|
+
engineRequest: engine.effectiveId,
|
|
38571
39075
|
seed: descriptor.seed
|
|
38572
39076
|
});
|
|
38573
39077
|
const opened = prepared.open("simulate", `simulate:${descriptor.seed}`, { durationSec: descriptor.horizonSec });
|
|
@@ -38589,6 +39093,13 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
|
38589
39093
|
throw new Error("Action history exceeded the result budget; pacing cannot be inferred from truncated history");
|
|
38590
39094
|
const actions = run.actionsLog ?? [];
|
|
38591
39095
|
const result = {};
|
|
39096
|
+
const monetary = (amount) => {
|
|
39097
|
+
const E = opened.scenario.ctx.E;
|
|
39098
|
+
if (!E.isFinite(amount))
|
|
39099
|
+
throw new Error("Monetary metric overflowed the selected engine");
|
|
39100
|
+
const decimal = E.toString(amount);
|
|
39101
|
+
return engine.effectiveId === "number" ? Number(decimal) : decimal;
|
|
39102
|
+
};
|
|
38592
39103
|
for (const metric of config.metrics) {
|
|
38593
39104
|
if (metric.kind === "firstAction" || metric.kind === "firstActionPrefix") {
|
|
38594
39105
|
const action = actions.find((item) => metric.kind === "firstAction" ? item.actionId === metric.actionId : item.actionId.startsWith(metric.prefix));
|
|
@@ -38598,12 +39109,12 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
|
38598
39109
|
else if (metric.kind === "actionCount")
|
|
38599
39110
|
result[metric.id] = actions.length;
|
|
38600
39111
|
else if (metric.kind === "endWallet")
|
|
38601
|
-
result[metric.id] =
|
|
39112
|
+
result[metric.id] = monetary(run.end.wallet.money.amount);
|
|
38602
39113
|
else {
|
|
38603
39114
|
const worth = opened.scenario.model.netWorth?.(opened.scenario.ctx, run.end);
|
|
38604
39115
|
if (!worth)
|
|
38605
39116
|
throw new Error("endNetWorth requires model.netWorth; wallet is not a substitute");
|
|
38606
|
-
result[metric.id] =
|
|
39117
|
+
result[metric.id] = monetary(worth.amount);
|
|
38607
39118
|
}
|
|
38608
39119
|
}
|
|
38609
39120
|
return result;
|
|
@@ -38661,7 +39172,7 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
|
38661
39172
|
`);
|
|
38662
39173
|
return { id: variant.id, scenario: name };
|
|
38663
39174
|
});
|
|
38664
|
-
addArtifact("variants.json", JSON.stringify({ version: 1, engine:
|
|
39175
|
+
addArtifact("variants.json", JSON.stringify({ version: 1, engine: engine.effectiveId, seeds: plan.seeds, horizonSec: horizon, strategy: plan.strategy, variants }, null, 2) + `
|
|
38665
39176
|
`);
|
|
38666
39177
|
}
|
|
38667
39178
|
return artifacts;
|
|
@@ -38674,12 +39185,24 @@ async function refreshBalanceWorkflow(configPath, flags, check = false) {
|
|
|
38674
39185
|
function cell(value) {
|
|
38675
39186
|
return String(value).replaceAll("|", "\\|").replace(/[\r\n]/g, " ");
|
|
38676
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
|
+
}
|
|
38677
39200
|
function explain(result) {
|
|
38678
39201
|
if (result.status === "breach" && result.value !== null) {
|
|
38679
|
-
if (result.min !== undefined && result.value
|
|
38680
|
-
return `below the minimum by ${result.min
|
|
38681
|
-
if (result.max !== undefined && result.value
|
|
38682
|
-
return `above the maximum by ${result.value
|
|
39202
|
+
if (result.min !== undefined && comparePacingValues(result.value, result.min) < 0)
|
|
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}`;
|
|
39204
|
+
if (result.max !== undefined && comparePacingValues(result.value, result.max) > 0)
|
|
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}`;
|
|
38683
39206
|
}
|
|
38684
39207
|
if (result.status === "pass")
|
|
38685
39208
|
return "within the inclusive target bounds";
|
|
@@ -38718,6 +39241,7 @@ var balance_default = defineCommand({
|
|
|
38718
39241
|
description: "Refresh a typed CSV balance sheet into scenario, pacing checks, and result sheets",
|
|
38719
39242
|
options: {
|
|
38720
39243
|
...pluginOptions(),
|
|
39244
|
+
engine: option(string2().min(1).optional(), { description: "Numeric engine (default: number; explicit: breakInfinity)" }),
|
|
38721
39245
|
check: option(exports_coerce.boolean().default(false), { description: "Check result freshness without rerunning simulations" }),
|
|
38722
39246
|
format: option(_enum(["json", "md"]).default("json"), { description: "JSON manifest or human-readable target explanations" })
|
|
38723
39247
|
},
|
|
@@ -38725,7 +39249,7 @@ var balance_default = defineCommand({
|
|
|
38725
39249
|
if (positional.length !== 1)
|
|
38726
39250
|
throw usageError("Usage: idk balance <workflow.json> [--check] [plugin options]");
|
|
38727
39251
|
const result = await refreshBalanceWorkflow(positional[0], flags, flags.check);
|
|
38728
|
-
const body = flags.format === "json" ? JSON.stringify(result, null, 2) : ("state" in result) ? renderBalanceFreshness(result) : renderBalanceReport(JSON.parse(await readTextFile(
|
|
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);
|
|
38729
39253
|
await writeStdout(body + `
|
|
38730
39254
|
`);
|
|
38731
39255
|
if (flags.check && "state" in result && result.state !== "current")
|
|
@@ -38770,7 +39294,6 @@ import { resolve as resolve13 } from "path";
|
|
|
38770
39294
|
// src/io/replayArtifact.ts
|
|
38771
39295
|
init_outputMeta();
|
|
38772
39296
|
init_bun();
|
|
38773
|
-
import { resolve as resolve12 } from "path";
|
|
38774
39297
|
var REDACTED_KEYS = new Set([
|
|
38775
39298
|
"generatedAt",
|
|
38776
39299
|
"scenario",
|
|
@@ -38836,7 +39359,7 @@ function toReplayCommandLine(args) {
|
|
|
38836
39359
|
return `bun run --cwd packages/cli dev -- ${rendered}`;
|
|
38837
39360
|
}
|
|
38838
39361
|
async function writeReplayArtifact(args) {
|
|
38839
|
-
const abs =
|
|
39362
|
+
const abs = await assertOutputNotInput(args.outPath);
|
|
38840
39363
|
const runId = args.meta.runId;
|
|
38841
39364
|
const seed = args.meta.seed;
|
|
38842
39365
|
const scenarioHash = args.meta.scenarioHash;
|
|
@@ -39174,6 +39697,7 @@ function compareIdentity2(args) {
|
|
|
39174
39697
|
return {
|
|
39175
39698
|
a: side(args.scenarios.a),
|
|
39176
39699
|
b: side(args.scenarios.b),
|
|
39700
|
+
...args.engineId && args.engineId !== "number" ? { engineId: args.engineId } : {},
|
|
39177
39701
|
pluginDigests: pluginDigestValues(args.loaded.pluginDigest),
|
|
39178
39702
|
metrics,
|
|
39179
39703
|
bundle: flags.bundle ?? null,
|
|
@@ -39181,7 +39705,13 @@ function compareIdentity2(args) {
|
|
|
39181
39705
|
milestoneKey: metrics.includes("timeToMilestone") ? compareMilestoneKey(flags) ?? null : null
|
|
39182
39706
|
};
|
|
39183
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
|
+
}
|
|
39184
39713
|
function measureScenario(args) {
|
|
39714
|
+
const requireFinite = (amount, label) => requireFiniteAmount(args.E, amount, label);
|
|
39185
39715
|
const runInput = args.compiled.fresh("economy");
|
|
39186
39716
|
const run = runScenario(runInput);
|
|
39187
39717
|
const endWorth = runInput.model.netWorth?.(runInput.ctx, run.end) ?? run.end.wallet.money;
|
|
@@ -39193,7 +39723,12 @@ function measureScenario(args) {
|
|
|
39193
39723
|
unit: etaInput.ctx.unit,
|
|
39194
39724
|
suffix: { kind: "alphaInfinite", minLen: 2 }
|
|
39195
39725
|
}).amount;
|
|
39196
|
-
|
|
39726
|
+
requireFinite(target, "ETA target");
|
|
39727
|
+
const reachedFn = (s) => {
|
|
39728
|
+
requireFinite(s.wallet.money.amount, "ETA money");
|
|
39729
|
+
const worth = etaInput.model.netWorth?.(etaInput.ctx, s) ?? s.wallet.money;
|
|
39730
|
+
return args.E.cmp(requireFinite(worth.amount, "ETA net worth"), target) >= 0;
|
|
39731
|
+
};
|
|
39197
39732
|
const etaRun = runScenario({
|
|
39198
39733
|
...etaInput,
|
|
39199
39734
|
run: {
|
|
@@ -39377,9 +39912,9 @@ function bundleMetrics(bundle) {
|
|
|
39377
39912
|
function compareDecisionForMetric(args) {
|
|
39378
39913
|
switch (args.metric) {
|
|
39379
39914
|
case "endMoney":
|
|
39380
|
-
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")));
|
|
39381
39916
|
case "endNetWorth":
|
|
39382
|
-
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")));
|
|
39383
39918
|
case "droppedRate":
|
|
39384
39919
|
return betterFromCmp(args.ma.droppedRate < args.mb.droppedRate ? 1 : args.ma.droppedRate > args.mb.droppedRate ? -1 : 0);
|
|
39385
39920
|
case "etaToTargetWorth": {
|
|
@@ -39453,7 +39988,7 @@ function buildSingleCompareOutput(args) {
|
|
|
39453
39988
|
},
|
|
39454
39989
|
insights: buildCompareInsights({
|
|
39455
39990
|
metric: args.metric,
|
|
39456
|
-
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",
|
|
39457
39992
|
better: result.better,
|
|
39458
39993
|
a: {
|
|
39459
39994
|
endNetWorth: args.E.toString(args.ma.endNetWorth),
|
|
@@ -39475,6 +40010,7 @@ var compare_default = defineCommand({
|
|
|
39475
40010
|
description: "Compare two scenarios via measured simulation metrics",
|
|
39476
40011
|
options: {
|
|
39477
40012
|
...pluginOptions(),
|
|
40013
|
+
engine: option(string2().min(1).optional(), { description: "Numeric engine (default: number; explicit: breakInfinity)" }),
|
|
39478
40014
|
duration: option(exports_coerce.number().optional(), { description: "Override durationSec" }),
|
|
39479
40015
|
step: option(exports_coerce.number().optional(), { description: "Override stepSec" }),
|
|
39480
40016
|
strategy: option(strategySchema, { description: "Override strategy id (greedy|planner|scripted)" }),
|
|
@@ -39530,7 +40066,8 @@ var compare_default = defineCommand({
|
|
|
39530
40066
|
throw usageError("metric=timeToMilestone requires --milestone-key <key>");
|
|
39531
40067
|
}
|
|
39532
40068
|
const scenarios = { a: aScenario, b: bScenario };
|
|
39533
|
-
const
|
|
40069
|
+
const engine = resolveEffectiveEngine({ requested: flags.engine });
|
|
40070
|
+
const identity = compareIdentity2({ scenarios, flags, loaded, engineId: engine.effectiveId });
|
|
39534
40071
|
const effectiveSeed = flags.seed ?? defaultRunSeed({
|
|
39535
40072
|
base: {
|
|
39536
40073
|
command: "compare",
|
|
@@ -39550,9 +40087,12 @@ var compare_default = defineCommand({
|
|
|
39550
40087
|
milestoneKey: undefined
|
|
39551
40088
|
}
|
|
39552
40089
|
},
|
|
39553
|
-
runs: [{ identity, defaults:
|
|
40090
|
+
runs: [{ identity, defaults: {
|
|
40091
|
+
...compareIdentity2({ scenarios, flags: { "max-duration": DEFAULT_MAX_DURATION }, loaded }),
|
|
40092
|
+
engineId: "number"
|
|
40093
|
+
} }]
|
|
39554
40094
|
});
|
|
39555
|
-
const E =
|
|
40095
|
+
const E = engine.engine;
|
|
39556
40096
|
const aCompiled = compileComparableScenario({
|
|
39557
40097
|
scenario: aScenario,
|
|
39558
40098
|
E,
|
|
@@ -39627,7 +40167,8 @@ var compare_default = defineCommand({
|
|
|
39627
40167
|
a: aScenario,
|
|
39628
40168
|
b: bScenario
|
|
39629
40169
|
},
|
|
39630
|
-
pluginDigest: loaded.pluginDigest
|
|
40170
|
+
pluginDigest: loaded.pluginDigest,
|
|
40171
|
+
effectiveEngine: engine.effectiveId
|
|
39631
40172
|
});
|
|
39632
40173
|
const markdownWarnings = new Set;
|
|
39633
40174
|
if (selectedMetrics.some((metric) => ["endMoney", "endNetWorth", "droppedRate"].includes(metric))) {
|
|
@@ -39637,6 +40178,9 @@ var compare_default = defineCommand({
|
|
|
39637
40178
|
markdownWarnings.add(`Economy runs cover different elapsed durations (A: ${aElapsed}s, B: ${bElapsed}s); end values are not normalized to a common horizon.`);
|
|
39638
40179
|
}
|
|
39639
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
|
+
}
|
|
39640
40184
|
const singleResults = selectedMetrics.map((metric) => {
|
|
39641
40185
|
const design = getDesignPair(metric);
|
|
39642
40186
|
if (design) {
|
|
@@ -39732,8 +40276,8 @@ init_outputMeta();
|
|
|
39732
40276
|
// src/lib/setup.ts
|
|
39733
40277
|
init_errors3();
|
|
39734
40278
|
init_bun();
|
|
39735
|
-
init_selfCli();
|
|
39736
40279
|
import { basename as basename4, dirname as dirname9, relative as relative3, resolve as resolve15 } from "path";
|
|
40280
|
+
init_selfCli();
|
|
39737
40281
|
var START_MARKER = "# >>> idk completions >>>";
|
|
39738
40282
|
var END_MARKER = "# <<< idk completions <<<";
|
|
39739
40283
|
function userHome() {
|
|
@@ -39874,7 +40418,7 @@ async function writePluginTrust(args) {
|
|
|
39874
40418
|
if (args.plugins.length === 0) {
|
|
39875
40419
|
throw usageError("setup plugin-trust requires at least one --plugin path.");
|
|
39876
40420
|
}
|
|
39877
|
-
const outPath =
|
|
40421
|
+
const outPath = await assertOutputNotInput(args.outPath, { protectedInputs: args.plugins });
|
|
39878
40422
|
if (await fileExists(outPath) && !args.force) {
|
|
39879
40423
|
throw usageError(`Output file already exists: ${outPath}`, "Pass --force true to overwrite.");
|
|
39880
40424
|
}
|
|
@@ -40375,6 +40919,9 @@ import { resolve as resolve17 } from "path";
|
|
|
40375
40919
|
init_errors3();
|
|
40376
40920
|
init_outputMeta();
|
|
40377
40921
|
var strategySchema2 = string2().min(1).optional();
|
|
40922
|
+
function uint32Seed(seed) {
|
|
40923
|
+
return Number.isFinite(seed) ? seed >>> 0 : seed;
|
|
40924
|
+
}
|
|
40378
40925
|
function parseHorizonToken(raw) {
|
|
40379
40926
|
const token = raw.trim().toLowerCase();
|
|
40380
40927
|
if (!token)
|
|
@@ -40530,7 +41077,7 @@ function runLtvAnalysis(args) {
|
|
|
40530
41077
|
}
|
|
40531
41078
|
const worth = args.compiled.model.netWorth?.(args.compiled.ctx, state) ?? state.wallet.money;
|
|
40532
41079
|
const endWorthLog10 = args.compiled.ctx.E.absLog10(worth.amount);
|
|
40533
|
-
const progression =
|
|
41080
|
+
const progression = progressionFactor2(startWorthLog10, endWorthLog10, monetizationConfig.revenue.progressionLogSpan);
|
|
40534
41081
|
const horizonDays = h.seconds / 86400;
|
|
40535
41082
|
const point = estimateLtvPerUser2({
|
|
40536
41083
|
config: monetizationConfig,
|
|
@@ -40543,7 +41090,7 @@ function runLtvAnalysis(args) {
|
|
|
40543
41090
|
progression,
|
|
40544
41091
|
draws,
|
|
40545
41092
|
quantiles: monetizationConfig.uncertainty.quantiles,
|
|
40546
|
-
seed: (args.seed ?? monetizationConfig.uncertainty.seed ?? 1) + h.seconds
|
|
41093
|
+
seed: uint32Seed((args.seed ?? monetizationConfig.uncertainty.seed ?? 1) + h.seconds)
|
|
40547
41094
|
}) : undefined;
|
|
40548
41095
|
const E = args.compiled.ctx.E;
|
|
40549
41096
|
const deltaWorth = E.sub(worth.amount, previousWorth.amount);
|
|
@@ -41117,6 +41664,8 @@ var evaluate_default = defineCommand({
|
|
|
41117
41664
|
files.ltv = resolve18(outDir, "ltv.json");
|
|
41118
41665
|
const summaryPath = resolve18(process.cwd(), flags["out-dir"], flags.format === "md" ? "summary.md" : "summary.json");
|
|
41119
41666
|
files.summary = summaryPath;
|
|
41667
|
+
for (const path of [files.simulate, files.experience, files.ltv, summaryPath])
|
|
41668
|
+
await assertOutputNotInput(path);
|
|
41120
41669
|
await writeTextFile(files.simulate, `${JSON.stringify({ ...simulate, _meta: simulateMeta }, null, 2)}
|
|
41121
41670
|
`);
|
|
41122
41671
|
await writeTextFile(files.experience, `${JSON.stringify({ ...experience, _meta: experienceMeta }, null, 2)}
|
|
@@ -41851,7 +42400,7 @@ var simulate_default = defineCommand({
|
|
|
41851
42400
|
state: strategyState
|
|
41852
42401
|
} : undefined
|
|
41853
42402
|
});
|
|
41854
|
-
await writeTextFile(stateOutPath, `${JSON.stringify(serialized, null, 2)}
|
|
42403
|
+
await writeTextFile(await assertOutputNotInput(stateOutPath, { allowFlags: ["resume"] }), `${JSON.stringify(serialized, null, 2)}
|
|
41855
42404
|
`);
|
|
41856
42405
|
}
|
|
41857
42406
|
const offlineSummary = buildOfflineSummary(offlineRun);
|
|
@@ -42096,6 +42645,13 @@ function readBestScoreFromArtifact(x) {
|
|
|
42096
42645
|
}
|
|
42097
42646
|
return score;
|
|
42098
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
|
+
}
|
|
42099
42655
|
function buildTuneInsights(outputBase) {
|
|
42100
42656
|
const report = outputBase.report;
|
|
42101
42657
|
const bestScore = readBestScoreFromTuneResult(outputBase);
|
|
@@ -42190,6 +42746,7 @@ var tune_default = defineCommand({
|
|
|
42190
42746
|
description: "Tune strategy parameters with objective scoring",
|
|
42191
42747
|
options: {
|
|
42192
42748
|
...pluginOptions(),
|
|
42749
|
+
engine: option(string2().min(1).optional(), { description: "Numeric engine (default: number; explicit: breakInfinity)" }),
|
|
42193
42750
|
tune: option(string2().optional(), { description: "TuneSpec file path (.json|.yaml)" }),
|
|
42194
42751
|
wizard: option(exports_coerce.boolean().default(false), {
|
|
42195
42752
|
description: "Interactively generate a TuneSpec before tuning"
|
|
@@ -42245,11 +42802,22 @@ var tune_default = defineCommand({
|
|
|
42245
42802
|
const tuneSpecInput = wizardResult?.tuneSpec ?? await readScenarioFile(tunePath);
|
|
42246
42803
|
const baselinePath = flags["baseline-artifact"] ? resolve21(flags["baseline-artifact"]) : undefined;
|
|
42247
42804
|
const baselineRaw = baselinePath ? await readJsonFile(baselinePath) : undefined;
|
|
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
|
+
}
|
|
42814
|
+
const engineIdentity = engine.effectiveId === "number" ? {} : { engineId: engine.effectiveId };
|
|
42248
42815
|
const seed = flags.seed ?? deriveDeterministicSeed({
|
|
42249
42816
|
command: "tune",
|
|
42250
42817
|
scenario: scenarioInput,
|
|
42251
42818
|
tuneSpec: tuneSpecInput,
|
|
42252
42819
|
options: {
|
|
42820
|
+
...engineIdentity,
|
|
42253
42821
|
baselineArtifact: baselineRaw === undefined ? undefined : hashContent(baselineRaw),
|
|
42254
42822
|
regressionTolerance: flags["regression-tolerance"]
|
|
42255
42823
|
}
|
|
@@ -42257,7 +42825,7 @@ var tune_default = defineCommand({
|
|
|
42257
42825
|
const runId = flags["run-id"] ?? deriveDeterministicRunId({
|
|
42258
42826
|
command: "tune",
|
|
42259
42827
|
seed,
|
|
42260
|
-
scope: { scenario: scenarioInput, tuneSpec: tuneSpecInput, pluginDigests: Object.values(loaded.pluginDigest) }
|
|
42828
|
+
scope: { scenario: scenarioInput, tuneSpec: tuneSpecInput, pluginDigests: Object.values(loaded.pluginDigest), ...engineIdentity }
|
|
42261
42829
|
});
|
|
42262
42830
|
const outputMeta = buildOutputMeta({
|
|
42263
42831
|
command: "tune",
|
|
@@ -42266,10 +42834,11 @@ var tune_default = defineCommand({
|
|
|
42266
42834
|
tuneSpec: tuneSpecInput,
|
|
42267
42835
|
runId,
|
|
42268
42836
|
seed,
|
|
42269
|
-
pluginDigest: loaded.pluginDigest
|
|
42837
|
+
pluginDigest: loaded.pluginDigest,
|
|
42838
|
+
effectiveEngine: engine.effectiveId
|
|
42270
42839
|
});
|
|
42271
42840
|
const result = await cmdTune({
|
|
42272
|
-
E:
|
|
42841
|
+
E: engine.engine,
|
|
42273
42842
|
scenarioInput,
|
|
42274
42843
|
tuneSpecInput,
|
|
42275
42844
|
modelRegistry: loaded.modelRegistry,
|
|
@@ -43658,7 +44227,6 @@ init_zod();
|
|
|
43658
44227
|
// src/commands/_shared/listOutput.ts
|
|
43659
44228
|
init_outputMeta();
|
|
43660
44229
|
init_bun();
|
|
43661
|
-
import { resolve as resolve25 } from "path";
|
|
43662
44230
|
async function writeListOutput(args) {
|
|
43663
44231
|
const outputForRender = args.format === "json" ? {
|
|
43664
44232
|
...args.payload,
|
|
@@ -43669,7 +44237,7 @@ async function writeListOutput(args) {
|
|
|
43669
44237
|
process.stdout.write(body);
|
|
43670
44238
|
return;
|
|
43671
44239
|
}
|
|
43672
|
-
const path =
|
|
44240
|
+
const path = await assertOutputNotInput(args.out);
|
|
43673
44241
|
await writeTextFile(path, body);
|
|
43674
44242
|
console.log(`Wrote ${args.format} output to ${path}`);
|
|
43675
44243
|
}
|
|
@@ -43818,8 +44386,9 @@ var objectives_default2 = defineGroup({
|
|
|
43818
44386
|
init_zod();
|
|
43819
44387
|
init_errors3();
|
|
43820
44388
|
init_outputMeta();
|
|
43821
|
-
import { resolve as
|
|
44389
|
+
import { resolve as resolve25 } from "path";
|
|
43822
44390
|
init_bun();
|
|
44391
|
+
init_invocation();
|
|
43823
44392
|
init_selfCli();
|
|
43824
44393
|
function deepEqual(a, b) {
|
|
43825
44394
|
return stableStringify(a) === stableStringify(b);
|
|
@@ -43839,6 +44408,7 @@ function parseArtifact(input) {
|
|
|
43839
44408
|
flags: record(string2(), unknown())
|
|
43840
44409
|
}),
|
|
43841
44410
|
replay: object({
|
|
44411
|
+
cwd: string2().optional(),
|
|
43842
44412
|
args: array(string2()).min(1),
|
|
43843
44413
|
commandLine: string2(),
|
|
43844
44414
|
verify: object({
|
|
@@ -43885,13 +44455,15 @@ var replayVerify_default = defineCommand({
|
|
|
43885
44455
|
if (!artifactPath) {
|
|
43886
44456
|
throw usageError("Usage: idk replay verify <artifact.json>");
|
|
43887
44457
|
}
|
|
43888
|
-
const artifactAbs =
|
|
44458
|
+
const artifactAbs = resolve25(process.cwd(), artifactPath);
|
|
43889
44459
|
const raw = await readJsonFile(artifactAbs).catch((error) => {
|
|
43890
44460
|
if (error instanceof Error && error.name === "CliError")
|
|
43891
44461
|
throw error;
|
|
43892
44462
|
throw replayArtifactInvalidError("Invalid replay artifact.", errorDetail(error), error);
|
|
43893
44463
|
});
|
|
43894
44464
|
const artifact = parseArtifact(raw);
|
|
44465
|
+
const recordedCwd = artifact.replay.cwd || process.cwd();
|
|
44466
|
+
recordNestedInputs(recordedCwd, artifact.input.positional, artifact.input.flags);
|
|
43895
44467
|
const requiredChecks = {
|
|
43896
44468
|
runId: typeof artifact.replay.verify.runId === "string" && artifact.replay.verify.runId.length > 0,
|
|
43897
44469
|
seed: typeof artifact.replay.verify.seed === "number" && Number.isFinite(artifact.replay.verify.seed),
|
|
@@ -43907,6 +44479,15 @@ var replayVerify_default = defineCommand({
|
|
|
43907
44479
|
const expectedHash = artifact.replay.verify.resultHash ?? hashReplayResult(expectedCanonical);
|
|
43908
44480
|
const actualHash = hashReplayResult(actualCanonical);
|
|
43909
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));
|
|
43910
44491
|
const semanticChecks = {
|
|
43911
44492
|
runId: replayMeta && typeof replayMeta.runId === "string" && replayMeta.runId === artifact.replay.verify.runId,
|
|
43912
44493
|
seed: replayMeta && typeof replayMeta.seed === "number" && replayMeta.seed === artifact.replay.verify.seed,
|
|
@@ -44186,4 +44767,4 @@ export {
|
|
|
44186
44767
|
cli2 as cli
|
|
44187
44768
|
};
|
|
44188
44769
|
|
|
44189
|
-
//# debugId=
|
|
44770
|
+
//# debugId=75B3E1ECDA8A1B6D64756E2164756E21
|