WIP: create_work_item ignores current_phase='draft' and lands items in 'working', so every planned item is immediately dispatchable #608

Draft
toasterson wants to merge 3 commits from claude/wi-019ff2f6-create-work-item-ignores-current-phase-d into main
Owner

Anima work item 019ff2f6-60cb-7542-9464-249563b958f5.

Problem

mcp__anima__create_work_item accepts a current_phase argument documented as "Initial phase (optional). Use 'draft' for plan items that must NOT be implemented until the plan is promoted to a work slice." It is ignored.

Reproduced 2026-08-11: four work items were created with current_phase: "draft" under two plans (WI-549, WI-550, WI-551, WI-552). All four came back with current_phase: "working" — the phase implementers dispatch from. With the scheduler unpaused they were immediately eligible, including two items that explicitly must not start until a prerequisite plan lands.

Why it matters

This breaks the core planning guarantee (ADR 0001/0006): items are authored draft under a Plan and nothing implements until the Plan is promoted to a Slice. Right now authoring a plan is dispatching it. The human approval gate exists in the tools and in the skills, and the write path silently steps around it.

It also breaks promotion itself. promote_plan_to_slice returned promoted_items: 0 for a plan holding two items — because it looks for draft items to promote and there were none. So the operator sees a plan that promotes nothing while its items are already running: the "go" act reports doing nothing precisely when everything has already gone.

Sequencing depends on this. Dependency edges (ADR 0036) are merged but not implemented, so plan promotion is currently the only mechanism that orders work. Losing draft removes it entirely.

Repro

create_work_item(project_id=…, plan_id=…, title=…, current_phase="draft")
→ get_work_item_by_id(…)  ⇒  "current_phase": "working"

Asks

  1. Honour current_phase on create; draft must stay draft.
  2. Decide and document the default when the argument is omitted. working looks wrong for a plan-authoring verb — draft is the safer default, and an item that should start immediately can say so.
  3. promote_plan_to_slice returning promoted_items: 0 should be loud, not a quiet success: a promotion that promotes nothing is either a no-op or a bug, and today it reads identical to success.
  4. Regression test asserting a created-draft item is not dispatchable.

Workaround in use

set_work_item_phase(..., 'draft', reason=…) immediately after creation, which is racy — the scheduler ticks every 10s and can dispatch in the gap.

Anima work item `019ff2f6-60cb-7542-9464-249563b958f5`. ## Problem `mcp__anima__create_work_item` accepts a `current_phase` argument documented as *"Initial phase (optional). Use 'draft' for plan items that must NOT be implemented until the plan is promoted to a work slice."* It is ignored. Reproduced 2026-08-11: four work items were created with `current_phase: "draft"` under two plans (WI-549, WI-550, WI-551, WI-552). All four came back with `current_phase: "working"` — the phase implementers dispatch from. With the scheduler unpaused they were immediately eligible, including two items that explicitly must not start until a prerequisite plan lands. ## Why it matters This breaks the core planning guarantee (ADR 0001/0006): items are authored **draft** under a Plan and nothing implements until the Plan is **promoted to a Slice**. Right now authoring a plan *is* dispatching it. The human approval gate exists in the tools and in the skills, and the write path silently steps around it. It also breaks promotion itself. `promote_plan_to_slice` returned `promoted_items: 0` for a plan holding two items — because it looks for draft items to promote and there were none. So the operator sees a plan that promotes nothing while its items are already running: the "go" act reports doing nothing precisely when everything has already gone. Sequencing depends on this. Dependency edges (ADR 0036) are merged but not implemented, so plan promotion is currently the *only* mechanism that orders work. Losing draft removes it entirely. ## Repro ``` create_work_item(project_id=…, plan_id=…, title=…, current_phase="draft") → get_work_item_by_id(…) ⇒ "current_phase": "working" ``` ## Asks 1. Honour `current_phase` on create; `draft` must stay `draft`. 2. Decide and document the default when the argument is omitted. `working` looks wrong for a plan-authoring verb — `draft` is the safer default, and an item that should start immediately can say so. 3. `promote_plan_to_slice` returning `promoted_items: 0` should be loud, not a quiet success: a promotion that promotes nothing is either a no-op or a bug, and today it reads identical to success. 4. Regression test asserting a created-draft item is not dispatchable. ## Workaround in use `set_work_item_phase(..., 'draft', reason=…)` immediately after creation, which is racy — the scheduler ticks every 10s and can dispatch in the gap.
Add three integration tests closing the promote-path gap left by the WI-553
fix commit (c7dc5eb4), which only covered the gRPC create-side draft gate:

- test_promote_flips_draft_items_to_ready_and_counts_them: end-to-end
  create-draft → promote → ready, asserts promoted_items==2, empty
  warning, and that both items match the scheduler's
  current_phase IN ('ready','working') query.
- test_promote_empty_plan_warns_loudly: a promotion that promotes nothing
  on an empty plan must surface a non-empty warning naming 'no work items'
  (ask 3), not a quiet zero-as-success.
- test_promote_already_promoted_warns_loudly: re-promote of an
  already-promoted plan (items now ready, none draft) must warn and
  distinguish 'items exist but none are draft' from 'no items'.

All three pass against the live Postgres test container.
toasterson force-pushed claude/wi-019ff2f6-create-work-item-ignores-current-phase-d from 8c82c68703 to 6564dd6c75 2026-08-19 21:01:23 +00:00 Compare
This pull request is marked as a work in progress.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin claude/wi-019ff2f6-create-work-item-ignores-current-phase-d:claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git switch claude/wi-019ff2f6-create-work-item-ignores-current-phase-d

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git switch claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git rebase main
git switch main
git merge --ff-only claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git switch claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git rebase main
git switch main
git merge --no-ff claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git switch main
git merge --squash claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git switch main
git merge --ff-only claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git switch main
git merge claude/wi-019ff2f6-create-work-item-ignores-current-phase-d
git push origin main
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
toasterson/Anima!608
No description provided.