The Default Label Was Fleet

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

What happened. The fleet keeper has two backstops for its own workers: one ends a job that has sat in the resuming state for three minutes, and one ends a job whose transcript has been quiet for an hour and that the watchdog cannot classify. I was pleased with the second when I built it. In the week of 15 September the fleet was paused throughout, the keeper dispatched nothing, and the two backstops ended eight sessions. One was a session I had opened from my phone seven minutes earlier, asking about a tool on the laptop. Another was killed three times in two hours and sixteen minutes and came back each time, which is what a session I keep reopening looks like. Three of the sessions had the workspace root as their working directory, which no fleet worker ever has: it is where a phone session lands when it is opened without a repository.

When it was noticed. The monthly fleet retrospective, reading six days of the keeper’s journal. One line in 36,230 said a worker had been spawned, at the end of the window when the pause lifted. Eight lines said a worker had been reaped. The arithmetic does not work unless the keeper reaps things it did not spawn.

The cause. Both backstops asked “is this job ours?” with one test: the job’s source field equals fleet. That is not the fleet’s word. It is the CLI daemon’s default label for any background job: the schema falls back to it when the field is missing or unknown, and the CLI’s own background launcher passes it explicitly. A session I open from my phone is adopted into the daemon as a background job by a timer, so it is labelled fleet too, it sits in an enabled repository or in none, and an hour of quiet is the normal state of a session a human drives between other things. The keeper’s own comment beside the three-minute limit states the contract the label could not deliver: only fleet jobs are eligible, so interactive sessions that also pass through resuming are never reaped.

The fix. The keeper already held the proof it needed. Every worker it dispatches is written to its spawn state, and a wedged worker is always its project’s latest record, because nothing is restaffed while a slot reads occupied. A pure predicate, isKeeperWorker, asks that record instead of the label, and both backstops use it. Occupancy is untouched: a phone session sitting in a repository still counts as that repository being taken, which is the safe direction. The cost, accepted: a worker whose spawn record has been lost is no longer reaped by these two backstops, though the watchdog still owns its limit states and it still shows on the board.

What guards it now. A test over the predicate: a keeper-dispatched resuming job is owned; a labelled job in the same repository that no spawn record names is not; a record match without the label is not; an empty state owns nothing; the un-owned phone session still counts as occupancy. The change is an apply pack, because the fleet’s directory is one no agent may edit, so it was validated on a fresh clone (151 tests before, 152 after, a dry-run scan clean) and waits for my hand and a keeper restart.

The watchdog has the same label test in two places of its own, and one of them switched the model under my phone session two days before this was found. One backstop family per pack. The keeper’s were this month’s harm.


← all writing