Skip to content

fix: describe what transfer_workitems actually does - #209

Open
dheeru0198 wants to merge 1 commit into
mainfrom
fix/cycle-transfer-precondition
Open

fix: describe what transfer_workitems actually does#209
dheeru0198 wants to merge 1 commit into
mainfrom
fix/cycle-transfer-precondition

Conversation

@dheeru0198

@dheeru0198 dheeru0198 commented Aug 19, 2026

Copy link
Copy Markdown
Member

Description

cycle.transfer_workitems advertised itself as "moves everything to new_cycle_id". Both halves of that are wrong.

  1. It moves only unfinished work items. The endpoint's own API description: "Move incomplete work items from the current cycle to a new target cycle. Captures progress snapshot and transfers only unfinished work items."
  2. It refuses unless the source cycle has already ended, and nothing on the surface said so:
# plane/api/views/cycle.py — TransferCycleIssueAPIEndpoint.post
if old_cycle.end_date is not None and old_cycle.end_date > timezone.now():
    return Response({"error": "The old cycle is not completed yet"}, status=400)

So for the ordinary request "this sprint is wrapping up — close it and move the leftover work to the next one", the intuitive order is rejected. You must complete the cycle first, then transfer. An agent discovers this only by making the call and reading a bare 400.

How it was found

While measuring this tool surface with an eval harness. Three models across two vendor CLIs hit it on the same task, deterministically — identical arguments, identical 400, then a recovery attempt. It was the most-errored action in every run, and the only error attributable to the tool description rather than to the model.

run errored / calls
gpt-5.6-luna (codex-cli) 2 / 4
sonnet (claude-cli) 2 / 4
haiku (claude-cli) 2 / 5

Every one of those is a wasted round trip paid by every agent that tries the obvious order.

Verified by re-measuring

Same task, same models, same harness — only the note changed:

pass total calls transfer_workitems errored
sonnet, old note 3/3 25 2 / 4
haiku, old note 3/3 23 2 / 5
sonnet, new note 3/3 18 0 / 3
haiku, new note 3/3 13 0 / 3

Every failed call is gone on both tiers, and the transfer count settles at exactly one per
repetition with no retries. Total calls fell 28% for sonnet and 43% for haiku, with success
unchanged. Haiku's incidental cycle.list and project.retrieve errors disappeared too —
it no longer has to re-orient after being refused.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Documentation update

Test Scenarios

  • Ask an agent to close a running cycle and move its unfinished items to another cycle; it should now complete first and transfer second, without the failed call.
  • Confirm the generated tool description carries the precondition: transfer_workitems (project_id, cycle_id, new_cycle_id) -- moves only the unfinished work items to new_cycle_id; the source cycle must have ended first, so complete it before transferring or the call is rejected

Note: pytest tests/tools reports 17 pre-existing failures on origin/main (all in test_workitem_property.py, TypeError: 'function' object is not subscriptable). Identical count with and without this change — unrelated, but worth someone's attention.

References

Text-only change to one Action note; no behaviour change.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Clarified that work item transfers include only unfinished items.
    • Documented that the source cycle must have ended before transfers can proceed.
    • Transfers are rejected when these conditions are not met.

The note said "moves everything to new_cycle_id". Both halves were wrong.

The endpoint transfers only the *unfinished* work items — its own API
description says so — and it refuses outright unless the source cycle has
already ended:

    if old_cycle.end_date is not None and old_cycle.end_date > timezone.now():
        return Response({"error": "The old cycle is not completed yet"}, 400)

So the natural order for "close this cycle and move its leftover work" is
backwards: complete first, then transfer. Nothing on the tool surface said
so, and the failure is a bare 400 discovered only by making the call.

Found while measuring the tool surface with an eval harness. Three models
across two vendors hit it on the same task, deterministically: identical
arguments, identical 400, then a recovery. It was the single most errored
action in every run — one wasted call each time, paid by every agent that
tries the obvious order.
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 474a57d2-6e94-4cbe-8b2c-687c3e514fab

📥 Commits

Reviewing files that changed from the base of the PR and between 00d9d1f and d1da171.

📒 Files selected for processing (1)
  • plane_mcp/tools/cycle.py

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

The transfer_workitems action metadata now states that only unfinished work items transfer and that the source cycle must have ended. Required parameters remain unchanged.

Changes

Cycle work item transfer

Layer / File(s) Summary
Transfer action contract
plane_mcp/tools/cycle.py
The transfer_workitems description documents the unfinished-item and ended-cycle requirements.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Merge Risk: ⚪ Minimal · up to d1da1

This localized documentation update clarifies the existing transfer behavior without changing runtime behavior, and no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: akhil-vamshi-konam

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the documentation fix for transfer_workitems and matches the main change.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cycle-transfer-precondition

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants