Fifteen items reached Done this week and none went to Won't Do, against seventy-eight the week before. Almost all of it came down to one question asked in three places: who holds the keys, and what happens to them afterwards.
The retained veterinary practice's new site now lives in accounts the practice owns. A code-hosting account and a hosting account were created in the practice's name this week, registered to a mailbox in its own tenancy, with two-factor authentication enabled and the recovery codes in the practice's safe rather than ours. Every push to the main branch mirrors the whole history — every branch, every tag — into the practice's own repository, and the mirror writes down the last commit that made it across, so whether the copy is current is a question with an answer rather than an assumption. Automation is switched off on their copy, so the workflow files that travel with the history cannot run there.
The deploy credential is scoped to that account and to nothing else, which means it stops working of its own accord the moment our membership of the account ends. The platform's own repository integration would have been faster to set up and was declined for the same reason: it installs a relationship rather than a key, and a relationship has to be remembered to be removed. Our own login is deliberately not a collaborator on the mirror at all — one dedicated key, held in one place, replaced by generating another if it is ever lost. None of this is difficult. It is simply easier to do now than at the point where somebody needs it to be true.
— On handover —Access that has to be remembered to be removed eventually will not be.
The agreement and its data-processing schedule were signed on the Thursday, and the practice's preview address went across with them. Sign-off on the approach and the design is the one thing still open in that phase.
A local dog-training club's enrolment form gained a class selector — required, nothing pre-selected, with each class routed to the mailbox that deals with it. An absent or unrecognised answer is refused before the spam check rather than after it, on the scripted and unscripted paths alike. It was proven by sending one real enrolment of each kind from a phone and watching them arrive in the right inboxes, which is a different claim from a stubbed test passing, and the only one that covers the mailbox actually existing.
The same form's photography line stopped being a notice and became a question. It had been a paragraph explaining what happens and inviting anybody unhappy about it to say so; it is now a required yes or no with nothing pre-selected, so the club knows each handler's answer before the class rather than after the photograph. A refusal is carried into the summary in terms too blunt to skim past. The privacy notice took a new version number and date in the same change, because that page promises one whenever its content moves. An opt-out buried in a paragraph and an answer somebody had to give are not the same thing, even where most people would have said yes to both.
N17 Time gained a full season page — thirty-eight matches under month headings, results with the score in fixture order, the next match anchored so the front page can jump straight to it. It added no new storage and no new scheduled work. The hourly refresh was already running; it now asks for the season unfiltered and keeps it in the same stored snapshot, which grew to about six kilobytes. The front page is eleven kilobytes and the season page twenty-seven, both inside a fifty-kilobyte budget. A second view for the cost of a wider question.
The page also became installable, with the last known fixture readable offline. Twenty-six tests covered that path, including the case where the network has gone and the case where the server answers with an error, and all of them passed. On a real phone in flight mode the offline notice did not appear. An installed app resumes without reloading, and the browser can serve the page from its own cache while it is still fresh, so the fallback the tests exercised was never reached. The page now asks the browser directly whether it is online and says so itself. The tests were not wrong about what they tested; they were exercising a path the device had no particular reason to take.
Traffic figures were wanted for that page, and the cookieless option was the one taken: no cookies, no local storage, nothing that follows a reader from one site to the next. It is worth naming what it cost, because this journal made the opposite claim about the same page eight days ago. It now makes one request to somebody else's domain, so no third-party requests is no longer true of it. That was the trade: a measurement worth having, against a sentence that was pleasant to write.
In progress across every project stands at nine.
None of the above is fast work, and none of it is visible from the outside. An account in the client's name, a mirror that reports whether it ran, a credential that lapses on its own, a question where there used to be a notice — each of them is a small amount of effort now in place of somebody else's problem later. That is most of what the job is.