Summary
stash plan --complete-rollout skips the production-deploy gate, so it asks for confirmation. But that confirmation is an interactive p.confirm (default-no) with no bypass — so a non-interactive run (CI, agent, piped stdin) auto-cancels and exits 0 via CancelledError.
Automation asks for a complete-rollout plan, gets exit 0, and has to assume a plan existed when none was drafted. Two gaps:
- Not automatable — there's no way to confirm the gate-skip without a TTY.
- Dishonest exit code — a cancelled run that drafted no plan still exits 0.
Expected
- A flag (e.g.
--yes) should confirm the gate-skip without a prompt, still logging the safety warnings so the record shows what was skipped.
- A non-interactive
--complete-rollout without consent should refuse with a non-zero exit and point at the flag, rather than silently cancelling with 0.
- An interactive decline should stay exit 0 — a deliberate "no" isn't a failure.
Resolution
Fixed in #686 — scoped --yes confirms the gate-skip; non-interactive --complete-rollout without --yes exits 1 with a pointer to --yes; interactive decline still exits 0.
Summary
stash plan --complete-rolloutskips the production-deploy gate, so it asks for confirmation. But that confirmation is an interactivep.confirm(default-no) with no bypass — so a non-interactive run (CI, agent, piped stdin) auto-cancels and exits 0 viaCancelledError.Automation asks for a complete-rollout plan, gets exit 0, and has to assume a plan existed when none was drafted. Two gaps:
Expected
--yes) should confirm the gate-skip without a prompt, still logging the safety warnings so the record shows what was skipped.--complete-rolloutwithout consent should refuse with a non-zero exit and point at the flag, rather than silently cancelling with 0.Resolution
Fixed in #686 — scoped
--yesconfirms the gate-skip; non-interactive--complete-rolloutwithout--yesexits 1 with a pointer to--yes; interactive decline still exits 0.