Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/dev/verify_governor.mjs

6.7 KiB, 1 run

created by r2519314175:439, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1// verify_governor.mjs — the spend governor's pure decision core.
2//
3// The governor watches the RATE of spend, not the total, so that a fan-out of
4// agents cannot burn a week's credit in a blink. This test drives the pure
5// core directly under Node (no browser, no stack): the learned baseline, the
6// predictive batch estimate, the dispatch decision, the live rate, and the
7// green/amber/tripped level. The wiring into the real page is checked
8// separately by verify_governor_ui.mjs against the running app.
9//
10// Loaded by evaluating www/js/governor.js in a sandbox: the module guards its
11// browser globals behind `typeof`, so with `window` passed as undefined only
12// the pure core and the Node export run. This is robust to whatever module
13// system the app's package.json declares.
14import { readFileSync } from 'fs';
15
16const src = readFileSync(new URL('../www/js/governor.js', import.meta.url), 'utf8');
17const mod = { exports: {} };
18// eslint-disable-next-line no-new-func
19new Function('module', 'window', src)(mod, undefined);
20const Gov = mod.exports;
21const C = Gov._core;
22
23const ok = [], bad = [];
24const check = (name, pass, detail) => {
25 (pass ? ok : bad).push(name);
26 console.log((pass ? ' ok ' : ' FAIL ') + name + (detail ? ' — ' + detail : ''));
27};
28const near = (a, b, eps = 1e-9) => Math.abs(a - b) < eps;
29
30// ── The learned baseline ───────────────────────────────────────────
31{
32 // Too few samples: the baseline is assumed, not measured, and uses the
33 // fallback worker cost.
34 const thin = C.baselineFrom([{ t: 1, u: 0.05 }, { t: 2, u: 0.05 }]);
35 check('thin history is not "learned"', thin.learned === false);
36 check('thin baseline falls back to the fallback worker cost',
37 near(thin.perTurnUsd, C.consts.FALLBACK_WORKER_USD), 'got ' + thin.perTurnUsd);
38
39 // Enough samples: the per-turn figure is the median of the priced turns,
40 // and zero/negative costs are ignored.
41 const rich = C.baselineFrom([
42 { t: 1, u: 0.10 }, { t: 2, u: 0.20 }, { t: 3, u: 0.30 },
43 { t: 4, u: 0.40 }, { t: 5, u: 0.50 }, { t: 6, u: 0.60 },
44 { t: 7, u: 0 }, { t: 8, u: -1 },
45 ]);
46 check('rich history is "learned"', rich.learned === true);
47 check('baseline per-turn is the median of priced turns',
48 near(rich.perTurnUsd, 0.35), 'got ' + rich.perTurnUsd);
49 check('baseline rate is floored at the pennies floor',
50 rich.rateUsdMin >= C.consts.MIN_RATE_FLOOR_USD_MIN);
51}
52
53// ── The predictive estimate ────────────────────────────────────────
54{
55 const base = { perTurnUsd: 0.10 };
56 check('a batch costs N times a worker', near(C.estimateBatch(30, base), 3.0), 'got ' + C.estimateBatch(30, base));
57 check('a zero batch costs nothing', C.estimateBatch(0, base) === 0);
58 check('a batch with no baseline uses the fallback',
59 near(C.estimateBatch(10, null), 10 * C.consts.FALLBACK_WORKER_USD));
60}
61
62// ── The auto budget ────────────────────────────────────────────────
63{
64 // A cheap normal turn: the budget is the floor, not a trivial figure.
65 check('auto budget is floored', near(C.autoBudget({ perTurnUsd: 0.02 }), C.consts.DEFAULT_BUDGET_USD));
66 // An expensive turn: the budget scales with how the person works.
67 check('auto budget scales with a costly turn',
68 near(C.autoBudget({ perTurnUsd: 0.50 }), 0.50 * C.consts.BUDGET_TURN_MULTIPLE),
69 'got ' + C.autoBudget({ perTurnUsd: 0.50 }));
70}
71
72// ── The dispatch decision (the heart) ──────────────────────────────
73{
74 const base = C.baselineFrom([]); // fresh account: fallback $0.08/worker, $1 budget
75 const budget = C.autoBudget(base);
76
77 // A handful of agents on a fresh burst: silent.
78 const few = C.decideDispatch(3, base, 0, budget);
79 check('a few agents dispatch silently', few.needsConfirm === false,
80 'predicted ' + few.predicted.toFixed(2) + ' vs budget ' + budget.toFixed(2));
81
82 // The "fifty agents in a blink" case: it must ask.
83 const many = C.decideDispatch(50, base, 0, budget);
84 check('a big fan-out asks first', many.needsConfirm === true,
85 'predicted ' + many.predicted.toFixed(2));
86
87 // A burst already near its budget: even a small batch that crosses it asks.
88 const nearCap = C.decideDispatch(3, base, budget - 0.10, budget);
89 check('a batch that would cross an already-spent budget asks', nearCap.needsConfirm === true);
90
91 // The same batch on a fresh budget passes — the pause is about the runaway,
92 // not about the batch in isolation.
93 const fresh = C.decideDispatch(3, base, 0, budget);
94 check('the same batch on a fresh budget passes', fresh.needsConfirm === false);
95
96 // A user with an expensive normal is not nagged for their normal fan-out:
97 // the budget scaled with them.
98 const richBase = C.baselineFrom(Array.from({ length: 8 }, (_, i) => ({ t: i, u: 0.40 })));
99 const richBudget = C.autoBudget(richBase);
100 const richFew = C.decideDispatch(4, richBase, 0, richBudget);
101 check('an expensive-normal user is not nagged for a normal fan-out',
102 richFew.needsConfirm === false,
103 'predicted ' + richFew.predicted.toFixed(2) + ' vs budget ' + richBudget.toFixed(2));
104}
105
106// ── The live rate ──────────────────────────────────────────────────
107{
108 const now = 1_000_000;
109 const obs = [
110 { t: now - 90_000, u: 5.00 }, // outside the 60s window — ignored
111 { t: now - 30_000, u: 0.50 },
112 { t: now - 10_000, u: 0.50 },
113 ];
114 // $1.00 in the last minute → $1.00/min.
115 check('rate is the last-minute spend per minute',
116 near(C.velocityFrom(obs, now, 60_000), 1.0), 'got ' + C.velocityFrom(obs, now, 60_000));
117 check('an empty window is a zero rate', C.velocityFrom([], now, 60_000) === 0);
118}
119
120// ── The level ──────────────────────────────────────────────────────
121{
122 const base = { rateUsdMin: 0.50 }; // normal ~ $0.50/min
123 const budget = 5.0;
124 check('an ordinary rate is green', C.levelFor(0.40, base, 0.20, budget) === 'green');
125 // Well above baseline and above the pennies floor.
126 check('a fast rate is amber', C.levelFor(3.0, base, 1.0, budget) === 'amber',
127 'got ' + C.levelFor(3.0, base, 1.0, budget));
128 // Fast but still pennies: never amber (no nagging over nothing).
129 check('a fast rate on pennies is still green',
130 C.levelFor(0.40, { rateUsdMin: 0.05 }, 0.10, budget) === 'green');
131 // A burst that has run past its budget: tripped.
132 check('past the budget is tripped', C.levelFor(0.10, base, budget + 1, budget) === 'tripped');
133}
134
135console.log('\n' + ok.length + ' ok, ' + bad.length + ' failed');
136process.exit(bad.length ? 1 : 0);