v1.14.1 ·
The event that never fired because we followed the instructions
Two automations were declared on the event that fires when a piece of work finishes. One marked the instance as owing a retrospective. One moved the finished item out of the roadmap's "in progress" pile. Both were enabled. Neither had ever run.
The bug report said nothing emitted the event, and made a good case. The cheap fix was to add an emitter. That would have been wrong, and one search showed why: the emitter existed, shipped and worked.
The guard that read the instructions backwards
What stopped it was its own safeguard against firing twice. It asked "has this already happened?" by checking whether retrospective.md existed. The framework's written order says to write the retrospective first and fire the event second. So following the documentation guaranteed the event was suppressed.
Deleting that check alone would have fixed the symptom and broken the guarantee. The only other signal, a marker file, is removed by the retrospective step itself, so after a normal completion neither survives and the event would fire forever. The guard needed something written by completion. Now completion stamps a timestamp on the instance, written in one place and never refreshed. Completion has one author instead of two.
Nothing had ever written that timestamp, so every finished instance looked un-fired and would have announced itself again. Nineteen of them. A repair pass in aidlc doctor stamps them first, using each instance's own historical completion time. That pass is a precondition of the fix. The retrospective marker also stopped asking for retrospectives that already exist.
The second cause, found by trying it
With the event repaired, one roadmap item still refused to move, though it sat in the directory being scanned. Its title began with a backtick, which the file format reserves, so its header would not parse. The reader returns "nothing here" for both absent and unreadable, so the item was invisible to every listing and lookup. Five of forty-nine items were in that state, some for ten days.
I fixed the data: the five titles are quoted, and the repair pass now names any unreadable item instead of skipping it. I did not change the reader. One return value meaning two things touches every caller, so it became its own roadmap item.
Both handlers had passing tests. Nothing tested that the event arrives. The proof is this instance's own completion: I wrote the retrospective first, on purpose, and the roadmap item moved by itself.
The CI gate that ran after the tag
The second instance in this release closed a related gap. release.yml was the only workflow, triggered only by a v* tag, so the suite ran once per release, after the tag existed. A break landed on main and waited for whoever shipped next.
Now every push to main and every pull request runs pnpm build, pnpm lint and pnpm test, the same three gates in the same order as scripts/release.sh. The tag workflow gained the lint step it never had. The root test script runs packages one after another, which took the suite from 268 seconds to 66 and removed two load-induced timeouts.
The new workflow had never run when the plan was written. It ran on a pull request twice and on a push to main, and passed all three. I merged with a merge commit, not a squash, because the blog trail finds instances by matching branch names in merge subjects, and a squash would have left this one out of the next release post.