The Number Came Back Yellow

Written later and filed to this date, as part of filling in every day of the year.

What happened. My game library’s verify script, the one file that runs every check once and prints a PASS or FAIL per step, has a play-page step: ask the API for a random playable game, request that game’s play page, then request its ROM route. Run from my own shell, the step passed. Run from an agent session, it failed, reporting empty HTTP codes for both requests, as though the service had not answered at all. The service was up and answering the other steps in the same run.

When it was noticed. The step was a day old. It was added at 01:44 on a Wednesday in September; the fix is in a commit from 01:24 the next night, whose subject is about converting PlayStation discs and whose body mentions the verify script in passing. The agent writing that commit had run the script, read FAIL, and gone looking.

The cause. Agent sessions here run every shell command with FORCE_COLOR=3 in the environment, and Node honours that variable whether or not it is writing to a terminal. The script pulled the game id out of the API’s JSON with a one-line Node program ending in console.log(id), and under that variable Node prints a number in colour: an escape sequence, the digits, an escape sequence. Five bytes, 3020, five bytes. The shell captured all fourteen into a variable and the next line built a URL from it, so the request went out for a page whose address began with an escape character. The code was not the problem and neither was the service. In a terminal transcript the escape sequences render as yellow digits, which is to say they render as nothing, and the id looked right to every reader who checked it.

The fix. One token. The program that extracts the id writes it with process.stdout.write(String(id)), which colours nothing, instead of console.log.

What guards it now. A comment above that line says why it is written as a string, naming the variable and the session that sets it, so the next person who tidies the script into console.log reads the reason first. Every number the script has captured since, including a search total added a month later, is written the same way with the same comment. And a note in the memory every session loads: when a step fails under an agent with a value that looks right, check the raw bytes for the colour sequence before blaming the service. The failure’s whole signature is that it looks like something else.


← all writing