Skip to content

Withdrawing a plan keeps it (UPG) - #475

Merged
dannash100 merged 2 commits into
mainfrom
feature/withdraw-plans
Aug 3, 2026
Merged

Withdrawing a plan keeps it (UPG)#475
dannash100 merged 2 commits into
mainfrom
feature/withdraw-plans

Conversation

@dannash100

Copy link
Copy Markdown
Contributor

Follow-up to #423. Withdrawing a plan hard-deleted the row, so "we were going to 2.61 in March, then dropped it" left no trace of ever having been decided.

Everything else in UPG is retained: a replaced plan keeps superseded_at, a met plan keeps met_at, and that history is what makes "how long do our upgrades really take" answerable. Withdrawal was the one hole in it.

Now a topical soft delete, withdrawn_at / withdrawn_by, with every open-plan query filtering on withdrawn_at IS NULL.

Two things worth arguing with:

The partial unique index had to move. upgrade_plans_one_open_per_group was WHERE met_at IS NULL AND superseded_at IS NULL. Left as it was, a withdrawn plan keeps holding the group's one open slot and blocks recording a replacement, which is the opposite of what withdrawing is for. The migration drops and recreates it with withdrawn_at IS NULL in the predicate.

The down migration deletes withdrawn plans rather than reopening them, and is marked DESTRUCTIVE. Reopening them would fail the restored narrower index for any group that withdrew one plan and then recorded another.

withdraw() returns Option<Self> and filters on the plan still being open, so withdrawing twice is a no-op rather than restamping who did it.

Nothing changes for the operator. The fleet view keys off all_open, so a withdrawn plan drops to the unplanned list exactly as before, and the existing Playwright test for that passes untouched.

@passcod

passcod commented Aug 3, 2026

Copy link
Copy Markdown
Member

is there UI to see withdrawn plans?

@passcod

passcod commented Aug 3, 2026

Copy link
Copy Markdown
Member

Also might want (here or follow up if missing in general) MCP surface for this

@dannash100

dannash100 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Both done in 8eaa162.

UI. There wasn't any: for_group existed but nothing rendered it. The upgrades page now has a Past plans section, most recently closed first, showing where each deployment was going, the date it was planned for, and how it ended. Withdrawn reads differently from met, and the chip's tooltip carries who withdrew it. Fed by a new fleet-wide /api/upgrade_plans/history.

upgrades page

withdrawn tooltip

MCP. There was no upgrade-plan surface at all, so it's two read-only tools rather than a withdrawal-shaped patch. list_upgrade_plans gives every group's open plan with the version it runs, the version it's going to, the planned date and late, plus the groups with nothing recorded. get_upgrade_plan_history takes a group and gives every plan it has had, each with its outcome (open, met, replaced, withdrawn) and who recorded, amended or withdrew it. The server instructions now say a late plan is normal operational reality, so an agent doesn't file one as an incident.

The outcome derivation (PlanOutcome, outcome(), ended_at()) sits in the database crate, so the web view and MCP can't drift on what withdrawn means. UPG and MCP specs updated, endpoint and tool tests added, plus two more Playwright cases.

Screenshots are seeded e2e data, on assets/upgrade-plan-history so they render here; happy to drop that branch if you'd rather not have it hanging around.

@dannash100
dannash100 added this pull request to the merge queue Aug 3, 2026
Merged via the queue into main with commit 7b68097 Aug 3, 2026
7 checks passed
@dannash100
dannash100 deleted the feature/withdraw-plans branch August 3, 2026 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants