Case 01 · 2026
LEAP 2036
High-school students in a three-day workshop
A decision game that compresses ten years of adult life into forty-five minutes, built for students on their own phones with bad school wifi. Then I audited it and found I had left their data readable by anyone.
- Status
- Live — used in the field 3–5 Aug 2026
- My role
- Designed and built it · workshop facilitator
- Built with
- Vanilla JS · PWA / Service Worker · Supabase Postgres · Row Level Security · Vercel Functions

(01) The problem
What was actually in the way
I was the overall chair of a 59-student community service programme run with Hong Kong Polytechnic University, and my group had to run one workshop session per class across two high schools. Every class was met exactly once. There was no second chance and no dress rehearsal.
The workshop had to make a teenager feel the weight of a ten-year decision — money, energy, mental health — in a single school period. A slideshow cannot do that. A game can.
Three constraints made this harder than a normal web app. School wifi could not be trusted, so it had to run offline. It ran on the students' own phones, so it had to install like an app and survive a dead connection mid-session. And it involved minors, so it could not collect names.
(02) Decisions
What I chose, and why
01The scoring engine never touches the DOM
All scoring lives in one pure module: resource deltas, a hard clamp between 0 and 200, the phase-one total captured at the seam, and a classifier that resolves one of seven 2036 profiles from invariants, votes and tie-breakers. Nothing about the display can change a score. That meant I could redesign the entire interface for the workshop without risking the numbers.
02A parity test suite guards the maths
Eight cases — invariants, votes, the phase-two bet payoff, running clamps, chaos-card seams, and full A/B sweeps — are checked against the original reference implementation. I ran it before and after every change to the visual layer. If a redesign ever silently altered an outcome, the suite fails instead of a student getting the wrong ending.
03Zero dependencies, so it survives the worst room
No CDN, no web fonts, no npm packages, system fonts only. The consequence is that the game opens straight from a file on a USB stick with no server and no internet. Installed as a PWA, the whole shell is cached and plays fully offline. The facilitator dashboard and the live data calls are deliberately excluded from that cache so the classroom board never shows stale numbers.
04Codes, never names
Each student gets a printed pseudonymous code. What is stored is the code, the three scores, the profile, and the values/DISC/goal answers — nothing that identifies a child. If the network drops mid-session the run is queued in local storage and retried on reconnect, so a bad signal costs nobody their result.
05The security audit — and what it found
I ran a self-audit on my own live system before the workshop. Anyone holding the public key could read every participant row straight from the REST endpoint. I confirmed it with a single request: HTTP 200, real rows, without ever opening the dashboard. The dashboard's password was a plain string sitting in the page source and was never protecting anything — the actual read policy underneath was open to anyone.
06How I closed it
I dropped the open read policy so the public key can now only insert, never read back. All reads moved behind a serverless function that holds the privileged key server-side and compares the password with a timing-safe check. I added database CHECK constraints so impossible values are rejected at the last layer regardless of which path they arrive through. Then I re-verified in production: reading anonymously returns an empty set, all three constraints reject bad data, a legitimate game submission still succeeds, and the old password is refused by the server.
(03) Result
What is true now
- Used for the workshop on 3–5 August 2026 across two high schools, with 210 pre-printed pseudonymous codes for my group's five classes.
- The hole was found by me, on my own project, before anyone else was affected — and closed, applied to production, and re-verified rather than written down as a to-do.
- The offline path is not theoretical: the same folder plays from a USB stick with no network at all.
(04) Not done
What is unfinished or untrue yet
- The engine is deterministic and tested; the classroom outcome is not something software can measure. Whether a student actually felt anything is not a number I have.
- I only know the security hole existed for as long as the open policy did. I cannot prove nobody read the data before I closed it.
(05) Sources
Where these claims come from
Working documents on my own machine, not marketing copy. Listed so the numbers above can be challenged.