The bug museum
A place to actually touch the broken version. Most write-ups end at "there was a bug and here is the fix", which leaves the reader with nothing, because they never met the bug.
Exhibit one — try it
Below is the hit test exactly as it shipped. Press right on the green arc: it counts as a miss. Flip the switch and the same screen runs the fixed version. The two look identical — one comparison operator apart.
A game shipped with its hit test inverted
What happened
초록 구역을 정확히 눌러도 실패하고, 정반대를 눌러야 성공했습니다.
Why
각도 차이를 −π..π 로 접은 뒤 '구역 반폭보다 작은가'를 봐야 하는데 부등호를 반대로 썼습니다. 화면에는 구역이 제대로 그려지고 바늘도 제대로 돌기 때문에, 눌러 보면 '내가 못 맞혔나' 로 보입니다.
How it surfaced
브라우저로는 못 잡았습니다. 확인용 창이 가려져 있으면 애니메이션이 멈춰서, 그 화면에서 확인할 수 있는 것은 '첫 프레임이 그려졌다'까지였습니다. 규칙만 떼어 node 에서 재 보고 나왔습니다.
The fix
부등호를 뒤집고, 0도를 넘는 자리까지 포함해 판정 검사 10항목을 남겼습니다.
A CSS fix that erased a different button
What happened
고스트 버튼이 흰 배경에 흰 글자로 안 보였습니다. 고쳤더니 이번에는 기본 버튼이 까만 배경에 까만 글자가 됐습니다.
Why
<button> 에 남는 브라우저 기본 배경을 지우려고 button.btn 규칙을 넣었는데, 그 선택자의 특이도가 .btn-primary 보다 높아서 primary 의 배경색까지 함께 지웠습니다.
How it surfaced
둘 다 사용자가 먼저 봤습니다. 첫 번째는 캐시된 옛 CSS 때문에 고쳐 배포한 뒤에도 화면이 그대로였고, 그래서 '고쳤다'고 잘못 말할 뻔했습니다.
The fix
:where() 로 감싸 특이도를 0 으로 만들었습니다. 그리고 게이트에 button.btn 원시 선택자 금지 검사를 넣고, 일부러 되돌려서 실제로 잡히는지 확인했습니다.
Holes that appeared every time the wave went up
What happened
우측 하단에 블록도 장애물도 없는 빈 칸 세 개가 남았습니다.
Why
판이 오를 때 침식을 한 겹 벗기는데, 그 뒤에 블록을 내려 채우지 않았습니다. 매치로 벗길 때는 지우기 → 중력 → 리필 경로를 타지만 판 상승은 그 경로를 타지 않았습니다.
How it surfaced
실기기 제보로 알았습니다. 그리고 잡는 과정에서 검증에서 세 번 틀렸습니다 — 검사가 210초 동안 단 한 번만 돌았고(통과 횟수를 안 세면 0회 통과도 통과로 보입니다), 실패한 패치를 성공으로 보고했고, 엉뚱한 곳을 의심했습니다.
The fix
'빈 칸에는 반드시 침식이 있어야 한다'는 불변식을 세우고, 자동 플레이 중 계속 확인하는 모드를 만들었습니다. 시드 세 개 × 600여 회 통과, 수정 전에는 세 시드 모두 위반했습니다.
Why keep these
All three have one thing in common: they looked fine on screen. The inverted hit test drew its arc and needle correctly, the invisible button still occupied its space, and the holes stayed unnoticed until a later match touched that column.
So each fix left a check behind. And each check was itself checked by breaking the code again on purpose — one of them failed to catch anything the first time. A check that cannot catch its own bug is not a check.
The build notes are in the dev log, and what each genre needs is here.