bitmax/docs/handbook/14-vol-V-inbox.md
monster 59fd95b707 Initial commit: BORING SOFTWARE — an anthology of incremental games
Five incremental games disguised as boring 1998-era desktop utilities, launched from a Win98 shell (ENTROPY OS):

- Vol I  qBitTorrz       (index.html)        — torrent-client idler; seed, climb hardware tiers, migrate
- Vol II  DEFRAG.EXE     (defrag.html)       — steer a disk defragmenter; drag-select; outrun entropy
- Vol III MACRO_VIRUS.XLS(spreadsheet.html)  — build a compounding economy by drag-filling formulas
- Vol IV  UPLINK         (terminal.html)     — terminal + live htop; manage load/heat; escalate to root
- Vol V   INBOX ZERO     (inbox.html)        — keyboard-triage an exponential inbox; write regex rules
- ENTROPY OS             (desktop.html)      — the Win98 launcher that holds them all

Each is a single self-contained HTML file (vanilla JS, no deps, no build), with idle/offline
progress, scientific-scale numbers, diegetic upgrades, and a prestige that re-frames the fiction.

Also includes MANIFESTO.md (design thesis) and docs/ — the Collector's Edition companion:
a Dev Handbook and a Lore Bible (lore complete; 5 handbook chapters land in the next commit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 15:44:36 +10:00

334 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Vol V Internals — INBOX ZERO
*The engineering manual for `inbox.html`: how plausible mail is minted, how the flood ramps, the overwhelm penalty that nearly broke the economy, the rules engine that automates your judgment, and the Inbox-Zero prestige loop.*
INBOX ZERO is Volume V of *Boring Software* — an Outlook 97 three-pane mail client that is secretly a survival game against exponential noise. Where **Vol IV — UPLINK** asks you to balance load against the OOM killer, this volume asks a simpler, crueler question: can you process mail faster than it arrives? The honest answer is *no* — not by hand — and the whole arc is the player discovering that, then encoding their judgment into rules until the inbox empties itself.
The save key is `boringsoft_inbox_v1`. The shared scaffolding (`fmt`, the `~100ms` tick, offline catch-up, `sanitizeState`, toasts) is the same contract every volume inherits; this chapter documents only what is specific to the inbox, and assumes you know the DNA from §6 of the style canon.
· · ·
## The MAIL model
A message is a flat object minted by `genMail(forceType)`. The shape it returns:
```js
return {
id:_mid++, type, from:fromName, addr:fromAddr, subject,
value: Math.max(0, baseVal),
unread:true, flagged:meta.flag, vip:meta.vip,
att: type==='work'&&Math.random()<0.45 || type==='phishing'&&Math.random()<0.6,
t: now(), body: pick(BODIES[type]),
};
```
| Field | Type | Meaning |
|-------|------|---------|
| `id` | int | Monotonic, from the module-level `_mid` counter. Selection (`G.sel`) and DOM rows key off this. |
| `type` | string | One of `work`, `newsletter`, `spam`, `phishing`, `vip`. |
| `from` / `addr` | string | Display name and `user@domain`, procedurally generated per type. |
| `subject` | string | A template from the per-type subject pool, with `{n}` and `{proj}` substituted. |
| `value` | number | The *base* Productivity the mail is worth — a per-action multiplier is applied later, never stored here. |
| `unread` | bool | Flipped to `false` the moment it's selected (`selectMail`). |
| `flagged` / `vip` | bool | `flag`/`vip` from the type's metadata; phishing and VIP both flag. |
| `att` | bool | Has an attachment. Decorative, except phishing attachments render as `invoice_overdue.pdf.exe`. |
| `t` | epoch ms | Arrival time, drives the `relTime` "3m ago" column. |
| `body` | string | A canned paragraph from `BODIES[type]`. |
> **DEV NOTE** — `value` is the *base* worth, not the banked Productivity. This is deliberate and load-bearing: a mail minted on the Startup plane and triaged after you've ascended to Government must pay out at *Government* rates. If we'd frozen the multiplier into `value` at spawn time, every mail that survived an ascension would underpay. Multipliers are always applied at the point of triage (`manualMult`, `ruleMult`), never baked in. The reading pane even previews this live: `+fmt(m.value*manualMult()) PP if archived`.
### The procedural generators
The minting is unglamorous string assembly, and that is the point — it has to read like real corporate mail, not like a video game. Senders are built from name and domain pools (`FIRST`, `LAST`, `WORK_DOMAINS`, `NEWS_DOMAINS`, `SPAM_DOMAINS`, `PHISH_DOMAINS`, `VIP_DOMAINS`). The flavor is half *The Office* cast (`Schrute`, `Beesly`, `Halpert`) and half spam-folder archaeology (`secure-paypa1.com`, `bank0famerica.net`, `nigerian-prince.org`).
Subject lines come from a per-type pool with two placeholders:
```js
let subject = pick(subT).replace(/\{n\}/g,n).replace(/\{proj\}/g,proj);
```
`{n}` is a random integer in `[1, 9999)`; `{proj}` is one of the `PROJ` codenames (`Phoenix`, `Atlas`, `Synergy`, …). Address construction is type-specific — work mail derives the address *from* the display name (`fromName.toLowerCase().replace(/[^a-z]/g,'.')`), so "Dwight Schrute" becomes `dwight.schrute@boringsoft.net`, while VIP mail always lands at the current plane's domain (`pick(VIP_DOMAINS)+'@'+plane().domain`). That last detail matters for rules: a `from contains CEO` filter keeps working across planes because the VIP names are stable even as the domain shifts.
### The five types — value and sign
`MAIL_TYPES` is the single source of truth for spawn weighting and base worth:
| Type | `weight` | `baseVal` | `flag` | `vip` | Triage intent |
|------|---------|----------|--------|-------|---------------|
| `work` | 34 | 14 | — | — | Archive (the bread and butter) |
| `newsletter` | 24 | 5 | — | — | Archive cheaply, or rule away |
| `spam` | 24 | 0 | — | — | Delete |
| `phishing` | 10 | 0 | ✓ | — | Delete (it's flagged, not VIP) |
| `vip` | 8 | 90 | ✓ | ✓ | **Reply** — deleting it costs you |
`rollType()` is a standard weighted pick over `TYPE_ORDER` (total weight 100, so the percentages read directly). Base value is then jittered by ±30% so two work mails are never identically priced:
```js
const baseVal = meta.baseVal * (0.7+Math.random()*0.6);
```
Note that spam and phishing have `baseVal: 0` — they are worth *nothing* to archive. The "negative value" of spam isn't stored as a negative number; it's expressed structurally, in the asymmetry of `deleteSel`. Deleting a worthless mail pays a tiny "tidied up" reward (`m.value*0.1 + 0.5`); deleting a *VIP* applies a flat penalty of half its banked value and a scolding toast. So the sign of an action is contextual: the same `delete` keystroke is correct on spam and a self-inflicted wound on a VIP. That is the whole risk surface of manual triage in one function.
· · ·
## The arrival pipeline
`spawnMail(n)` is the funnel every new mail passes through, online and offline:
```js
function spawnMail(n){
for(let k=0;k<n;k++){
const m = genMail();
if(!applyRules(m)){
// not auto-handled -> lands in inbox
G.inbox.push(m);
}
}
if(G.inbox.length && G.sel==null) G.sel = G.inbox[0].id;
}
```
The ordering is the design: **rules run before the mail ever touches the inbox.** If a rule matches, `applyRules` banks the Productivity and the mail never enters `G.inbox` (the one exception is `flag`, which re-pushes it — see the rules section). This is why a good rule-set produces a *visibly* self-clearing inbox rather than one that fills and then drains.
### `arrivalRate()` — the flood
```js
function arrivalRate(){
const base = 0.8 * plane().rate;
const ramp = 1 + Math.min(8, (G.peakThroughput>0? Math.log10(1+G.peakThroughput)*0.18 : 0));
return base * ramp;
}
```
Base is `0.8` emails per second, multiplied by the current plane's `rate`. The `ramp` is a slow within-run time-pressure curve keyed off `peakThroughput` — the better you've been doing this run, the faster mail comes, capped at a 9× multiplier (`1 + min(8, …)`). The log-scaling means the ramp is brutal early and forgiving late; it exists to keep a stagnant inbox from being trivially idle-able while you're not investing.
`step(dt)` accumulates fractional arrivals so the rate is honored even at sub-1/s on the Startup plane:
```js
G.spawnAccum += rate*dt;
let toSpawn = Math.floor(G.spawnAccum);
if(toSpawn>0){ G.spawnAccum -= toSpawn; if(toSpawn>400) toSpawn=400; spawnMail(toSpawn); }
```
The `toSpawn>400` clamp is a per-tick ceiling so a throttled tab that hands us a 5-second `dt` (the tick's own cap) on The Void can't try to mint thousands of objects in one synchronous loop and jank the frame. Offline catch-up uses the same accumulator with a higher clamp (`2000`) and only piles unhandled mail up to `inboxCap()*3` to bound memory.
### `inboxCap()` — and the post-mortem
```js
function inboxCap(){
// base buffer gives a new player ~20s of grace before the flood overwhelms them;
return 18 + lvl('cap')*UP_BY_ID.cap.add + perkAdd('serenity') + G.ascensions*0;
}
```
Base capacity is **18**. The `cap` upgrade adds `+14` per level; the `serenity` perk adds `+10` per level permanently.
> **DEV NOTE** — the post-mortem. The base cap was originally **8**, which is roughly what a real "manageable inbox" feels like. It was a disaster. On the Startup plane the flood plus the first ramp tick could overflow an 8-slot cap inside the first ten seconds, before a new player had read the help dialog or bought a single upgrade. The status bar screamed OVERWHELMED, income halved, and the player's first impression was a game punishing them for not yet knowing the rules. We rebalanced the base to 18 — about 20 seconds of grace at the opening rate — and re-tuned the `cap` upgrade's add from `+5` to `+14` so a single purchase is a *felt* relief, not a rounding error. The vestigial `+ G.ascensions*0` term is the scar: we briefly granted cap per ascension, decided perks should own that axis instead (`serenity`), and left the zeroed term as a deliberate marker of where the knob used to be. Don't delete it without reading this note — it's a comment that compiles.
### `isOverwhelmed()` and the penalty
```js
function isOverwhelmed(){ return now() < G.overwhelmedUntil || G.inbox.length > inboxCap(); }
function overwhelmPenalty(){ return isOverwhelmed() ? 0.5 : 1; }
```
Overwhelm is sticky. The instant `G.inbox.length` exceeds the cap, `step` sets `G.overwhelmedUntil = now()+1500` — a 1.5-second tail so that dropping to exactly cap doesn't flicker the status bar off and on every tick. While overwhelmed, `overwhelmPenalty()` returns `0.5` and is multiplied into *every* income path: `manualMult`, `ruleMult`, and through them every archive, reply, delete, and rule-banked dollar.
> **DEV NOTE** — the wired-in fix. The original overwhelm mechanic *slowed arrivals* when you were drowning — which is exactly backwards. It made the game easier the worse you were doing, so the inbox self-corrected and the pressure evaporated. The comment in `step` is the fossil of that decision: `if(isOverwhelmed()) rate *= 1.0; // arrivals don't slow; YOUR income tanks instead`. The `*= 1.0` is a no-op on purpose, a tombstone marking where the bad multiplier was. The real penalty moved into `overwhelmPenalty()` and was threaded through the multiplier functions so it could never be forgotten at a call site — there is exactly one place to be overwhelmed and exactly one place it bites. The status bar copy ("⚠ OVERWHELMED — income halved until you dig out") promises this to the player, so the constant is a contract, not a free parameter.
· · ·
## Triage actions and the keyboard
There are three manual actions, each operating on the selected mail. Productivity is banked through one of three multiplier helpers:
```js
function manualMult(){
return plane().ppMult * Math.pow(UP_BY_ID.hotkeys.mult, lvl('hotkeys'))
* perkMult('clarity') * overwhelmPenalty();
}
```
| Action | Function | Key | Payout | Notes |
|--------|---------|-----|--------|-------|
| Archive | `archiveSel` | `e` | `value × manualMult()` | `×readBonus()` if already read; `×0.85` if archived unread before the `reading` upgrade. |
| Reply | `replySel` | `r` | `value × 1.5 × manualMult() × replyMult()` | Costs `replyCost()` Focus (floor 3, default 8). The only action VIPs reward. |
| Delete | `deleteSel` | `#` / `Del` / `Backspace` | `(value×0.1 + 0.5) × manualMult()` | On a VIP instead: `value×0.5×manualMult()`, clamped at 0, with a warning toast. |
`reading` and Focus deserve a note. Archiving an *unread* mail "sight unseen" pays `×0.85` until you buy **Speed-Reading Course** (`reading`), after which reads pay a `readBonus()` premium instead. `archiveAllRead()` exploits this — it bulk-archives every read, non-VIP mail at full `readBonus`, which is the intended reward for the `j/k`-to-read-then-bulk-archive rhythm. Replies are Focus-gated: `replyCost()` currently floors at 3 but is wired to scale (the `8 - lvl('focusregen')*0.0` term is another zeroed knob awaiting a balance pass).
The keyboard handler is the volume's tactile hook. It early-returns inside form fields (so typing a rule pattern doesn't archive mail), respects `Escape` to close modals, reserves `Ctrl/Cmd+S` for save, and otherwise dispatches:
```js
switch(e.key){
case 'j': case 'ArrowDown': e.preventDefault(); moveSel(1); break;
case 'k': case 'ArrowUp': e.preventDefault(); moveSel(-1); break;
case 'e': e.preventDefault(); archiveSel(); break;
case 'r': e.preventDefault(); replySel(); break;
case '#': e.preventDefault(); deleteSel(); break;
case 'Delete': case 'Backspace': e.preventDefault(); deleteSel(); break;
}
```
A nice touch: if you're viewing a non-inbox folder and press a triage key, the handler snaps you back to the inbox first, so muscle memory never silently no-ops. `moveSel` marks mail read as it passes, which is what feeds `archiveAllRead`. The same actions are reachable from the toolbar, the Edit menu, and a right-click context menu — but the keyboard is the one that feels like a real mail client, and that fidelity *is* the design (see §5 of the manifesto: fidelity over flash).
· · ·
## The rules engine
Rules are the automation layer — the moment the game stops being twitch triage and becomes systems-building. A rule record:
```js
{field, op, pattern, action, enabled, hits}
```
| Field | Domain | Source |
|-------|--------|--------|
| `field` | `from`, `subject`, `address`, `type` | `RULE_FIELDS` |
| `op` | `contains`, `matches`, `is` | `RULE_OPS` (`matches` is regex, gated behind an upgrade) |
| `pattern` | string | user-entered |
| `action` | `archive`, `delete`, `reply`, `flag` | `RULE_ACTIONS` |
| `enabled` | bool | toggled by the checkbox in the manager |
| `hits` | int | lifetime auto-triage count, shown per-rule and summed in the folder tree |
### Compilation
`compileRule(r)` precompiles the matcher once, not per-mail. For `matches` it builds a case-insensitive `RegExp`; for `contains`/`is` it lowercases the pattern into `_needle`. A bad regex is caught and the rule is flagged `_bad` rather than allowed to throw inside the hot path:
```js
function compileRule(r){
try{
if(r.op==='matches'){ r._re = new RegExp(r.pattern, 'i'); }
else { r._re = null; r._needle = String(r.pattern).toLowerCase(); }
r._bad = false;
}catch(e){ r._bad = true; r._re=null; }
}
```
`contains` is a `String.includes`; `is` is exact equality; `matches` runs the precompiled regex against the *raw* field value (the `i` flag handles case). The "glob/regex" distinction in practice is: without the `regex` upgrade you have substring and exact matching only, which covers most real filtering (`address contains spam.` → delete). The `regex` unlock turns on the `matches` operator and full pattern power — the builder even suggests `^(prize|winner|won)` as a starter.
### Application and slots
```js
function applyRules(m){
const slots = ruleSlots();
const active = G.rules.filter(r=>r.enabled).slice(0, slots);
for(const r of active){
if(ruleMatches(r, m)){
r.hits = (r.hits||0) + 1;
autoTriage(m, r.action);
return true;
}
}
return false;
}
```
Two things are doing real work here. First, **rule slots cap how many rules actually run**`ruleSlots()` is `1 + lvl('ruleslots') + perkAdd('preset')`, and only the first `slots` *enabled* rules are evaluated. You can author more rules than you can run; the surplus sit dormant until you buy slots. Second, **first match wins** (the `return true`), so order is strategy — a broad `archive` rule above a specific `delete` rule will eat mail the delete rule wanted.
`autoTriage` mirrors the manual payouts but banks through `ruleMult()` (which adds the `rulespeed` upgrade and the `enlightened` perk on top of plane and clarity):
```js
function autoTriage(m, action){
let gain = 0;
if(action==='archive'){ gain = m.value; folderInc('archive'); }
else if(action==='delete'){ gain = m.value*0.1; folderInc('spam'); }
else if(action==='reply'){ gain = m.value*1.4; folderInc('sent'); }
else if(action==='flag'){ m.flagged=true; m._ruleHandled=false; G.inbox.push(m); return; }
const banked = gain * ruleMult();
G.pp += banked;
if(hasUp('autoresponder')) G.pp += banked * lvl('autoresponder')*UP_BY_ID.autoresponder.mult;
trackThroughput(banked);
}
```
`flag` is the odd one out: it doesn't bank or remove, it pushes the mail *into* the inbox with a highlight — the escape hatch for "auto-surface this VIP, don't auto-handle it." Everything else banks and is gone. The `autoresponder` upgrade skims a passive `12%`-per-level bonus on top of rule income, which is the idle payoff the spec promised.
`addRule()` is the gatekeeper for authoring: it rejects empty patterns, refuses when `G.rules.length >= ruleSlots()`, blocks `matches` without the `regex` upgrade, charges **5 Focus** to author, and refunds that Focus if the regex turns out invalid. So even building automation costs the regenerating resource — you can't spam-author rules while drowning.
> **DEV NOTE** — rules run in `simulateAway` too. Offline catch-up calls the exact same `applyRules` per spawned mail, which is the whole reason an idle inbox can stay near zero: your encoded judgment keeps working while the tab is closed. The welcome-back toast reports it honestly — "your Rules auto-banked **N PP**" — and warns if the inbox overflowed past cap while you were gone. If you ever change the arrival or rule math, change it in *one* place that both `step` and `simulateAway` call, or online and offline economies will silently diverge. They currently share `arrivalRate`, `genMail`, and `applyRules`; keep it that way.
· · ·
## Planes and prestige
The five planes are the prestige ladder, each a multiplier on both volume and power:
| Plane | `rate` | `ppMult` | Domain |
|-------|-------|---------|--------|
| Startup | 1 | 1 | `boringsoft.net` |
| Enterprise | 6 | 7 | `enterprise-corp.com` |
| Government | 32 | 55 | `agency.gov` |
| The Whole Internet | 180 | 520 | `all-of.net` |
| The Void | 1100 | 6400 | `∅.void` |
Note `ppMult` outpaces `rate` at every step (7 vs 6, 55 vs 32, 520 vs 180, 6400 vs 1100). Ascension is a *net positive* on throughput — the volume terrifies, but the power compounds faster. That's the carrot that makes climbing feel good rather than punishing.
### The Inbox-Zero gate
You cannot prestige on cooldown or by spending; you must **genuinely reach Inbox Zero**:
```js
function canAscend(){ return G.inbox.length===0 && enlightenmentFor()>=1; }
```
With the flood always arriving, hitting exactly zero is a real achievement — you have to out-triage or out-rule the incoming rate long enough to drain the last mail, then immediately ascend before the next spawn. `enlightenmentFor()` is the prestige currency, sqrt-scaled off `peakThroughput` with a floor of 2000 and a plane bonus:
```js
function enlightenmentFor(){
const p = G.peakThroughput;
if(p < 2000) return 0;
return Math.floor(Math.pow(p/2000, 0.42) * (G.plane+1));
}
```
`doAscend()` banks the Enlightenment, increments `plane` and `ascensions`, and resets the run: `pp`, `inbox`, `peakThroughput`, `spawnAccum`, `overwhelmedUntil`, and `folderCounts` all clear; Focus refills to max. Crucially it **keeps** perks and Enlightenment, and carries `perkAdd('preset')` rules forward — the **Inherited Filters** perk — re-stamping them with `hits:0` and recompiling. Your judgment survives the reincarnation even though everything else burns.
### Serenity perks (Enlightenment)
The five permanent perks, bought in the Ascend dialog with Enlightenment, persist across every run:
| Perk | Effect per level | Max |
|------|-----------------|-----|
| `clarity` | ×1.30 global Productivity | 50 |
| `serenity` | +10 base Inbox cap | 50 |
| `flow` | +0.4 Focus regen | 40 |
| `preset` | +1 carried-over rule slot per ascension | 20 |
| `enlightened` | ×1.25 Productivity from *rules* (compounds with `rulespeed`) | 40 |
The endgame is reaching Inbox Zero on **The Void** — the secret ending — where the mail rate is 1100× and the only thing that empties the inbox is an automation stack so complete it triages the entire internet faster than it arrives. The Ascend dialog acknowledges it: *"You are on The Void — the highest plane. Reaching Zero here is the secret ending."* Thematically it rhymes with every other volume's terminus — **Vol I — qBitTorrz**'s Singularity, **Vol II — DEFRAG.EXE**'s migrated platter — the substrate grown so large it's indistinguishable from no substrate at all.
· · ·
## Save-key registry and state shape
`freshState()` seeds the global `G`. The persistence-relevant keys:
| Key | Default | Role |
|-----|--------|------|
| `pp` | 0 | Productivity (the spendable run currency) |
| `focus` / `focusMax` | 30 / 30 | Regenerating pool for Replies & rule authoring |
| `enlightenment` | 0 | Prestige currency (persists) |
| `peakThroughput` | 0 | Best PP/s this run; drives `enlightenmentFor` and the ramp |
| `plane` / `ascensions` | 0 / 0 | Prestige depth |
| `inbox` | `[]` | Live mail array; the survival gauge's numerator |
| `sel` / `folder` | `null` / `inbox` | Selection and active folder |
| `folderCounts` | `{archive,spam,sent}` | Lifetime-this-plane processed counters |
| `upgrades` / `perks` | `{}` / `{}` | Level maps, keyed by id |
| `rules` | `[]` | Rule records (sans the recompiled `_re`/`_needle`) |
| `overwhelmedUntil` | 0 | Sticky-overwhelm timestamp |
| `spawnAccum` | 0 | Fractional-arrival accumulator |
`sanitizeState()` is the guard that makes a corrupt save un-brickable, per the shared contract. It coerces every numeric to a finite default, clamps `plane` into `[0, PLANES.length-1]`, drops unknown upgrade/perk ids, rebuilds the inbox array element-by-element (defaulting unknown `type`s to `work`), and — importantly — **revalidates every rule against `RULE_FIELDS`/`RULE_OPS`/`RULE_ACTIONS` and recompiles it**, so a save edited to contain a malicious or malformed regex can't execute as anything but a flagged-`_bad` no-op. It also reconciles `_mid` past the highest surviving id so new mail never collides with loaded mail.
· · ·
## If you change this
- **`inboxCap()` base (18).** This is a tuned grace window, not a free number — read the cap post-mortem note above. Lowering it reintroduces the open-second overwhelm that made new players feel punished. If you change it, re-tune the `cap` upgrade's `add` (14) in the same pass.
- **The overwhelm penalty.** `overwhelmPenalty()` returns `0.5` and the status bar literally promises "income halved." It is wired through `manualMult`, `ruleMult`, and `autoTriage`. If you change the factor, change the UI copy; if you add a new income path, route it through a multiplier helper, not a raw `G.pp +=`. Do **not** resurrect the arrivals-slow-down mechanic — the `*= 1.0` tombstone in `step` exists to stop exactly that.
- **`arrivalRate()` and the ramp.** Online (`step`) and offline (`simulateAway`) must call the same rate, generator, and rule code or the two economies diverge. The `0.8` base and the `log10×0.18`, cap-8 ramp are balanced against the plane `rate` table — bumping one without the other breaks the climb.
- **`value` is base, not banked.** Never bake a multiplier into a stored `value`, or post-ascension mail underpays. Apply multipliers at triage time, always.
- **First-match-wins + slot truncation.** `applyRules` evaluates only the first `ruleSlots()` enabled rules and stops on first match. If you make rules run in parallel or all-match, you change the core strategy (rule ordering) and must rewrite the manager's "Active rules run top-to-bottom; first match wins" copy.
- **The zeroed knobs (`G.ascensions*0`, `lvl('focusregen')*0.0`).** These are intentional markers of retired or reserved balance axes. Don't prune them as dead code without reading why they're zero — they document where a tuning lever used to live, or will.