TL;DR : a grid_size INT column on three tables (rooms, players, card_templates) looked like a sane denormalization for a multiplayer bingo game. Two months later I deleted it on all three tables, because the value is tautologically encoded in another column already in those rows. Derived state at read time was simpler, smaller, and less buggy. Here's the trail. The setup I'm building BingWow, a free real-time multiplayer bingo platform. Each player has a board JSONB column that stores their cells: clue ids, positions, and image references. Boards are 3×3 (9 cells), 4×4 (16), or 5×5 (25). Mobile players are clamped to 3×3 regardless of the host's pick — it's an intentional product invariant.…