Deploy UX: strong-approval isn't automatable, `-y` is misleading, and a no-op migrate downgrades to changed=unknown
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 3
- Forks
- 0
- Avg merge
- 2h 40m
- Merged PRs (30d)
- 63
Description
Feedback from a real production deploy (pursue → v2026.07.10) driven end-to-end through ob. The tool is genuinely strong — the plan output (risk/reversibility/approval, pinned digests, exact remote commands) and the deploy trace (preflight → transfer → migrate → rolling drain/converge → verify → activate, with a rollback hint) are clear and confidence-inspiring. These are refinements, most-valuable first.
1. Strong-approval path isn't automatable, and -y is misleading
ob deploy -y is documented as "skip the confirmation prompt" (cmd/ob/commands.go:203), but a strong plan still hard-fails without a grant:
✗ ob: strong approval is required for this exact deployment plan; create a bound grant with
ob approve --plan PLANand apply it withob deploy --plan PLAN --approval APPROVAL
So -y reads as "this will deploy" when it won't (see the structured-deploy guard at cmd/ob/commands.go:609,629). Worse, ob approve exposes only --plan and --out (cmd/ob/commands.go:177-188) — there is no non-interactive confirmation flag. The only way to approve from a non-TTY (CI, an agent, a script) is to pipe the exact release ID into the interactive prompt:
printf '%s\n' "$RELEASE_ID" | ob approve --plan plan.json -o approval.json
That's fragile and clearly not an intended interface.
Suggested:
- Add a first-class non-interactive approve, e.g.
ob approve --plan PLAN --confirm <release-id>(require the ID as an explicit arg so it stays a deliberate act, not a blanket--yes). - Clarify
-y's help: it does not satisfy strong approval. Ideallyob deploy -yon a strong plan fails fast stating that (it already points to approve+approval, which is good). - Consumers wiring
obintojust/CI hit this immediately: ajust deploythat runsob deploy --plan …always fails on strong plans because there's no scriptable approve step to put in front of it.
2. A no-op migration downgrades rollback safety to changed=unknown
This deploy touched no schema, and the plan correctly showed job:migrate … changed=false. But at execution:
⚠ migration job migrate: changed=unknown (result file is missing); automatic rollback is unavailable after this step
The gate mounts a result file and reads it back (internal/engine/gate.go:112-165); when the job doesn't write OB_RESULT_FILE, it falls to reason = "result file is missing" → changed=unknown (internal/engine/gate.go:171,202). The stock atlas migrate image doesn't write that file on a clean no-op, so a zero-change deploy silently loses automatic rollback.
Suggested: treat a clean migrate exit with no diff as changed=false (keep rollback open), or have the bundled migrate wrapper always write a result on success. A no-op migration shouldn't be scarier than a real one.
3. Tight, shared plan/approval expiry
The bound plan expired ~15 min after generation (expires: 2026-07-14T21:34:51Z), and plan → approve → deploy all share that window. For a flow whose whole point is a human approval pause, 15 min is short. A longer default (or a visible countdown / "regenerate" hint on expiry) would cut down on plan-regeneration churn.
4. Artifact hygiene
Plan and approval artifacts land in CWD (ob approve defaults --out ob-approval.json, cmd/ob/commands.go:186). Over a few releases the repo root accumulates ob-plan-*.json and now ob-approval-*.json (the grant is correctly 0600). Consider defaulting these under an XDG/state dir, plus an ob prune for spent plans and consumed grants.
5. Minor: dirty build in a release tool
The runner self-reports ob 0.0.1-m0 (…+dirty). A tool deploying production from a dirty build is a smell — consider warning (or refusing without --force).
Happy to send a PR for #1 (non-interactive ob approve --confirm) if that direction sounds right.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in cmd/ob/commands.go:177-188, 203, 609, and 629 to trace approval and deploy flags, then inspect internal/engine/gate.go:112-165, 171, and 202 for migration results. Confirm the intended scope with maintainers, then verify scriptable strong approval, accurate -y behavior, and safe no-op migration handling before considering the expiry, artifact, and dirty-build refinements.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, go
- Domain
- cli, devops, infrastructure
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100