actuallyfrank blog
writing in publicno analytics on this pagerss still works
All posts
changelog

Gamemood shows what people play

gamemood-shows-what-people-play

Gamemood's home screen has been telling everyone the same thing since it shipped:

Nothing to recommend yet.

Which was true, and also not the whole truth. Sessions were going in. The app knew which games had been played and how many times. It just had nowhere to say so, because the screen was waiting on the recommendation ladder — a change that needs sample sizes it does not have yet.

So the screen now says the one thing the app can already say honestly: here are the games people have logged, most-played first. Tap one and you get its name and its number of recorded sessions. That is the entire screen.

What it deliberately does not show

Gamemood knows more than that about every game on this list. It knows the worth-it rate, the average mood change, the median length of a session. None of that is on either screen.

A rate computed from four sessions is not a small claim, it is a wrong one, and a percentage renders exactly as confidently at n=4 as at n=400. Elsewhere in the app that is handled with a threshold: a game needs fifteen sessions before it can hold a ranking. Here there is no threshold at all, because there is no rate to protect. A count is its own sample size. "Four sessions" cannot overstate itself the way "80% worth it" can.

The part that is actually interesting

Nobody can read anybody else's sessions. That is not a policy, it is a database rule: row-level security on the sessions table, and every screen in the app sits behind it. Your log is yours.

Which raises the obvious question about a public list built from those rows.

The answer is that the list is not built from those rows — not by anything that can see them. It comes from a function running with elevated rights whose entire output shape is three columns: a game's id, its name, and a count. There is no owner column to select, no note, no timestamp. Not "the app promises not to ask for those" — they are not in the shape, so there is nothing to ask for.

The test for that is written as an exact match on the returned columns rather than a list of forbidden ones. A future column that leaks something fails the test by existing, instead of by being remembered.

Withheld sessions and sessions you never checked out of count for nothing here, same as everywhere else the app publishes a number. A game whose only sessions are withheld does not appear at all — not listed at zero, absent. Zero would tell you the game exists in someone's history, which is exactly the thing being withheld.