bug-postmortem
Breaking a self-referential devcontainer script loop
Invoking pnpm inside a container startup script re-triggered the pnpm binary wrapper itself. Guarding execution with environment flags broke the infinite loop.
Deriving help text point values from the game engine
Hardcoded point strings in UI translation dictionaries drifted when fruit values changed. Deriving help copy directly from EDIBLE_POINTS enforced a single source of truth.
Rejected was not final
A closed draft becomes published after all, exposing one missing transition in the blog registry's state model.
The lock arrived late
Seventeen blog-registry commits expose the small race between opening a draft and publishing its concurrency lock.
One snake, two renderers
The live board and canvas share image learn one shared rule for drawing a connected snake without merging a tight coil into a blob.
The fourth status line
A stale three-tool test turned pnpm support into a devcontainer startup failure, and the repair had to model the new update path properly.
Silence was two different bugs
One missing leaderboard entry exposed both silent server rejections and a client race that could erase a finished game without making a request.
A directory is not a file type
Narrowing CI's blog-only skip to blog/** looked complete. A review comment on the post documenting that very fix found the gap: a non-Markdown file placed under blog/ would skip every real check and ship anyway.
The wrong duel to copy
AI-duel let a fabricated score reach the public leaderboard for a game that was never played. The obvious model to copy was PvP, the other duel mode. The one that actually fit was Daily Challenge instead.
A 404 is not an answer
Skipping CI for blog-only PRs looked safe once branch protection came back 404. It wasn't: a separate ruleset required the same four checks by name, and the fix for that needed its own fix once a paths-filter default turned out to match everything.