Stealable preview leases for draft PRs
Update 2026-08-10: the v1 draft-skip policy (and the
previewopt-in label,--allow-draft,decideDraftPreviewPolicy) was removed outright — every open PR now gets previews, draft or not. That deletes this task's premise and its "revert v1" checklist items. The stealing idea only becomes relevant again if slot contention returns; the draft/ready split would then need a different priority signal since drafts are no longer second-class.
Follow-up to tasks/complete/2026-07-07-draft-prs-no-preview-lease.md (PR
#1720), which is the blunt v1: draft PRs skip previews entirely unless they
opt in. The better shape (Misha's suggestion): drafts DO deploy and get e2e
signal when capacity is spare, but their lease is second-class — a ready PR
that finds no free slot may steal a draft's slot.
Sketch#
Slot selection for a ready PR, in priority order:
- a free slot (least-recently-released first, as today — freed slots rest)
- steal from the stalest draft-held lease (oldest
updatedAt/renewal first) - queue, as today
Design constraints (from the PR #1720 discussion)#
- Only steal draft-held AND idle leases (no renewal in ~30min). Renewals happen at run start and runs take ~6–20min, so idle ≈ not mid-run. This preserves the invariant that two PRs never deploy onto the same slot concurrently — per-PR concurrency groups don't protect across PRs, and an automated steal during a victim's in-flight deploy means both write workers to the same slot. Under total contention with all-fresh drafts (bedtime), ready PRs still queue; accepted.
- Steal must be atomic-ish in the semaphore (check-idle → evict → acquire): two ready PRs can target the same victim at once. This is a semaphore-level feature (lease priority/stealability), not deploy-script logic.
- Victim recovery mostly exists already: deploy handles "my slot is
gone / someone took it" by claiming a fresh slot and redeploying the whole
fleet, and the PR-body banner machinery narrates slot moves. Add a banner
variant naming the thief PR and why ("you're a draft; mark ready or add
the
previewlabel to hold a slot firmly"). - Once this lands, the v1 policy (skip previews for drafts) should be
removed or reduced; the
previewlabel could be repurposed as "don't steal my draft's lease". Updatedocs/dev-environments.md, README/CLAUDE "Before PRs" note, and thedecideDraftPreviewPolicyunit tests.
Checklist#
- semaphore: leases carry a stealable/priority flag (or holder metadata enough to derive it) and an atomic steal operation
- acquire path: free slots → stalest idle draft-held lease → queue
- victim PR-body banner naming the thief and the opt-out
- revert/soften the v1 draft-skip policy in
preview deploy - docs + AGENTS/README note updated