v1.14.5 ·
The number that was always missing by seven minutes
Every release post has a card at the top with two numbers: what the work cost, and how long it took from creation to finish. For twelve of the first twenty-six posts, the second one said "not recorded". Not zero. Missing.
It is an ordering problem, and it hid because both orders look correct. The post is generated during the release, after the version tag exists and before anything is pushed. It reads the project's metrics once, writes them into the post, and never looks again. That is deliberate. A post should say what the work cost when it shipped, not drift upward whenever someone later fixes a bug in it.
The catch is that whatever is unknown at that instant stays unknown. The elapsed time of a piece of work does not exist until the work is marked finished, because there is nothing to subtract from. So whether a post can state its duration depends on whether I closed the work a few minutes before the release or a few minutes after.
Closing it afterwards is the order a careful person picks, because then the record can describe what happened: the version that appeared, the checks that passed. It also silently discards the duration. The evidence is clean. The sign of the gap between closing the work and generating the post predicts the outcome every time. One release closed its work eighty-seven seconds before and recorded just over twenty-one hours. Two closed thirteen and seven minutes after and recorded nothing. There is no third pattern.
Nothing fails, and regenerating later does not help, because the generator carries the old numbers forward on purpose.
Why refuse
There were three ways out. The first was to remember: write down the right order and trust whoever releases next. This project has the evidence on how that goes. A note naming an exact fix was rediscovered from scratch three days later. A manifest note saying to add an entry later was never re-read, and two releases shipped with no post while every check stayed green.
The second was to make the number recoverable afterwards. That works for cost, because the release reconciles accounting just before generating the post and the usage is already on disk. It cannot work for duration. Before the work is closed there is no end time to recover.
The third was to refuse. A readiness check runs from scripts/release.sh after the deferred-blog check and before the version bump, while there is nothing to unwind. It stops the release when any instance the entry names has no lead time, and says which cause: the last phase is still open, the instance is complete but its lead time cannot be derived, or metrics does not report it. It skips when there is nothing to protect.
Two details took more thought than the refusal. The check tests for the exact number the post will print, not for the condition behind it. "Is it finished" and "does it have a lead time" are the same question today, but asking the second means the check cannot drift away from what it protects. And there is no override flag. This project has watched a gate with an override get waved through on every phase of one release, while a gate with none forced five weak criteria to be fixed. The honest exits already exist: say the release does not cover that work, or that it publishes no post, and write down why.
The failure message needed care. "Not finished" invites you to go finish it, which here means publishing, the thing just prevented. So it says the odd part outright: close the work from the plan, tag, then append what happened to the record. The post reads the record as it stood at tag time, so it loses nothing.