Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
335 changes: 335 additions & 0 deletions docs/superpowers/specs/2026-08-08-post-v1.9-idea-backlog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
# Post-v1.9 idea backlog

**Status: CAPTURED, NOT DESIGNED.** Owner's ideas from 2026-08-08, written down
so they are not lost. Nothing here is approved, scoped or scheduled.

This is deliberately *not* a plan. The process that has worked on this project
is brainstorming → spec → plan → subagent-driven implementation → whole-branch
final review, and skipping to a plan is how ideas acquire accidental
requirements. Each item below is the raw idea, what it touches, and anything
already known that constrains it.

Several of these are large enough to be their own release. A plausible grouping
is at the bottom.

---

## Two constraints that cut across most of this

**1. The economy is server-authoritative and lazily evaluated.** Nothing ticks
in real time — state is computed from the last-seen timestamp forward when a
request arrives. So **anything time-based must be *schedulable*, not rolled
live**: pick the moment ahead, store it, and let evaluation notice it has
passed. The existing precedent is `scheduleAnomaly` in `shared/reducer.js`:

```js
server.nextAnomalyAt = now + minDelayMs + rng() * (maxDelayMs - minDelayMs);
server.anomalyExpiresAt = server.nextAnomalyAt + windowMs;
```

Randomness is injected (`rng = Math.random`) rather than called directly, which
is what makes it testable. Every "bad events happen at a certain time" and
"Grid nodes go down" idea below should extend this pattern rather than invent a
new one. An event rolled at the moment a request happens to arrive cannot be
reconciled against offline progress, and offline progress is a headline feature
of this game.

**2. `users.id` is `provider:providerId` and is referenced by three foreign
keys.** It never changes. Anything touching identity has to work without
rewriting it.

---

## A. The leaderboard hides reset players — this one is a bug

> "The leaderboard should show 0s even after users reset their cores after a
> singularity."

**Diagnosed.** `server/leaderboardService.js` builds every board with:

```js
.filter((r) => r.value > 0)
```

So a player whose `legacyCores` went to 0 in a Singularity does not show as
`0` — they **vanish from the board entirely**. Same for any board whose value
resets.

The filter is not gratuitous: without it every registered account that has
never played would sit on every board at 0. So the fix is not "delete the
filter", it is "distinguish a player who reset from one who never started".
`allTimeFlops` reads `meta.stats.lifetimeFlopsAllTime`, which survives every
prestige, so it can discriminate — include a player when they have any
all-time activity, even when *this* board's value is 0.

Worth deciding explicitly: should a reset player rank *below* everyone with a
positive score (0 sorts last naturally), or be pinned with a "just prestiged"
marker? The second is more interesting — a Singularity is an achievement, and
currently it looks like disappearing.

Small, self-contained, and fixable well before the bigger items.

---

## B. Risk and mitigation — the largest new system here

> "Bad events should happen at a certain time (like drive failures, technician
> failure, malware). You then have to buy antivirus or something else in the
> store to get rid of the bad effects. Add the ability to buy cybersecurity
> insurance to offset ransomware automatically (but it gets used up) — backup
> ISP for ISP outages — backup hard drives for hard drive failures."

This is a genuine second axis for the game: today everything is monotonic
growth, and this introduces loss to defend against.

**Shape it borrows from:** `scheduleAnomaly` already schedules a timed
opportunity with an expiry window. A hazard is the same machinery with the sign
flipped — schedule it, let it fire, let it expire.

**The interesting design question** is the mitigation economy, because there are
two distinct kinds and they should feel different:

- **Reactive** ("buy antivirus to get rid of the bad effect") — a cure. The
player is already hurting and pays to stop it.
- **Prepaid and consumable** ("insurance ... but it gets used up", backup ISP,
backup drives) — a hedge bought before anything happens, which silently
absorbs one hit and then needs restocking.

The prepaid kind is the better mechanic: it rewards planning, creates a
recurring sink, and the moment it silently saves you is satisfying *only if the
game tells you it did*. A consumed insurance policy must produce a visible
"ransomware absorbed" notification, or the player never learns the hedge was
worth buying.

**Constraints:**
- Hazards must respect offline time. If a player is away 12 hours and a drive
fails at hour 3, evaluation has to apply it from hour 3 — not on next login —
or the offline-gain calculation lies.
- There has to be a floor. A player returning to a wrecked rack with no
currency to repair it is a dead save. Consider capping hazard severity by
progression, or guaranteeing repairs are always affordable from what the
hazard itself didn't destroy.
- Cold Storage is offline-gated by design; decide whether hazards can strike it
or whether it is a safe harbour (a good reason to keep tapes there).

---

## C. Make the Grid dynamic

> "things like home volunteers and university clusters aren't on all the time,
> there could be downtime or other maintenance"

Thematically strong — it is exactly how volunteer compute behaves in reality,
and it gives the Grid a personality distinct from the Racks.

Same scheduling constraint as B. Natural extensions: university clusters idle
on a term schedule, home volunteers drop off in the evening, and a maintenance
window the player can *see coming* so it is planning rather than punishment.
The difference between "the Grid is unreliable" and "the Grid is unreliable in
a way I can route around" is whether the downtime is visible in advance.

Interacts with B: if hazards and Grid downtime both reduce output, they need a
shared notion of "capacity currently offline" so the UI can explain a slowdown
with one coherent story instead of two competing ones.

---

## D. Overclock rework

> "The overclock should be a multiplier against the Racks, but then should turn
> off a rack at random when you overheat"

Converts Overclock from additive to a real risk/reward dial. Note v1.6 already
made venting percentage-based and added an auto-dismissing overheat popup, so
the heat UX this builds on is recent and deliberate — worth re-reading that
work before changing what overheating means.

A rack switching off at random needs the same determinism treatment: which rack
must be derivable, not rolled fresh on each evaluation, or two clients
reconciling the same overheat could disagree about which rack died.

---

## E. Buy-to-milestone buttons

> "Add a button on the Racks, Grid, and Overclock that buys to the next
> milestone"

Straightforward quality-of-life, and the kind of thing that quietly removes a
lot of clicking.

**Known trap:** `UpgradesPanel.jsx` and `SingularityPanel.jsx` read upgrade
maximums from the static definition's `maxLevel` rather than the live
`config.upgrades.maxLevels[id]`, so admin balance edits do not reach them.
`ColdStoragePanel.jsx` does it correctly. A "buy to next milestone" button that
inherits the static-def bug would compute its target from numbers the server
does not agree with, and the server is authoritative — so it would visibly
overshoot or stall. Fix the config read as part of this, not after.

---

## F. A third prestige

> "What about a third prestige that is a HARD reset with Cold Storage and sets
> back to absolute zero with something special. Maybe something with a portal"

**Note the deliberate inversion.** Cold Storage's Tapes and its 7-upgrade tree
were specified to *survive* Migrate and Singularity — that permanence is what
makes the offline lane feel worth investing in. A third prestige that wipes it
is not an extension of the existing ladder, it is a reversal of a design
promise, and it needs to buy something proportionate.

That is not an objection — a prestige that finally takes the thing nothing else
could take is a strong hook, and "absolute zero" earns a genuinely different
reward tier. But it should be designed as such rather than slipped in as a
third rung.

The portal idea is worth developing: it suggests the reward is *access* to
something rather than another multiplier, which would be a welcome change of
shape at that depth.

---

## G. Unique items you can place in your racks

> "Brainstorm a way to have unique items as rewards that you can add to your
> racks. This should be an event and special achievement award"

The most open-ended item here, and the one that most changes what the game is —
it introduces collection and identity alongside optimisation.

Things to settle early: are items cosmetic, functional, or both? Do they
survive prestige (if they are event rewards, almost certainly yes — an
unrepeatable event reward that a prestige destroys is a trap)? Are they
tradeable (no, presumably — that is an economy)? And how do they render, since
the rack view is the game's main visual surface.

Ties naturally to F's "something special" and to the event system, which
already has per-user participation tracking and a rung ladder to hang rewards
on.

---

## H. Event theming with custom CSS

> "Custom CSS import for the events to allow leaves and snow falling for the
> winter ones. Money falling for the Black Friday event"

Great instinct — seasonal events currently change numbers and copy but not
atmosphere.

**Do not implement this as arbitrary operator-supplied CSS.** Events are
authored by `event_coordinator`, which is deliberately the *lowest* of the
three roles (owner > admin > event_coordinator). Arbitrary CSS injected into an
authenticated page is not cosmetic — attribute selectors combined with
`url()` can exfiltrate page contents to a remote host, and it would hand the
least-trusted role a data-exfiltration primitive against every player,
including the owner.

The safe version gives the same result: a **named effect registry** in the
client (`snow`, `leaves`, `money`, `embers`, …), with events selecting an
effect id plus a few bounded parameters (density, colour from a fixed palette,
speed). Coordinators get the creative control they actually want; nobody gets
to ship a stylesheet. If freeform styling is genuinely needed later, restrict
it to owner-authored themes, not event config.

---

## I. Shard sinks, including themes

> "Shard store to buy boosts? We need some other way to spend Shards. Also add
> a way to buy different themes"

A real gap — Singularity Shards currently have one destination, so past a point
they accumulate meaninglessly.

Themes are a particularly good sink: purely cosmetic, permanent, no balance
risk, and they pair with H's effect registry (one visual system serving both
event atmosphere and player-bought themes). Boosts need balance care since
shards are unbounded over time — prefer permanent small unlocks or repeatable
consumables over stacking multipliers.

---

## J. Badge progress bars

> "For badges, add a progress bar for each badge to show the user where they
> are in the process"

Achievements exist and unlock silently against thresholds. Showing distance to
the next one turns a list of things you happen to have into a set of goals.

Requires each achievement to expose its progress as (current, target) rather
than just a boolean — a change to how achievements are defined, not just
rendered. Some may not have a meaningful scalar (one-off events); those should
degrade to locked/unlocked rather than a fake bar.

---

## K. Minigame high scores

> "Track high scores in Games"

Small and self-contained. Minigame sessions are already server-mediated
(`/api/minigame/start` and `/finish`), so the score already reaches the server
and there is somewhere honest to record a best. Pairs naturally with the
leaderboard work in A.

---

## L. Link multiple auth providers to one account

> "When adding SuperTokens, we should add the ability to link multiple auth
> types and join based on email. Multiple auth types (ie. GitHub and Discord)
> should be allowed to be linked to a single user"

**The schema already supports this.** `identities` is keyed on
`(provider, provider_id)` with a `user_id` foreign key and an index on it —
two identity rows pointing at one `users.id` is exactly the intended shape, and
v1.7 split identities out of `users` precisely so this would be possible.
`users.id` never has to change. So this is a *flow* problem, not a migration.

**But "join based on email" is the dangerous half, and it is already documented
as such** in `docs/authentication-methods.md`: automatically linking accounts
that share an email address is an account-takeover vector. If someone registers
a GitHub account using an email that matches an existing Discord player, they
inherit that player's save, shards and admin roles. The provider asserting the
email does not make it safe — email ownership is not verified consistently
across providers, and RackStack currently uses email for nothing at all.

**The safe design:** linking is an authenticated, deliberate act. A logged-in
player goes to settings, presses "link Discord", completes that OAuth flow, and
a second `identities` row is written pointing at *their* existing `user_id`.
Identity is proven by the live session, never by a string match. Email matching
can at most *suggest* "this looks like your account, sign in with GitHub to
link it" — never perform the join.

Also relevant if email enters the picture: adding any email-bearing recipe
makes the previously-accepted nodemailer advisory live again.

---

## A plausible grouping

Not a commitment — just how these seem to cluster:

- **Quick wins, mostly independent:** A (leaderboard zeros — arguably a bug fix
that should not wait), E (buy-to-milestone, with the config-read fix), K
(minigame high scores), J (badge progress).
- **One release: risk & reliability.** B and C and D share scheduling
machinery, a "capacity offline" concept and a notification surface. Doing
them together is much cheaper than separately, and they are incoherent apart.
- **One release: identity.** L on its own, small and security-sensitive enough
to deserve its own review.
- **One release: expression.** H (effect registry) + I (shard store, themes),
since both want the same visual system.
- **Needs real design work first:** F (third prestige) and G (unique items).
These change what the game is, and G in particular should be brainstormed
properly before anyone estimates it.

## Standing obligation

Any of these that ships a feature tour must also append its steps to
`client/src/game/data/tours/onboarding.js` — completing the onboarding tour
marks every registered tour complete, which is only correct while onboarding
remains a superset. No test catches a violation.
Loading