v4.3.1: fix /code:plan → /code:ship handoff (schema trap, silent rejection, stale-task pollution) - #65
Merged
Conversation
…ction, stale-task pollution)
Live session hit three compounding bugs: (1) the TaskCreate metadata example
in commands/plan.md used pipe-alternation in value position
("user_story": "US-N | AC-N.M | chore:<reason>"), which the planner copied
verbatim as "US-1 | AC-1.1, AC-1.2" — correctly rejected by the PreToolUse
hook regex, but (2) Phase 3 had no recovery path so the orchestrator
narrated forward on phantom task ids; (3) /code:ship then read project-global
TaskList which still contained pending tasks from the prior merged PRD and
none for the current branch, and exited with "no queue" instead of diagnosing.
Fix 1: replace alternation-as-value with concrete singular examples
("US-1", "interface") and lift the allowed-forms enumeration into adjacent
prose so the schema can't be copied wrong.
Fix 2: §"On TaskCreate rejection" — read the rejection dump, identify the
bad field, re-issue the same TaskCreate; never call TaskUpdate on phantom
ids. Three retries on the same field escalates to the user.
Fix 3: §"Pre-dispatch" scopes the queue to tasks whose user_story matches
the active PRD's US/AC tags or starts with "chore:" (chores during a
feature are this-branch work, never stale). Empty-queue branch now
distinguishes three cases (PRD/no tasks; PRD/different-PRD tasks;
no PRD/no tasks) with specific next-step messages.
Also bumps marketplace.json 4.2.3 → 4.3.1, catching up the 4.3.0 release
that missed the marketplace metadata.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A live
/code:plan→/clear→/code:shipsession reproduced three compounding bugs that landed the orchestrator on phantom task ids and the dispatcher on an empty queue. Root cause traced via the hook's rejection dump at${TMPDIR}/code-et-task-hook/last-rejected.json:Bug 1 (trigger) — schema trap in
commands/plan.md. The metadata example showed"user_story": "US-N | AC-N.M | chore:<reason>"with pipe-alternation in value position. The planner read the|as composition, emitted"US-1 | AC-1.1, AC-1.2", and the PreToolUse hook regex (correctly) rejected. Fixed by replacing the example values with concrete singular tags ("US-1","interface") and moving the allowed-forms enumeration into adjacent prose.Bug 2 (what made it invisible) — no recovery from rejection (
commands/plan.md§"On TaskCreate rejection"). Phase 3 had no instruction for hook exit-2, so the orchestrator narrated"Now wiring task dependencies…"on task ids that didn't exist. Added explicit recovery: read the rejection dump, identify the field, re-issue the sameTaskCreate; neverTaskUpdate(addBlockedBy)on phantom ids. Three retries on the same field escalates to the user.Bug 3 (what made the symptom hard to diagnose) — silent empty queue + stale-task pollution in
/code:ship(commands/ship.md§"Pre-dispatch").TaskListis project-global, not branch-scoped — pending tasks from a merged PRD persist forever, and/code:shipwas both dispatching them blindly and (when the current branch had no tasks) reporting "no queue" with no diagnostic. Added Pre-dispatch step that resolves the active PRD, parses its## Story Checklistfor US tags, and scopes the queue to matchingUS-N/AC-N.M/chore:*tasks. Empty-queue branch now distinguishes three cases with specific next-step messages.Also catches up
marketplace.json(was stale at 4.2.3; missed in #64).Known follow-up
This release prevents dispatch of stale tasks but does not clear them. A v4.3.2 task-completion-on-PR-merge hook is the proper fix; tracked in the CHANGELOG entry.
Test plan
/code:planan idea → verify TaskCreate calls use singularuser_storyvalues, no rejections in${TMPDIR}/code-et-task-hook/last-rejected.json."US-1 | AC-1.1") → orchestrator stops on that call, reads the dump, retries with corrected value./code:shipon a branch with PRD on disk + 0 tasks → expect "Active PRD: …, 0 tasks tied to its user stories. Run /code:plan to decompose."/code:shipon a branch with PRD + only stale-from-other-PRD pending tasks → expect "Pending tasks (N) belong to a different PRD."/code:shipon a branch with PRD + matching tasks + onechore:*task → both dispatch.🤖 Generated with Claude Code