Skip to content

Deploy UX: strong-approval isn't automatable, -y is misleading, and a no-op migrate downgrades to changed=unknown #11

Description

@vishr

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 PLAN and apply it with ob 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. Ideally ob deploy -y on a strong plan fails fast stating that (it already points to approve+approval, which is good).
  • Consumers wiring ob into just/CI hit this immediately: a just deploy that runs ob 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions