Changelog — 2.219–2.226
Releases 2.219.0 through 2.226.0. Current releases are on the main changelog, and every band is listed in the release archive.
Loading audio...
Version 2.226.0
August 26, 2026A tool told us it had deleted something. It hadn’t — and the way it checked its own work could not tell “gone” from “never asked”
- Nothing you can see has changed. A long project to simplify how our machines are set up finished this evening. The part of the site that finds relevant passages for Reflections and Vignettes ran on different hardware for a few hours and then moved back — without interruption at any point.
- Halfway through, a tool reported success for work it had not done. We keep an internal address book so that things can find each other by name rather than by number. The tool that edits it removed an entry, checked its own work, and reported “removed and verified”. The entry was still there.
- It checked by asking the wrong shape of question. It asked “is the old entry still there?” — but it asked in a malformed way, so it got no reply. And no reply looks exactly like “it’s gone”. A question phrased as a negative answers itself the moment it stops being asked properly.
- What caught it was the very next command refusing. The other half of the same tool asks the opposite question — “did the new entry appear?” — and a broken question cannot satisfy that one. Two checks over one operation, phrased in opposite directions, and only one of them could fail honestly.
- We now realise this is our most repeated mistake, wearing different clothes each time. Only yesterday we found a safety check that reported “all clear” because the tool it used wasn’t installed. It is the same fault: a check that cannot tell absent from unasked. We have written it down as a standing rule, with the fix — prefer a question that a broken query fails, and where the question really must be a negative, prove the question works first.
- The tool now proves it can catch this, on itself. We put the old broken behaviour back deliberately and confirmed that its new self-check goes red — and that it goes red for that reason and no other. A safety check that has never failed is not yet a safety check.
- We also found a testing tool that would have passed by testing the wrong machine. During a move there are briefly two machines that can both answer. Its default pointed at the one we were leaving, so it would have reported everything healthy while telling us nothing about the new one.
- And one setting had been written down in eight separate places in our own code. Five of them pointed at hardware that stopped existing that afternoon. It is now written once.
- Nothing to do at your end.
Version 2.225.0
August 26, 2026We rebuilt a machine we had never actually practised recovering, and proved it by making it identical to what it replaced
- Nothing you can see has changed. One of our machines — the one that does the most thinking behind the scenes — was wiped and rebuilt from scratch this afternoon and is back doing its job.
- The reason was a gap we could describe but not close. We had genuinely practised recovering a machine from backup, start to finish. But this particular one was set up differently from all the others, so what we had actually proved was “we can recover a machine like the one we practised on” — and this wasn’t one. Rebuilding it the same way as the rest turns an assumption into something we have really done.
- There was nothing to switch over, which made proving it harder rather than easier. Usually a move ends with a clean test: turn the old thing off, check it genuinely can’t answer, then use the new one. Here the machine came back at the same address, so there was no “old thing” to switch off. Instead we compared what it ended up running, character for character, against what it ran before — and a memory figure that would be very hard to hit by accident. When there’s no switchover to prove, the proof is that the rebuild is indistinguishable from what it replaced.
- Keeping the old backup credentials turned out to save far more than we expected. We kept them for a boring reason — the backups are filed under that name. But it also meant the first backup after the rebuild recognised most of the machine as unchanged and finished in about half a minute instead of uploading everything again. The right decision, for a better reason than the one we gave.
- And we found we’d been quoting a number measured in the wrong situation. When this machine is unavailable, requests fall back to an outside service. We had recorded how long that takes — but we’d measured it with the machine switched on and only the software stopped, which is much quicker than a machine that is genuinely powered off. The real delay applied for about half an hour, not the whole afternoon.
- Nothing to do at your end.
Version 2.224.0
August 26, 2026The safety check that would have told us everything was fine, because the tool it used wasn’t installed
- Nothing you can see has changed, and that was again the goal. Voice synthesis moved back onto its rebuilt machine today — a complete round trip in a single day — with no interruption at any point. If you generated narrated audio this afternoon, you were served by a machine that had been wiped and rebuilt hours earlier.
- The most important check of the whole move would have lied to us. Before switching the old machine off, you confirm the new one is being used. Our check asked the old machine whether it was still answering — using a small tool that, it turned out, isn’t installed there. It would have reported “the old machine is off, all clear” whether or not that was true. We caught it because something else printed “command not found” where we expected silence.
- So we made the check prove itself first. We ran it while both machines were still running, and confirmed it correctly said “both are up”. Only then did we trust it to say “this one is down”. A test that has never given the answer you already know cannot be trusted to give one you don’t.
- And we watched the hardware itself. Three separate things had to agree before we called it done: the address book pointed at the new machine, the old one actively refused connections, and the new machine’s processor visibly did the work while a real piece of audio was produced. The last of those is the one that can’t be faked by something answering politely.
- The same day, a second check turned out to be wrong in both directions at once. When a new disk arrives we run it hard and then look for signs of trouble. That check counted any line mentioning a “timeout” — but some perfectly healthy disks print one at startup that simply describes a setting, so the check would have condemned a brand-new disk. And on a machine using an older type of disk entirely, it found nothing to look at and reported “all clear” about a component it had never examined. It has never gone wrong in practice only because that part of the check is run by hand, and nobody had run it yet.
- Separately: a setting that decides which version of our software gets installed was missing from the instructions for several of our services. Left alone, following those instructions would quietly install “whatever is newest” instead of the version that was tested — with nothing going wrong at the time. Fixed, and the build now refuses to proceed if it happens again anywhere, including for anything we add in future.
- Nothing to do at your end.
Version 2.223.0
August 26, 2026We wrote a safety check and then never ran it — and the first time we did, it caught something we’d broken an hour earlier
- Nothing you can see has changed. This is behind-the-scenes work on how we make and check our own backups. It is written up because the mistakes in it are the interesting part.
- A check that exists and is never performed is not a check. We had written down a short verification step precisely because “we took a backup” and “we have a backup that would work” are different claims. It then sat there, unperformed, for two days. It is now a program that runs, with its own built-in test proving it can fail — rather than a paragraph someone has to remember.
- The first time we ran it, it found a real fault — one we had created ourselves that morning. A recovery note had been recorded incorrectly an hour earlier. Everything else it checked came back clean, which is the reassuring half; the point is that nobody would have known either way.
- One of our tools reported success while writing nonsense. Asked to record something that wasn’t there, it quietly invented one and finished with “the operation has completed successfully”. Worse, the file it produces is the same size whether it is right or wrong — so the thing that lied is also the thing whose size can never reveal the lie.
- A number we had been treating as a warning sign turned out to be counting us looking at it. Reading the counter made the counter go up. The test is almost free once you think of it: read it, read it again, and see whether it moved. If it moves, you are measuring your own instrument rather than the thing.
- And a written instruction was confidently wrong because it didn’t know an unwritten habit. Our notes reasoned from something visible on the machine to a firm conclusion — and the conclusion was false, because the person who had set it up years earlier had a practice that was recorded nowhere. Asking took a few seconds. The instruction now says “go and check” instead of “assume”.
- Nothing to do at your end.
Version 2.222.0
August 26, 2026Our own instructions told us to do something the system refuses to do — we found out by doing it
- Nothing you can see has changed. We moved voice synthesis onto different hardware today without any interruption at all, and this is us writing down what actually happened while it was still true.
- The move itself was invisible, and that was the goal. The new machine was set up and proven to work first; only then did we switch the old one off, confirm it could no longer answer, and produce a real piece of narrated audio. Testing before switching the old one off would only have proved that something answered, not which thing.
- A step in our own written procedure was impossible, and it was marked as decided. One instruction said to run a particular command before switching a machine off. The system rejected it outright — that command can only be run after. It had been reasoned through carefully by someone, written up confidently, and never actually executed. A step marked “decided” that has never been run looks exactly like one that has.
- Careful reasoning is what made it convincing. The note even discussed an apparent contradiction between two of its own statements and explained why both were true. In fact one was simply wrong — and the effort spent reconciling them made the mistake harder to see, not easier.
- We also found an address in our notes that would have sent someone to a machine that isn’t there. It described a temporary state during a rebuild, written in the present tense, so it read as a statement of where that machine lives. It has been corrected, along with the reason it was easy to get wrong.
- And the voices needed carrying across by hand. The cloned voices the site uses for narration exist in exactly one place and cannot be regenerated — there is no original recording and no script that would recreate them. We counted them before copying and checked the same number afterwards. A count taken after the fact is a description; the same count taken beforehand is a check.
- Nothing to do at your end.
Version 2.221.0
August 26, 2026We had written machine addresses into the software, so moving a machine meant releasing the software
- Nothing you can see has changed. This is the last preparation before some hardware changes, and it is the one that makes those changes cheap instead of expensive.
- Parts of our code named the machines they talk to by number. That works right up until the machine changes — at which point the software has to be edited, reviewed, released and deployed, just to point at a different box. Now the code uses a name, and the name points at whichever machine currently does that job. Moving the work becomes a one-line change to an internal address book that takes effect in about a minute.
- For one of them we deliberately used the name of the JOB rather than the name of the machine. The part of our system that produces spoken audio has already been renamed once — and the address written beside it outlived that rename by two months, quietly pointing at a machine that had been switched off. A name that describes what something does survives a rename; a name that describes what something is does not.
- The other one kept its existing name, for the opposite reason. That service has already had its entire engine replaced without its name changing, so the name is proven durable. Consistency would have been the worse choice in one of the two cases; we picked per case and wrote down why.
- And we added a test that cannot be satisfied by the mistake it guards against. The obvious test checks the new name is present — but that goes green again the moment someone pastes a numeric address back in to fix something in a hurry. So the test instead checks that no numeric address appears at all. A rule written as “this must not be here” cannot be passed by the very thing it forbids.
- One of our checks reported nothing, and so did the thing we already knew the answer to. That second part is what made it quick: when a measurement comes back empty for something you can independently verify, the tool is broken rather than the system. It happened five times today, and every single time it pointed at something being worse than it was.
- Nothing to do at your end.
Version 2.220.0
August 26, 2026We tidied the release notes early, because two releases of room against three planned releases is not room — it is a deadline
- Nothing you can see has changed, unless you go looking for an older release. This page carries the newest releases and older ones move into dated archives as it fills. Every link anyone has ever shared still works — they are forwarded automatically, and the archives are all listed in the release archive.
- The page has a size limit, and a check that refuses to publish when it is exceeded. That check exists because this page once grew large enough to stop building altogether, which took the whole development site down with it. It is a good check. We had room for about two more releases, and three already scheduled.
- So it would have fired at the worst possible moment. Only yesterday we had a different check refuse a release over something the release had nothing to do with, and that cost real time to untangle. Doing this now costs ten quiet minutes; doing it when forced costs them in the middle of something else.
- We measured where to cut rather than picking a round number. And we only archive releases that have actually been published — anything still waiting to go out stays on this page, so nothing gets filed away before you have had a chance to see it.
- Checking which version was live returned nothing at all — including for the one we already knew. That second answer is the useful one: when a measurement comes back empty for something you can independently verify, the tool is broken rather than the thing being measured. It was a bad search pattern. Ten seconds to spot with a known-good comparison; a confusing hour without one.
- Nothing to do at your end, and no old link has stopped working.
Version 2.219.0
August 26, 2026Renaming a folder would have quietly disconnected every uploaded voice, and nothing anywhere would have complained
- Nothing you can see has changed. This is groundwork for a hardware change later in the week, done ahead of it and on its own — so that if something does go wrong during the move, we know it was the move.
- The voices people have uploaded were being filed under a name nobody had written down. The tooling that runs our services works out where to keep a service’s saved data from the name of the folder it is configured in. That name had only ever been inferred. Rename the folder — for tidiness, during a move, for any reason at all — and the tooling would conclude there was no saved data, create an empty store, and carry on perfectly happily. Uploaded and cloned voices are not something we can regenerate. The name is now written down explicitly.
- We wrote down the name the system already uses, not the tidier one. That sounds too obvious to mention, and it is the step that has gone wrong elsewhere: writing a neater name would have pointed the service at a store that has never existed, and the tooling would have helpfully created it — empty. Which is the exact failure we were preventing, arriving by the front door. So we read the name off the running system first.
- One setting in our own example configuration had a name nothing read. The service looks for one name; the example supplied a different one. Because the service has a sensible built-in default it started on the right port anyway — for entirely the wrong reason — and any value someone set there would have been ignored in silence. A default does not only supply a missing value. It hides a misnamed one.
- And the same example was missing the line that pins which build to install. Anyone setting the service up from our own instructions would have received whichever build happened to be newest, rather than the one we had tested. That is not always wrong, but it is never deliberate, and there is no signal either way. Several more of our examples still have the same gap; that is now written down as work rather than left as a surprise.
- Two of the notes in that file named machines that no longer exist. Both were switched off earlier this month. A configuration example that sends the next reader looking for something retired costs them real time, so they were corrected in the same change.
- Nothing to do at your end.