@mnemom/mnemom 0.17.6-next.1 → 0.17.6-next.2
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.
|
@@ -6,17 +6,14 @@
|
|
|
6
6
|
* Read-only; no network. Only token counts, model ids and timestamps are read from a
|
|
7
7
|
* transcript line — never message content.
|
|
8
8
|
*
|
|
9
|
-
* The
|
|
10
|
-
*
|
|
11
|
-
* mnemom-adw scratchpad/
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* 700k – 1M aggressive → the 400–700k bound, EXTRAPOLATED (no measured pair)
|
|
18
|
-
* ≥ 1M balanced → 0 (live sessions only; a stock history cannot get
|
|
19
|
-
* there because Claude Code compacts first — counted)
|
|
9
|
+
* The rate is ONE flat number (operator policy 2026-10-02): the median paired total-bill
|
|
10
|
+
* saving of the S46 chain45 C2n arm (context runtime, aggressive profile, no goal) against
|
|
11
|
+
* stock, 23.8% over n = 13 counted rounds (mnemom-adw scratchpad/trustcode-mvp/runs/
|
|
12
|
+
* s46-status.json; early exits and void arms excluded). It applies to every request whose
|
|
13
|
+
* original context is at or above the aggressive profile's fold point (its 60k tail
|
|
14
|
+
* budget); smaller requests never fold, so they save 0. A flat rate over-counts mid-size
|
|
15
|
+
* contexts and under-counts large ones; in aggregate that evens out. Per-size rates come
|
|
16
|
+
* back once there are enough measured pairs.
|
|
20
17
|
*/
|
|
21
18
|
/** One billed request, deduped by message id. `t` is epoch seconds. */
|
|
22
19
|
export interface Row {
|
|
@@ -59,28 +56,14 @@ export declare function parseUsageLine(line: Buffer, subagent: boolean): {
|
|
|
59
56
|
* session copies messages) is skipped, so each request is billed once, to its origin.
|
|
60
57
|
*/
|
|
61
58
|
export declare function loadTranscript(path: string, seen?: Set<string>): Row[];
|
|
62
|
-
/**
|
|
63
|
-
export declare const
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
* aggressive: no measured pair below 100k or at/above 700k.
|
|
67
|
-
*/
|
|
68
|
-
export declare const CURVE_LOWER: Readonly<Record<"aggressive" | "balanced", Record<number, number>>>;
|
|
69
|
-
export declare const NO_FOLD_BELOW = 200000;
|
|
70
|
-
export declare const EXTRAPOLATE_FROM = 700000;
|
|
71
|
-
export declare const BALANCED_FROM = 1000000;
|
|
72
|
-
export declare const POLICY = "none <200k / aggressive 200k-1M / balanced 1M+ (1M+ applies only to live sessions)";
|
|
59
|
+
/** S46 C2n vs stock, median paired total-bill saving (n = 13). */
|
|
60
|
+
export declare const S46_MEDIAN_SAVING = 0.238;
|
|
61
|
+
/** The aggressive profile's tail budget (cli/src/lib/agent.ts): below it nothing folds. */
|
|
62
|
+
export declare const AGGRESSIVE_FOLD_FROM = 60000;
|
|
73
63
|
export declare const ESTIMATOR_METHOD: string;
|
|
74
|
-
export type Strategy = "none" | "aggressive"
|
|
75
|
-
export type RateNote = "
|
|
76
|
-
/** The
|
|
77
|
-
export declare function binOf(x: number): number;
|
|
78
|
-
/** The screen never claims a negative saving: a negative measured rate shows as 0. */
|
|
79
|
-
export declare function floorRate(raw: number): {
|
|
80
|
-
screen: number;
|
|
81
|
-
note: "floored_at_0" | null;
|
|
82
|
-
};
|
|
83
|
-
/** The per-request rate the screen uses (`screen`) and the honest measured one (`raw`). */
|
|
64
|
+
export type Strategy = "none" | "aggressive";
|
|
65
|
+
export type RateNote = "below_aggressive" | null;
|
|
66
|
+
/** The per-request rate the screen uses. `raw` equals `screen`: no floor, no curve. */
|
|
84
67
|
export declare function ruleRate(x: number): {
|
|
85
68
|
strategy: Strategy;
|
|
86
69
|
raw: number;
|
|
@@ -90,7 +73,7 @@ export declare function ruleRate(x: number): {
|
|
|
90
73
|
export interface Estimate {
|
|
91
74
|
actual: number;
|
|
92
75
|
saved: number;
|
|
93
|
-
/**
|
|
76
|
+
/** Same as `saved` now that no rate is floored (kept for the audit record). */
|
|
94
77
|
rawSaved: number;
|
|
95
78
|
peak: number;
|
|
96
79
|
requests: number;
|
|
@@ -6,17 +6,14 @@
|
|
|
6
6
|
* Read-only; no network. Only token counts, model ids and timestamps are read from a
|
|
7
7
|
* transcript line — never message content.
|
|
8
8
|
*
|
|
9
|
-
* The
|
|
10
|
-
*
|
|
11
|
-
* mnemom-adw scratchpad/
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* 700k – 1M aggressive → the 400–700k bound, EXTRAPOLATED (no measured pair)
|
|
18
|
-
* ≥ 1M balanced → 0 (live sessions only; a stock history cannot get
|
|
19
|
-
* there because Claude Code compacts first — counted)
|
|
9
|
+
* The rate is ONE flat number (operator policy 2026-10-02): the median paired total-bill
|
|
10
|
+
* saving of the S46 chain45 C2n arm (context runtime, aggressive profile, no goal) against
|
|
11
|
+
* stock, 23.8% over n = 13 counted rounds (mnemom-adw scratchpad/trustcode-mvp/runs/
|
|
12
|
+
* s46-status.json; early exits and void arms excluded). It applies to every request whose
|
|
13
|
+
* original context is at or above the aggressive profile's fold point (its 60k tail
|
|
14
|
+
* budget); smaller requests never fold, so they save 0. A flat rate over-counts mid-size
|
|
15
|
+
* contexts and under-counts large ones; in aggregate that evens out. Per-size rates come
|
|
16
|
+
* back once there are enough measured pairs.
|
|
20
17
|
*/
|
|
21
18
|
import { forEachLine, isoSeconds, parseJson } from "./lines.js";
|
|
22
19
|
/**
|
|
@@ -137,51 +134,19 @@ export function loadTranscript(path, seen) {
|
|
|
137
134
|
}
|
|
138
135
|
return out;
|
|
139
136
|
}
|
|
140
|
-
// ── the
|
|
141
|
-
/**
|
|
142
|
-
export const
|
|
143
|
-
/**
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// bin 1 (100-200k) is measured at -0.059 but never used: < 200k runs no fold.
|
|
149
|
-
aggressive: { 2: 0.137, 3: 0.282, 4: 0.342 },
|
|
150
|
-
balanced: { 0: -0.222, 1: -0.028, 2: 0.055, 3: 0.081, 4: 0.163, 5: 0.43 },
|
|
151
|
-
};
|
|
152
|
-
export const NO_FOLD_BELOW = 200_000;
|
|
153
|
-
export const EXTRAPOLATE_FROM = 700_000;
|
|
154
|
-
export const BALANCED_FROM = 1_000_000;
|
|
155
|
-
export const POLICY = "none <200k / aggressive 200k-1M / balanced 1M+ (1M+ applies only to live sessions)";
|
|
156
|
-
export const ESTIMATOR_METHOD = "empirical curve (lower 95% bound, rounded down), strategy per request by its original context, " +
|
|
157
|
-
`policy ${POLICY}: < 200k the balanced arm's measured rate floored at 0, 200k-1M aggressive by bin ` +
|
|
158
|
-
"(>= 700k: the 400-700k rate, extrapolated); request count and output held at stock";
|
|
159
|
-
/** The curve bin of an original context (0 = below 100k; the top bin is open-ended). */
|
|
160
|
-
export function binOf(x) {
|
|
161
|
-
let i = 0;
|
|
162
|
-
while (i < CURVE_EDGES.length - 2 && x >= CURVE_EDGES[i + 1])
|
|
163
|
-
i++;
|
|
164
|
-
return i;
|
|
165
|
-
}
|
|
166
|
-
/** The screen never claims a negative saving: a negative measured rate shows as 0. */
|
|
167
|
-
export function floorRate(raw) {
|
|
168
|
-
return raw < 0 ? { screen: 0, note: "floored_at_0" } : { screen: raw, note: null };
|
|
169
|
-
}
|
|
170
|
-
/** The per-request rate the screen uses (`screen`) and the honest measured one (`raw`). */
|
|
137
|
+
// ── the saving rate ──────────────────────────────────────────────────────────
|
|
138
|
+
/** S46 C2n vs stock, median paired total-bill saving (n = 13). */
|
|
139
|
+
export const S46_MEDIAN_SAVING = 0.238;
|
|
140
|
+
/** The aggressive profile's tail budget (cli/src/lib/agent.ts): below it nothing folds. */
|
|
141
|
+
export const AGGRESSIVE_FOLD_FROM = 60_000;
|
|
142
|
+
export const ESTIMATOR_METHOD = "flat S46 median (23.8%, C2n vs stock, n = 13) on every request whose original context is " +
|
|
143
|
+
">= 60k (the aggressive profile's fold point), 0 below; request count and output held at stock";
|
|
144
|
+
/** The per-request rate the screen uses. `raw` equals `screen`: no floor, no curve. */
|
|
171
145
|
export function ruleRate(x) {
|
|
172
|
-
if (x
|
|
173
|
-
return { strategy: "
|
|
174
|
-
}
|
|
175
|
-
if (x < NO_FOLD_BELOW) {
|
|
176
|
-
const raw = CURVE_LOWER.balanced[binOf(x)];
|
|
177
|
-
return { strategy: "none", raw, ...floorRate(raw) };
|
|
178
|
-
}
|
|
179
|
-
if (x >= EXTRAPOLATE_FROM) {
|
|
180
|
-
const r = CURVE_LOWER.aggressive[binOf(400_000)];
|
|
181
|
-
return { strategy: "aggressive", raw: r, screen: r, note: "extrapolated" };
|
|
146
|
+
if (x < AGGRESSIVE_FOLD_FROM) {
|
|
147
|
+
return { strategy: "none", raw: 0, screen: 0, note: "below_aggressive" };
|
|
182
148
|
}
|
|
183
|
-
|
|
184
|
-
return { strategy: "aggressive", raw: r, screen: r, note: null };
|
|
149
|
+
return { strategy: "aggressive", raw: S46_MEDIAN_SAVING, screen: S46_MEDIAN_SAVING, note: null };
|
|
185
150
|
}
|
|
186
151
|
/** The one swap point: rows → list-price actual and the conservative saving. */
|
|
187
152
|
export function estimate(rows) {
|
|
@@ -209,7 +209,7 @@ export const LEDGER_SIGNALS = new Set(["registry_cc_id", "registry_conv_id"]);
|
|
|
209
209
|
/** The screen's hard budget: a regression in buildScreen's line dropping must fail loudly. */
|
|
210
210
|
export function assertScreenBudget(lines) {
|
|
211
211
|
if (lines.length > MAX_LINES || lines.some((l) => l.length > WIDTH)) {
|
|
212
|
-
throw new Error(
|
|
212
|
+
throw new Error(`first-run screen exceeded its ${MAX_LINES} x ${WIDTH} budget`);
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
/** A transcript's mtime (ms), 0 when it vanished since discovery (it then sorts first). */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The first-run screen: one plain terminal screen (at most
|
|
2
|
+
* The first-run screen: one plain terminal screen (at most 22 lines of at most 78
|
|
3
3
|
* columns, ASCII) built from the backtest numbers. Pure — no I/O — so every layout is
|
|
4
4
|
* unit-tested. Every number on it is recorded in the audit with its raw value and
|
|
5
5
|
* method.
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* - No live counter is promised: `mnemom agent` has no status bar today.
|
|
26
26
|
*/
|
|
27
27
|
export declare const WIDTH = 78;
|
|
28
|
-
export declare const MAX_LINES =
|
|
28
|
+
export declare const MAX_LINES = 22;
|
|
29
29
|
/** Less history than this (API prices, in the window) is too little to backtest. */
|
|
30
30
|
export declare const MIN_HISTORY_USD = 5;
|
|
31
31
|
/** Variation A iff the shown saving is at least this many dollars and this many percent. */
|
|
@@ -33,12 +33,12 @@ export declare const STRONG_MIN_USD = 5;
|
|
|
33
33
|
export declare const STRONG_MIN_PCT = 5;
|
|
34
34
|
export declare const DAYS = 30;
|
|
35
35
|
/**
|
|
36
|
-
* The forward line:
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* undercounts output).
|
|
36
|
+
* The forward line: chain45 S46 C2n (context runtime, aggressive profile) total bill vs
|
|
37
|
+
* stock, -20.9% [-25.6, -15.9], Opus 5.5, n=13 (r15 readout; operator 2026-10-02: quote
|
|
38
|
+
* S46, not S43), 95% CI rounded to fives, 15-25. The d240p1 ~45% figure is NOT used
|
|
39
|
+
* (its re-bill undercounts output).
|
|
40
40
|
*/
|
|
41
|
-
export declare const FORWARD_LINE = "Long sessions are where Mnemom saves the most: about 15 to 25% in our
|
|
41
|
+
export declare const FORWARD_LINE = "Long sessions are where Mnemom saves the most: about 15 to 25% in our datasets.";
|
|
42
42
|
/** Prices, promotions and plan allocations move; the saving is in usage (operator 2026-10-01). */
|
|
43
43
|
export declare const PRICE_LINE = "Prices and plan limits change. Mnemom cuts what you use, so you stay ahead.";
|
|
44
44
|
/** What `mnemom agent` does today: routes through the gateway, records, keeps context lean. */
|
|
@@ -52,8 +52,8 @@ export declare function sig3(x: number): number;
|
|
|
52
52
|
* screen. The implied saving is the shown saving, which never exceeds the raw saving.
|
|
53
53
|
*/
|
|
54
54
|
export declare function pair(total: number, saved: number): [number, number, number];
|
|
55
|
-
/** part / whole as a percentage rounded DOWN
|
|
56
|
-
export declare function
|
|
55
|
+
/** part / whole as a whole-number percentage, decimals dropped (rounded DOWN). */
|
|
56
|
+
export declare function pctDown(part: number, whole: number): number;
|
|
57
57
|
export declare function day(t: number): string;
|
|
58
58
|
export declare function usd(n: number): string;
|
|
59
59
|
export declare function clean(s: string): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The first-run screen: one plain terminal screen (at most
|
|
2
|
+
* The first-run screen: one plain terminal screen (at most 22 lines of at most 78
|
|
3
3
|
* columns, ASCII) built from the backtest numbers. Pure — no I/O — so every layout is
|
|
4
4
|
* unit-tested. Every number on it is recorded in the audit with its raw value and
|
|
5
5
|
* method.
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { ESTIMATOR_METHOD } from "./backtest.js";
|
|
28
28
|
export const WIDTH = 78;
|
|
29
|
-
export const MAX_LINES =
|
|
29
|
+
export const MAX_LINES = 22;
|
|
30
30
|
/** Less history than this (API prices, in the window) is too little to backtest. */
|
|
31
31
|
export const MIN_HISTORY_USD = 5;
|
|
32
32
|
/** Variation A iff the shown saving is at least this many dollars and this many percent. */
|
|
@@ -34,14 +34,14 @@ export const STRONG_MIN_USD = 5;
|
|
|
34
34
|
export const STRONG_MIN_PCT = 5;
|
|
35
35
|
export const DAYS = 30;
|
|
36
36
|
/**
|
|
37
|
-
* The forward line:
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* undercounts output).
|
|
37
|
+
* The forward line: chain45 S46 C2n (context runtime, aggressive profile) total bill vs
|
|
38
|
+
* stock, -20.9% [-25.6, -15.9], Opus 5.5, n=13 (r15 readout; operator 2026-10-02: quote
|
|
39
|
+
* S46, not S43), 95% CI rounded to fives, 15-25. The d240p1 ~45% figure is NOT used
|
|
40
|
+
* (its re-bill undercounts output).
|
|
41
41
|
*/
|
|
42
|
-
export const FORWARD_LINE = "Long sessions are where Mnemom saves the most: about 15 to 25% in our
|
|
43
|
-
const FORWARD_SOURCE = "operator 2026-10-
|
|
44
|
-
"rounded to 15 to 25; measured vs stock
|
|
42
|
+
export const FORWARD_LINE = "Long sessions are where Mnemom saves the most: about 15 to 25% in our datasets.";
|
|
43
|
+
const FORWARD_SOURCE = "operator 2026-10-02: S46 C2n total bill -20.9% [-25.6, -15.9] (Opus 5.5, n=13), 95% CI " +
|
|
44
|
+
"rounded to fives, 15 to 25; measured vs stock";
|
|
45
45
|
/** Prices, promotions and plan allocations move; the saving is in usage (operator 2026-10-01). */
|
|
46
46
|
export const PRICE_LINE = "Prices and plan limits change. Mnemom cuts what you use, so you stay ahead.";
|
|
47
47
|
/** What `mnemom agent` does today: routes through the gateway, records, keeps context lean. */
|
|
@@ -73,11 +73,11 @@ export function pair(total, saved) {
|
|
|
73
73
|
const tot = sig3(total);
|
|
74
74
|
return [tot, Math.min(sv, tot), Math.max(tot - sv, 0)];
|
|
75
75
|
}
|
|
76
|
-
/** part / whole as a percentage rounded DOWN
|
|
77
|
-
export function
|
|
76
|
+
/** part / whole as a whole-number percentage, decimals dropped (rounded DOWN). */
|
|
77
|
+
export function pctDown(part, whole) {
|
|
78
78
|
if (whole <= 0 || part <= 0)
|
|
79
79
|
return 0;
|
|
80
|
-
return Math.floor((100 * part) / whole
|
|
80
|
+
return Math.floor((100 * part) / whole + 1e-9);
|
|
81
81
|
}
|
|
82
82
|
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
83
83
|
export function day(t) {
|
|
@@ -126,17 +126,17 @@ const SAVED_METHOD = `backtest.estimate(): ${ESTIMATOR_METHOD}; 2 sig figs DOWN`
|
|
|
126
126
|
function subLines(sub, A) {
|
|
127
127
|
if (!sub)
|
|
128
128
|
return [];
|
|
129
|
-
const p =
|
|
129
|
+
const p = pctDown(sub.saved, sub.actual);
|
|
130
130
|
const raw = sub.actual > 0 ? (100 * sub.saved) / sub.actual : 0;
|
|
131
131
|
if (p < 5) {
|
|
132
|
-
A("sub_line_omitted", { shown: true, raw, method: "usage cut
|
|
132
|
+
A("sub_line_omitted", { shown: true, raw, method: "usage cut below 5% (decimals dropped)" });
|
|
133
133
|
return [];
|
|
134
134
|
}
|
|
135
135
|
A("sub_usage_pct", {
|
|
136
136
|
shown: p,
|
|
137
137
|
raw,
|
|
138
138
|
method: "saving / API-price cost over the subscription sessions in the window (all sessions if " +
|
|
139
|
-
"none is tagged); cost-weighted,
|
|
139
|
+
"none is tagged); cost-weighted, decimals dropped",
|
|
140
140
|
});
|
|
141
141
|
return wrap(`On your subscription that is about ${p}% less usage: fewer limit hits, and less ` +
|
|
142
142
|
"overage if you use extra usage.");
|
|
@@ -151,7 +151,7 @@ export function buildScreen(inp) {
|
|
|
151
151
|
const actual = ses.reduce((t, r) => t + r.actual, 0);
|
|
152
152
|
const saved = ses.reduce((t, r) => t + r.saved, 0);
|
|
153
153
|
const [a, s, e] = pair(actual, saved);
|
|
154
|
-
const p =
|
|
154
|
+
const p = pctDown(saved, actual);
|
|
155
155
|
const enough = actual >= MIN_HISTORY_USD;
|
|
156
156
|
const variation = enough && s >= STRONG_MIN_USD && p >= STRONG_MIN_PCT ? "A" : enough ? "B" : "C";
|
|
157
157
|
A("variation", { shown: variation, raw: { actual, saved }, method: "see screen.ts header" });
|
|
@@ -162,7 +162,11 @@ export function buildScreen(inp) {
|
|
|
162
162
|
L.push("");
|
|
163
163
|
if (variation === "A") {
|
|
164
164
|
A("spent_usd", { shown: a, raw: actual, method: SPENT_METHOD });
|
|
165
|
-
A("saved_pct", {
|
|
165
|
+
A("saved_pct", {
|
|
166
|
+
shown: p,
|
|
167
|
+
raw: (100 * saved) / actual,
|
|
168
|
+
method: "decimals dropped (rounded DOWN)",
|
|
169
|
+
});
|
|
166
170
|
const viaRaw = ses.reduce((t, r) => t + (r.viaMnemom ? r.saved : 0), 0);
|
|
167
171
|
const via = sig2(viaRaw);
|
|
168
172
|
const rest = sig2(saved - viaRaw);
|
|
@@ -170,12 +174,14 @@ export function buildScreen(inp) {
|
|
|
170
174
|
A("saved_usd", { shown: s, raw: saved, method: SAVED_METHOD });
|
|
171
175
|
A("with_mnemom_usd", { shown: e, raw: actual - saved, method: "spent shown - saved shown" });
|
|
172
176
|
L.push(...wrap(`At API prices that usage cost about ${usd(a)}. With Mnemom: about ${usd(e)}.`));
|
|
177
|
+
L.push("");
|
|
173
178
|
L.push(...wrap(`That's about ${usd(s)} less (${p}%), and you don't change how you work.`));
|
|
174
179
|
}
|
|
175
180
|
else {
|
|
176
181
|
const m = `${SAVED_METHOD}; sessions the launch ledger shows ran through Mnemom`;
|
|
177
182
|
A("saved_via_mnemom_usd", { shown: via, raw: viaRaw, method: m });
|
|
178
183
|
L.push(...wrap(`At API prices that usage comes to about ${usd(a)} without Mnemom.`));
|
|
184
|
+
L.push("");
|
|
179
185
|
if (rest < 1) {
|
|
180
186
|
L.push(...wrap(`Mnemom saved you about ${usd(via)} of it (${p}%), and you didn't change how you work.`));
|
|
181
187
|
}
|
|
@@ -202,11 +208,14 @@ export function buildScreen(inp) {
|
|
|
202
208
|
raw: big.actual - big.saved,
|
|
203
209
|
method: "its cost shown - its saving (2 sig figs DOWN)",
|
|
204
210
|
});
|
|
211
|
+
L.push("");
|
|
205
212
|
const where = big.label ? `${big.label} on ${day(big.end)}` : `on ${day(big.end)}`;
|
|
206
213
|
L.push(...wrap(big.viaMnemom
|
|
207
214
|
? `Your biggest session, ${where}: ${usd(ba)} without Mnemom, about ${usd(be)} with it.`
|
|
208
215
|
: `Your biggest session, ${where}: ${usd(ba)}, with Mnemom about ${usd(be)}.`));
|
|
209
|
-
|
|
216
|
+
const subL = subLines(inp.sub, A);
|
|
217
|
+
if (subL.length)
|
|
218
|
+
L.push("", ...subL);
|
|
210
219
|
}
|
|
211
220
|
else {
|
|
212
221
|
if (variation === "B") {
|
|
@@ -219,10 +228,12 @@ export function buildScreen(inp) {
|
|
|
219
228
|
L.push(...wrap(`Your sessions used about ${usd(a)} at API prices. They stayed small, so Mnemom ` +
|
|
220
229
|
"wouldn't have changed that much."));
|
|
221
230
|
}
|
|
222
|
-
|
|
231
|
+
if (variation === "B")
|
|
232
|
+
L.push("");
|
|
233
|
+
L.push(...wrap(FORWARD_LINE));
|
|
223
234
|
A("forward_range_pct", {
|
|
224
235
|
shown: "15 to 25",
|
|
225
|
-
raw: [-
|
|
236
|
+
raw: [-25.6, -20.9, -15.9],
|
|
226
237
|
method: FORWARD_SOURCE,
|
|
227
238
|
});
|
|
228
239
|
}
|