v1.30.0 ·
The protocol that was already dead
The problem
Two failures share one surface, and the second is the interesting one.
The first is ordinary. A phase asks you something without saying why it is asking, what the answer blocks, what the repository already says about it, or what happens if you say nothing. You cannot decide from that, so you either guess or ask for a rephrase — and a question that needs rephrasing is a defect, not a saved token. That much is a content problem with a content fix.
The second is that the mechanism meant to prevent this had been in the framework since August and was already dead. There was a written protocol: when you need substantial input from the user, write the question to an inbox directory, put the options as checkboxes, and wait. It was specified in the overview skill that every session loads. Two commits in this project's entire history used it. The directory was not present in the checkout at all.
A dead protocol is worse than a missing one, because it makes the gap invisible. Anyone reading the framework would conclude that structured questions were a solved problem here. The instructions said so. Nothing contradicted them. And the reason nothing contradicted them is the third failure: nothing anywhere read those files, counted them, or noticed when a question went unanswered. A question could sit blocking work indefinitely and the only trace would be a file somebody would have to remember to open.
So it is worth being precise about why it died, because "nobody used it" is a symptom, not a cause, and each of the three causes is a distinct way for a protocol to be technically present and practically absent.
Its trigger was discretionary. It fired on "substantial input" and "extensive details", which is a judgement no two readers make the same way and no single reader makes the same way twice. A rule that depends on the reader's estimate of substantiality is not a rule.
Its required content omitted the fields that make a question decidable. It asked for the question and the options. It did not ask for what the answer blocks, or for what the repository already says, which are exactly the two things that turn an unanswerable question into an answerable one. A perfectly conforming question could still be impossible to answer, which means conformance measured nothing worth measuring.
And nothing closed the loop. No count, no reminder, no surface anywhere that a question was open. The protocol wrote into a void and trusted the next person to look.
There is a smaller third failure sitting on top, and it is the one that actually started this. The framework had two unrelated directories whose names collided: the dead question inbox, and the live roadmap inbox where new ideas are captured. They share a word and have nothing else in common. The bug report that opened this work conflated them — which is a reasonable thing to do, and a good sign that one of the two names was wrong.
What makes this worth a release rather than a prose edit is the portability problem underneath it. Six agent platforms are supported. One of them has a structured picker for putting a question in front of a user; five do not. A question protocol written against the one with the picker is a protocol that quietly degrades to nothing on the other five, and a protocol written to the lowest common denominator throws away the picker where it exists. Getting that split right is most of the work, and getting it wrong is how you end up with question quality that depends on which editor you happened to open.
How it could be solved
Five decisions were put to the maintainer before anything was built, in the format the instance was being built to produce — so the question file doubles as the first worked example of the protocol it was asking about. All five took the recommendation, which is worth stating plainly because it means the rejected options below were rejected on argument rather than overruled.
Two published implementations were read first, not recalled. AWS's own AI development lifecycle separates a harness-neutral question specification from a per-platform rendering annex, so the specification never names a tool. GitHub's Spec Kit caps clarification at five questions total, asks exactly one at a time, and requires a stated reason and an explicit recommendation on every question. Both shaped what shipped; on one point they flatly disagree, which turned out to be the most useful thing about reading both.
On where a question file lives, the rejected option was one shared directory for everything. It is the better answer in isolation — one place to look, one count to display, questions outlive the work that raised them. It was rejected because outliving the work is the failure, not the feature. The only two question files this project ever wrote are still the only two, and nothing cleaned them up or read them again. Co-locating a question with the instance that raised it means the question dies when that work finishes. A separate location survives for the genuinely instance-less cases, because the constitution-update flow has no instance and pretending otherwise would break a shipped path.
On volume, the two references disagree outright, and that disagreement is the whole decision. Spec Kit caps hard at five questions total. AWS refuses a cap and scales by depth, with the stated objection that a vague one-line bugfix warrants more questions than a cap would allow — don't blindly cap at two. Both are right about different things. What shipped caps five questions open at once rather than five asked in total, which keeps Spec Kit's brake on the thing actually complained about — questions accumulating unanswered — while leaving room for the vague-bugfix case. It is also the only version of the rule that can be checked mechanically, because an unanswered question is a blank answer tag on disk and a question asked in total is recorded nowhere.
On routing, AWS asks you every time: here are your questions, how would you like to answer them, with three modes. That was rejected, and it is the closest call of the five. It spends a turn asking a question whose answer is inferable from the question's own size — if the options are self-explanatory and the stake fits a line, you want to click; if it needs citations and trade-offs, you want to read. The agent now decides by that rule and never asks. What makes a wrong guess cheap is that the file is written in every branch anyway, so the prompt names the path and you open it when the labels are not enough. The three modes do not actually disappear: editing the file instead is still available by editing the file, and discussing it is still available by replying in prose. Only the prompt asking which one is gone. A configuration key for the mode was also rejected — a wrong setting there is silently wrong for weeks.
On detection, the strongest option was rejected on this project's own record. A stop hook reading the answer tags would tell "waiting on you" apart from "abandoned mid-work", which is the mechanism AWS uses and is genuinely better in the abstract. It was rejected because it works on one of six platforms, and because five of this project's six traceable bugfixes came from features that watch the lifecycle rather than serve a user — each one adding a gate that every future piece of work then has to pass. A phase gate on an unanswered question was rejected for the same reason, more emphatically. What shipped is one count in a menu that already reads state to build itself, which costs nothing and taxes nothing.
On migration, a repair tool for stray files at the old path was rejected for a population of zero: two uses ever, both already deleted, directory absent. A migration for nobody is a check that runs forever to find nothing.
One more decision arrived late and was not anticipated by any of the five. Implementation reported sixty passing tests and complete coverage of all twenty criteria. The gate disagreed on nineteen of them, because every criterion reference had been written in the short form — and forty-seven separate pieces of work in this repository define a criterion numbered one. The scanner accepts the short form only when exactly one owner exists, so eighteen criteria read as untested while sixty tests asserted them, and two were genuinely untested and nobody had noticed. The option of relaxing the scanner was available and was not taken. A passing suite and a satisfied gate are different claims, and the gap between them is invisible from the code — which is the more useful finding than any of the nineteen individually.
How AIDLC solves it
An answerable question protocol, and the per-platform machinery that puts a question in front of the user without the protocol having to know which platform that is.
The framework already specified a way to ask the user something: write the question to an inbox directory under the framework's own state folder, put the options as checkboxes, and wait. That mechanism was used in two commits in this project's history and the directory was not present in the checkout. It failed for three reasons worth naming, because each one is a way a protocol can be technically present and practically dead. Its trigger was discretionary — it asked for "substantial input", which is a judgement nobody makes the same way twice. Its required content omitted the fields that make a question decidable, so a conforming question could still be unanswerable. And nothing anywhere counted an unanswered file, so a question could sit blocking work invisibly.
What replaces it is a Question Protocol in the overview skill, which every session
loads. A question now carries the decision as a single interrogative sentence, why it is
being asked and what it blocks, what the repository already says with a path:line
citation, two to four options each with its consequence, a marked recommendation, and
what happens if the user says nothing. Identifiers are expanded on first use, so a
question does not present a bare criterion tag as though the reader carries the mapping.
The trigger is now consequence rather than volume: a question is asked when different answers would change an artifact, a design decision, or scope, and a question whose answers change nothing is not asked at all. At most five questions stand open at one time — open, not asked in total, which means a long negotiation is allowed and an accumulating pile is not. That distinction is also the only version of the rule that can be checked mechanically.
Spec and rendering are separate, which is the part that makes the protocol portable. The
protocol names no platform tool anywhere in its body, and a test asserts that by
scanning for ten tool names with a non-vacuity case that catches a planted one. How a
question actually reaches the user is data, declared per platform and emitted to
.aidlc/resources/questions/rendering.md. Claude Code maps to its structured picker
along with the three limits that picker imposes. The five platforms with no native
picker get numbered prose, and that rendering states that option numbering restarts at 1
for every question — because a user who replies "2" must be answering the second option
of the question in front of them, not the second numbered thing in the message.
The question file is written in every branch, including when the answer arrives through a native picker. It is the record of what was asked and decided, not a fallback for when a prompt fails. Questions raised inside an instance live beside that instance; a separate location exists only for the cases that genuinely have no instance, such as a constitution update. Answers are folded into the phase artifact they were gathered for and the file stays behind.
Visibility is one count and nothing more. The entry point greps question files for a blank answer tag and offers them as a menu entry when the count is above zero. There is deliberately no Stop hook and no phase gate, which was an explicit decision rather than an omission: this project's own record is that five of its six traceable bugfixes came from meta-features that each added a gate every future instance then had to pass.
Three adjacent changes came with it. The capability loader had to learn the new key, because it drops unknown top-level keys and the rendering data would otherwise never have reached the emitter. The constitution skill's one worked example was rewritten from checkboxes into the new option shape, so the single example in the corpus conforms to the protocol it cites. And every reference to the dead inbox path is gone from the content package, with a test that stops it being reintroduced and two companion cases proving the guard does not also match the live roadmap inbox, which is a different directory that happens to share a name and confused the original bug report.