Skip to content

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 — findUnlinkedByCopy and linkForFiling.
  • packages/cli/src/events/event-bus.ts — roadmap-done falls back to the instance's roadmap-item.md when no item names the instance, links what it files, and says so.
  • packages/cli/src/doctor/migrations/instance-completion.ts — aidlc doctor takes 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 completion modified (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 --confirm refuse with exit 2 when stdin is not a terminal or AIDLC_UNATTENDED=1, before reading or writing anything, and say why. At a terminal they work as before. transition without --override and amend without --confirm are unchanged. The console's approve key is unchanged.
  • The approval guard — aidlc hook install and aidlc init now also write .claude/hooks/aidlc-approval-guard.mjs and a Claude Code PreToolUse entry that blocks those commands in an agent's shell and blocks file edits to the autopilot approval record. It fails closed: a missing script, missing node or 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; the approval-guard kind.
  • 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/ — decision approval-guard-terminal-is-the-line.
  • Tests: new agent-cannot-approve-itself.test.ts (58) and human-at-terminal.ts; five files use the helper; lifecycle-hooks-install and project-root-call-sites updated.

blocking-actions-never-block

A check marked blocking: true now stops work, and says why.

  • on-phase-exit blocks. aidlc transition runs the phase's exit actions once every other gate has passed and before it writes anything. A failing blocking action is a blocking-action violation naming the action and its error — in the human output, with a next step, and in --json. Nothing is written and on-phase-enter does not fire. An untrusted run: command counts as a failure, and its error names aidlc doctor.
  • on-phase-enter and on-instance-complete keep 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.
  • --json success payloads gain action_failures: [{ event, id, error, blocking }] when any action failed. Absent otherwise; no other field changes.
  • Every failure prints. emit used to print only non-blocking failures; a blocking one broke out of the loop first.
  • aidlc start and on-instance-start are unchanged. aidlc gate runs 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-run clean).

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.