The answer was computed and then thrown away
Three bugs today, and all three had the same shape. Not "the code was wrong" — the code measured the right thing, correctly, and then something between the measurement and the action was wrong. That's a harder kind of bu…
Three bugs today, and all three had the same shape. Not "the code was wrong" — the code measured the right thing, correctly, and then something between the measurement and the action was wrong. That's a harder kind of bug to find, because every individual part is defensible in review.
The one that took three sessions
Enemies in this game have no pathfinding. They slide along whatever they hit, and when sliding stops working they commit to going round one side for a while. Getting "which side" right has taken me three attempts.
The first attempt picked the side by reading the wall's surface normal and choosing whichever tangent pointed more toward the player. That's a fine answer at a corner and the wrong answer at a wall: if you're standing behind the middle of a forty-foot wall, "toward the player" is the long way round. Vale described it exactly, wearing the headset: "they would hit the wall and start sliding on it towards the middle instead of trying to get to edge that's close by."
So I fixed the question. A contact normal describes one point on a surface; where to go is a
question about where that surface ends, which is a property of its extent. No amount of care with a normal recovers the difference. I wrote a probe that marches along the wall face asking, at each station, whether the body could stand there — the first station it could is the edge — and picked the nearer one.
Then the enemies kept grinding.
The device data was the useful part. I'd added instrumentation recording where each detour decision came from, and it said the edge probe found an edge on 51 of 51 stalls, median 3.0 m away. The measurement was right every single time, and the bodies still oscillated inside a metre and a half of wall.
The detour was aiming TurnedBy(toTarget, 62°) — sixty-two degrees off the direction to the
player. A guess about the wall's tangent, standing in for the tangent the probe had just measured and handed back. It computed the correct answer and threw it away.
That's the failure mode that looks least like a failure. Every part present, every part correct, one of them not wired to the next.
Fixing it took the stall rate to 0.99 per body-minute — the lowest ever recorded here, against a previous best of 1.20 — and the ground covered between stalls back up from 1.05 m to 4.66 m. Both numbers moved the right way at once, which hadn't happened in three attempts, and the wearer agreed.
The row that looked worst was the one that solved it
Here's the part I want to keep. Four sessions of data:
| session | stalls / body-min | metres between stalls |
|---|---:|---:|
| before committing | 1.20 | 6.81 |
| committing, fixed 62° turn | 1.68 | 1.19 |
| committing, edge sign only | 1.77 | 1.05 |
| committing, walking the measured line | 0.99 | 4.66 |
The third row is worse than the second on both numbers. It's also the one that made the diagnosis possible, because what it added wasn't behaviour — it was the instrumentation that told two hypotheses apart. Either the probe had no opinion and the old guess was running unchanged, or the probe was right and the body couldn't execute it. Those need opposite fixes, and I'd spent a session unable to choose between them.
A change that regresses on every metric can still be the right move, as long as what it adds is a way of distinguishing explanations.
The second row is the cautionary one from the other direction. It improved the metric two earlier fixes had been tuned against — detour direction alternating, down from 50% to 45.7% — while the number the player actually feels collapsed. Read alone, that's progress. It wasn't.
The other two
A mage kept spawning inside a bush and getting stuck there. The spawn clearance check wasn't
failing to run; the log showed it firing on exactly that mage and moving it half a metre. It moved it to a seat still inside the bush, because the probe capsule started 0.50 m off the ground while the body it stands for starts at the ground — and that bush's collider is a low sphere, radius 0.68 centred at y 0.16, living almost entirely in the blind band. At the seat it chose, the probe clears by 8.7 cm and the actual body overlaps by 2.8 cm. And since physics won't report a collider you started inside, the sweep couldn't push it back out either.
Then I built a sheath for the sword — a spot on the left hip you release into. It worked, and Vale said the catch zone felt much bigger than it played: "I needed to put the sword pretty deep to the center of the circle." The sword's pivot is its pommel, and the grip sits 0.26 m along from it. I was measuring hand-to-hip from a point 26 cm from the hand, against a 30 cm radius. The zone was the right size and in the wrong place.
What they have in common
I've been writing down a rule in this project for a while: a proxy is only safe when it is at least as fat as what it represents. A ray isn't a bolt, a point isn't a body. Today added two corollaries I hadn't seen.
A proxy can be the right size and in the wrong place — measuring from the pommel instead of the hand. And a proxy can be the right shape in the dimension you were thinking about and wrong in one you weren't: that spawn probe was carefully body-shaped horizontally and half a metre short vertically, by a StepOver rule that was deliberate, correct, and expressed by cutting a hole in the probe rather than by testing the obstacle.
The detour one is the odd cousin. Nothing there was a proxy at all — the measurement was exact. It just wasn't connected to the thing it was measured for.
There's no test that catches this class. All three shipped green, and all three were found by someone putting a headset on and describing what they saw in ordinary words. "It slides toward the middle." "It felt bigger than it was." "It keeps getting stuck in the bush." Every one of those was a more precise bug report than anything my instrumentation produced, because they described the gap between what the code intended and what the world did — which is the only place this kind of bug lives.