v1.88.0 ·
Finished work files its idea even when the link is lost
The problem
roadmap-done finds the items to file by promoted_to alone. On 2026-10-09 two items
(agent-binary-missing-crashes-loop, help-epilog-parsed-as-options) reached in-progress/
with promoted_to: null, so completing their instances filed nothing and the roadmap showed
shipped work as in progress. Each instance's own roadmap-item.md copy still carried the
right id and promoted_to.
How it could be solved
Three decisions, each about how far to trust a record whose damage nobody could explain.
The first was to stop chasing the cause. Two ideas lost the line that tied them to the work that shipped them, and every lead was checked and ruled out: the timeline that looked suspicious was a time zone misread, and the one step that could have restored the old text kept the edit when tried. Rather than guess at a fix for something not reproduced, the change makes the outcome impossible to miss. Each piece of work keeps its own copy of the idea it started from, and that copy still knew the idea's id.
The second was to use that copy only as a fallback. When an idea still names the work, it is filed exactly as before and the copy is never read. Only when nothing names the work does the copy's id come into play, and only for an idea whose link is empty. An idea linked to other work is never taken, so a shared id cannot move the wrong thing.
The third was to repair the link while filing, not just move the file. The filed idea gets its link back, so it reads like every other finished idea, and a line says it was matched by id because its link was missing. The same fallback runs in the repair command, so ideas already stranded this way are found and filed without anyone doing it by hand.
How AIDLC solves it
roadmap-item-loses-promoted-to
A completed instance now files its roadmap item even when the item lost its promoted_to.
Changes
packages/cli/src/roadmap/promote.ts—findUnlinkedByCopyandlinkForFiling.packages/cli/src/events/event-bus.ts—roadmap-donefalls back to the instance'sroadmap-item.mdwhen no item names the instance, links what it files, and says so.packages/cli/src/doctor/migrations/instance-completion.ts—aidlc doctortakes the same fallback for completed instances.packages/cli/test/roadmap-item-loses-promoted-to.test.ts— 15 tests.packages/content/docs/roadmap.md— one paragraph.- Spec:
roadmap: Filing items at completionmodified (folds at completion).
The cause of the 2026-10-09 lost links was investigated and not reproduced; requirements.md
records what was ruled out, including that the item's "half an hour before" timeline was a
UTC/EDT misread.
agent-cannot-approve-itself
An agent session can no longer approve, override or confirm its own gates.
aidlc autopilot approve,aidlc transition --override,aidlc amend --confirmrefuse with exit 2 when stdin is not a terminal orAIDLC_UNATTENDED=1, before reading or writing anything, and say why. At a terminal they work as before.transitionwithout--overrideandamendwithout--confirmare unchanged. The console's approve key is unchanged.- The approval guard —
aidlc hook installandaidlc initnow also write.claude/hooks/aidlc-approval-guard.mjsand a Claude CodePreToolUseentry that blocks those commands in an agent's shell and blocks file edits to the autopilot approval record. It fails closed: a missing script, missingnodeor crash blocks the call and says to reinstall. - Every refusal is one line in
<git-common-dir>/aidlc/refusals.ndjson.
Minor, not patch: three commands now refuse in contexts where they used to run, and init writes a
new hook. Behaviour change to call out in the release notes: a script or CI job that runs any of
the three without a terminal now fails with exit 2. Nothing in this repo's scripts/ or
.github/ does.
Changes
packages/cli/src/hooks/human-only.ts(new) — the table, the presence check, the refusal log.packages/cli/src/hooks/approval-guard.ts(new) —guardVerdict, the rendered script, the hook command.packages/cli/src/hooks/install.ts— per-kind hook identity; theapproval-guardkind.packages/cli/src/commands/{autopilot,transition,amend,hook}.ts,src/change/types.ts.packages/content/docs/lifecycle.md,docs/index.yaml,skills/20-requirements.md..aidlc/knowledge/— decisionapproval-guard-terminal-is-the-line.- Tests: new
agent-cannot-approve-itself.test.ts(58) andhuman-at-terminal.ts; five files use the helper;lifecycle-hooks-installandproject-root-call-sitesupdated.
blocking-actions-never-block
A check marked blocking: true now stops work, and says why.
on-phase-exitblocks.aidlc transitionruns the phase's exit actions once every other gate has passed and before it writes anything. A failing blocking action is ablocking-actionviolation naming the action and its error — in the human output, with a next step, and in--json. Nothing is written andon-phase-enterdoes not fire. An untrustedrun:command counts as a failure, and its error namesaidlc doctor.on-phase-enterandon-instance-completekeep the move. They run after it is recorded. A blocking failure prints✗ blocking action "<id>" failed on <event>: <error>and that the move is already recorded, and the command exits 1. Both completion paths (final phase, maintenance entry) behave the same.--jsonsuccess payloads gainaction_failures: [{ event, id, error, blocking }]when any action failed. Absent otherwise; no other field changes.- Every failure prints.
emitused to print only non-blocking failures; a blocking one broke out of the loop first. aidlc startandon-instance-startare unchanged.aidlc gateruns no actions.
Visible to users on upgrade: any repo with a blocking on-phase-exit action that has been
failing silently will now be stopped by it. That is the fix. In this repo it is
docs-drift-check on leaving Implementation — see Risks.
Changes
13 files under packages/, .agents/ and .aidlc/skills/, +762 / −52, plus
packages/content/docs/lifecycle.md. 7 commits on the branch; each code commit carries its
Task: trailers.
packages/cli/src/events/event-bus.ts,core/types.ts,commands/transition.ts,core/next-steps.ts,core/lifecycle.ts(comment only).packages/content/skills/82-add-action.md,00-overview.md, regenerated into.aidlc/skills/and.agents/skills/with the branch's build (node packages/cli/dist/cli.js update --project-only).- Tests:
packages/cli/test/blocking-actions.test.ts(new, 17),event-bus.test.ts(+3). - Spec: ADDED
lifecycle-actions: Blocking actions— folds at completion (aidlc spec fold --dry-runclean).
Docs
packages/content/docs/lifecycle.md — "Three gates are worth knowing" now names the
blocking-action gate, with the reason enter and complete failures keep the move.