maniator / maniator/verticopolis
[P3] Decide whether the crash and `$exception` throttles should persist across a same-tab reload
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 5
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
Deferred from the Codex review on PR #840, verified before deferring.
Both throttles live in module memory, so a reload gives each a fresh budget. The analytics session id lives in sessionStorage and deliberately survives a same-tab reload (src/analyticsRelay.ts, so an "Update now" reload or a crash-recovery reload keeps one continuous session). The caps are therefore per page life, not per session, and one distinct_id can carry more than ten of either.
PR #840 renamed both constants to MAX_CRASHES_PER_PAGE_LIFE / MAX_ERRORS_PER_PAGE_LIFE, corrected the docs that claimed "one session sends", and pinned the seam with a test, so nothing is now mis-stated. What is left is the design question.
The reachable path. The crash screen's reload button calls location.reload() (src/game/saveLoad.ts), the fresh boot resumes the tower via RESUME_AFTER_RECOVERY_KEY, and if the GPU is still dead it crashes again with a fresh budget under the same distinct_id.
The argument for leaving it. The flood the cap exists to stop needs no reload at all: the crash screen re-shows in place on each context loss, which is how one page life reached 8,269 events on 2026-09-12. Reloads are human-paced (one button press each), so they are not a plausible route to the per-IP ingest budget. And a crash that survives a reload is a genuinely different incident: the player asked for a fresh page and the GPU died again, which is the escalation worth seeing rather than suppressing. boot already fires once per page life, so the page-life structure is recoverable from the data.
The argument for persisting it. The cap then means what a reader assumes across the whole session, and a pathological reload loop cannot multiply it. Codex also suggested enforcing the cap server-side as an alternative, which would be robust to the client's memory model entirely, at the cost of putting per-session state in a stateless ingest route.
If it is persisted, two things to get right: writing on the crash path is exactly where storage is least trustworthy (saveLoad.ts already wraps its sessionStorage access in try/catch for that reason), and the stored state must be namespaced with the session id so a genuinely new tab starts clean.
src/analyticsThrottle.ts, src/analyticsSession.ts, src/analyticsErrors.ts, src/analyticsRelay.ts. Related: #842 (the $exception throttle is also not re-opened on a consent epoch while the crash throttle is). /bmad-code-review.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read src/analyticsThrottle.ts, src/analyticsSession.ts, src/analyticsErrors.ts, src/analyticsRelay.ts, and the reload path in src/game/saveLoad.ts. Trace how the crash and $exception counters relate to sessionStorage and the analytics session id, then decide whether same-tab reloads should share budgets. Done means the chosen policy is implemented consistently, with storage failures and session namespacing addressed if persistence is selected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- analytics
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100