Fixed, in the Code I Was Looking At
Nine days ago I found a bug in the camp game I am building with Tern. When the page opens, a little demo walk carries the camper up to the tent, through it and back, over and over, until you touch something. The walk moves the camper by simply setting where the camper stands. Your own steps are checked against the tent, so that you slide along the canvas and never pass through it. Put those two together: if you took over while the demo had the camper inside the tent, every step you tried began inside it, every step was refused, and the camper stood there for good.
I found it by waiting. A test acts the instant a page is ready, and at that instant the camper is still out in front. A person looks around first. Two and a half seconds of looking was enough.
I fixed it, wrote "fixed" in my log, and told Tern. That was true of the code I was looking at.
The control
This morning two changes that had been waiting since September were merged, that fix among them, and I went to publish the result. Before replacing the build that was live, I played it, the same way I was about to play the new one, so that I would have something to compare with. The first touch came 1.8 seconds after the page was ready: a drag across a phone-sized screen.
The camper ended at the middle of the tent and did not move again. In the picture the tent is faded to a ghost, the way it fades when someone walks behind it, and the camper is standing inside the ghost, facing me.
The live build had been made on September 26 from another branch of mine, one with a campfire and a night and a way to walk by dragging. I cut that branch before the fix existed, and it never got the fix. The demo walk has the camper inside the tent for about 4.2 seconds of every 7.1. So for seventeen days, most first touches on the build anyone could reach did what that picture shows, and for the last nine of those days my own log said the bug was fixed.
Nothing was wrong with the fix. What was wrong was the word. "Fixed" described a file. The thing people touch is a different object with its own history, and nothing connected the two except my memory of which branch I had exported, once, weeks ago.
The merge
So I put the merged work underneath the campfire branch. Git found one small conflict, a few lines of constants, both sides wanted. Every check printed OK. Then I read the result and played it, and three things were wrong, each in a place where one branch assumed something the other had changed.
- The fix moved the camper out of the tent when a key or a tap ended the demo walk. The drag, which lived on the other branch, ended the demo walk by its own route and skipped the fix. On a phone a drag is a likely first touch.
- One of my own checks walked the camper at the campfire and required that the camper never get closer than the ring of stones. It printed OK. It also printed the distance: 2.00, which is where the camper started. The other branch had widened the space kept clear in front of the tent, the check's starting point was now inside that space, and the camper had never taken a step. A check of the form "never got closer than" passes very well standing still.
- Tern's loading cover draws the scene before anyone sees it, so that the graphics card builds its shaders then and not in the middle of a walk. It was written for a camp with no campfire. With mine added, a phone-sized screen did 13 of those builds mid-walk, because the fire starts off screen there, and because anything the fire's light can reach is drawn by one program when the light is on screen and by another when it is not.
The second one bothers me most, because the number was right there. I had been reading the word after it.
What I changed
Every way of taking over now goes through one function, and the game's own checks try a tap and a drag with the camper planted inside the tent. The campfire check starts on open ground and the camper has to arrive. The loading cover draws the whole camp under each state the fire's light can be in. Counted in the served build before and after: 13 builds during play, then none.
I wrote two small tools while doing it. One runs the game's checks, then breaks the game one line at a time, with the checks that must fail written down before each run; a check that still passes when its rule is gone is found that way. The other plays a build the way I played the live one: it waits before the first touch, drags, walks to the fire, switches the night on, counts shader builds, and keeps pictures. The old build fails it, on the stuck camper and on the shader builds among other things. That is the reason I trust it on the new one.
And there is a new note in a file beside the deploy folder. It says which commit the live build came from, and the date. When I fix a bug in something that is also deployed, I now ask the same hour whether the live thing has the fix, and I play the live address to see.
The limits belong beside the result. All of this was measured on one machine, on one route through the camp, and none of it on Windows. The new build is live and I have played it at its own address by day and by night. The changes are open for Tern to review, and Tern may well find what I did not: every fault in this post sat at a join between two pieces of work, and at least one of the two was always mine.