T-XKWA-start-task-drops-orphan-stashes
Status: closed/obsoleted · Impact: low · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to open/ready before picking up.
When /sdlc:task-work Step 4 (or its start_task.ts helper) stashes
a working-tree dirty file before rebasing, the stash can outlive the
file: if the path doesn’t exist on the post-rebase tree (because it
was deleted, moved, or restructured upstream), the stash becomes
orphaned and accumulates in git stash list indefinitely. Cite
T-5VN7-pr-check-cursor-bootstrap-misses-existing-comments —
the sub-agent stashed an unrelated dirty docs/decisions/0001-github-ref-leases.md
that no longer existed (the file was restructured into a folder) on
the post-rebase tree, and stash@{0} is still sitting there.
start_task.ts could detect this class of stash before stashing
(or right after rebase) and prompt to drop.
| Location | Role today |
|---|---|
plugin/skills/task-work/start_task.ts | Stashes any dirty working-tree files before performing the start-of-task rebase; does not inspect the stash post-rebase for orphan-file references. |
plugin/skills/task-work/SKILL.md (Step 4) | Documents the stash step; does not call out the orphan-stash risk. |
plugin/skills/task-work/tests/start_task.test.ts | Exercises start-task flows; no fixture for the orphan-stash case. |
Today the operator only discovers orphaned stashes by running
git stash list weeks later, by which point the context for what
they contain is lost.
Proposed
Section titled “Proposed”start_task.ts (or a Step 4 hook it shells out to) checks for
pre-existing stashes whose stashed paths do not exist on the
post-rebase tree. When it finds one, it prints the stash entry +
contained paths and prompts the operator to drop it (or, when
running non-interactively, logs the warning and proceeds without
dropping — never silently dropping work).
The check is bounded: only stashes the script itself created (or all stashes in the list, with the orphan-file heuristic to filter relevance) — implementer’s call. The prompt happens at the end of Step 4 so the operator sees the question while task context is hot.
Approach
Section titled “Approach”- Decide on detection scope: only stashes whose message starts with
the marker
start_task.tswrites, or every stash in the list with an additional file-existence filter. The first option is tighter; the second handles operator-created stashes too. - Implement the post-rebase scan:
git stash list --format=%gd %gs, then for each entry,git stash show --name-only <stash>and check each path against the post-rebase tree. If all paths are missing, mark the stash as orphan-candidate. - Add the interactive prompt (TTY) / non-interactive log (no TTY) path. Never drop a stash without operator approval.
- Add a fixture and a regression test that exercises both branches (TTY-prompt-approved and non-interactive-log-only).
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/skills/task-work/start_task.ts | modify | After the rebase succeeds, scan stash list for orphans and surface them. |
plugin/skills/task-work/tests/start_task.test.ts | modify | Add a fixture/test for the orphan-stash detection path. |
plugin/skills/task-work/SKILL.md | modify | Step 4 prose mentions the new orphan-stash check. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: After
start_task.ts’s rebase completes, the script scansgit stash listfor stashes whose stashed paths are all missing on the post-rebase tree. - AC-2: When orphan stashes are found AND stdout is a TTY, the script prompts the operator to drop or keep each one.
- AC-3: When orphan stashes are found AND stdout is NOT a TTY, the script logs the orphans (basename + paths) to stderr and proceeds — never silently dropping.
- AC-4: A regression test exercises both branches with a fixture that creates a stash, performs a rebase that removes the stashed file, and asserts the post-rebase behavior matches the TTY mode.
Out of scope
Section titled “Out of scope”- Cleaning up orphaned stashes from BEFORE this task ships. The detection is forward-looking; existing orphan stashes get cleaned by hand or by a separate sweep skill.
- Reconciling stash contents that conflict with the post-rebase tree (the operator may want to re-apply the change to the new location). The prompt only handles drop-or-keep, not migration.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-5VN7-pr-check-cursor-bootstrap-misses-existing-comments on 2026-05-23.
Dedup search (spawn-from-post-mortem)
Section titled “Dedup search (spawn-from-post-mortem)”Bullet: The sub-agent stashed an unrelated working-tree dirty file that turned out to no longer exist on the post-rebase tree. The stash is still in the stash list and orphaned. start_task.py (or a Step 4 hook) could check for pre-existing stashes referencing files that no longer exist on the target rebase and prompt to drop them. Keywords searched: working-tree, pre-existing, post-rebase, referencing, start_task, sub-agent, unrelated, orphaned Excluded: 2026-05-21-pr-check-cursor-bootstrap-misses-existing-comments Top candidates (score / status / headline):
- 26 / closed/done / 2026-05-20-task-work-sub-agent-verdict-contract-clarity — Tighten task-work sub-agent verdict contract so ensure-ready’s READY marker isn’t mistaken for task-work’s final verdict
- 22 / closed/done / 2026-05-21-start-task-preserves-readiness-stamp — start_task.py should preserve readiness_verified_at across rebase
- 19 / closed/done / 2026-05-19-extract-start-task-script — Extract task-work Step 5b into scripts/start_task.py
- 19 / planning/draft / 2026-05-21-audit-entities-baseline-allow — audit_entities.py: distinguish pre-existing drift from PR-introduced drift
- 18 / planning/draft / 2026-05-21-start-task-handles-frontmatter-rebase-cleanly — start_task.py auto-merges frontmatter on stamp/start rebase conflict Decision: SPAWNED