Skip to content

v1.14.2 ·

The lock that only kept out its owner

Two things in this release were wrong in the same quiet way: the state was bad and nothing said so.

A lock that only kept out its owner

AIDLC lets two people work the same piece of work, and part of that is a check on who owns the phase you are trying to advance. The check compared the recorded owner against whoever was asking. But the two names came from different places. A claim records a generated session identifier. The transition command asked the operating system for a username. They can never be equal.

So the check did not fail sometimes. It failed every time, against exactly the session that held the claim. It was hit twice in one day, on two pieces of work, and both times the way through was to blank the field or pass the flag that overrides the check. A guard you get past by turning it off is not guarding anything.

It had also never done its real job. It runs only when an owner is recorded, and the tool writes that field empty and leaves it empty. On the ordinary path it was inert, and the only way to wake it was to fill the field by hand, which is when it lied.

The report said to retire the owner field. I tried that first and gave it up inside one search. The field appears in more than a hundred places across thirty-one test files, mostly fixtures. The decisive point was not the cost, though. Deleting the field would not have fixed anything, because the comparison between two kinds of name would still be wrong. The report named what it could see. The mechanism sat one level up.

What shipped is fifteen lines in packages/cli/src/commands/transition.ts. When work is claimed, ask the claim who holds it, and use that as the answer to "who is doing this?". The name falls back to $USER or $USERNAME only when no live claim exists. The check itself is untouched. I rejected resolving the current session's identity instead, since the resolver mints a fresh identifier per process when it cannot do better, and an unregistered session would lock itself out on every transition.

Ideas that vanished

Each future idea is one file with a short header. If the title starts with a backtick, the header does not parse, because YAML reserves that character. Backticks are how you name a function, which is how agents name code problems.

The reader returns nothing for a file it cannot parse, and nothing for a file that does not exist, and every caller skips both. One character removed an idea from the browse list, from the lookup, from the automation that files it as done, and from the repair tool meant to notice this. Five of the first forty-nine ideas were in that state, some for ten days. I found them by accident, when the repair tool reported zero problems while one of the files sat in the folder it was reporting on.

Titles are now always quoted. An old rule quoted only when the title held a colon and a space, and that rule is what let backticks through. Conditional escaping needs you to list every dangerous character, and backticks do not look dangerous. The capture instructions in packages/content/skills/04-roadmap.md say so, with the reason.

I did not teach the reader to tell "cannot parse" from "not there". It is the tidier design, but it touches every caller to buy reporting two of them want. Instead unparseableItems and quoteItemTitle now live in packages/cli/src/roadmap/paths.ts, one shared walk. The repair tool had already written that walk privately, which was the symptom.

A new migration, roadmap-item-titles, quotes a repairable title, re-parses the whole header, and refuses to save unless it now parses. A file it cannot fix is named and left alone, reported as not applicable rather than pending. Pending work makes the tool exit with a failure, and a file only a human can fix would fail forever.

What it does not fix

The reader still returns one value for two different situations. That is a separate item on the roadmap.