A draft stranded between create and publish cannot be finished or removed through the contract

The need

On GitHub and Gitea, ReleaseAssetPublisher.CreateReleaseWithAssets creates the release as a draft, uploads into it, and publishes last. If the process dies between the create and the publish (a runner killed mid-job, which happened across this estate on 2026-09-03 while the only runner was over its memory), the draft stays. forge-github's own discardDraft comment records the consequence: "the release exists, so a retry gets ErrAlreadyExists, and this contract has no verb to finish or remove it."

A caller re-running a release cannot recover from that state. GetReleaseByTag does not return drafts on GitHub, UpdateRelease takes only name and body, and there is no delete, so from the caller's side the tag carries a release it cannot see, cannot publish, and cannot replace.

The use case

colophon's release verb (colophon spec 0005) is meant to be idempotent, and colophon spec 0006 makes a re-run attach the assets an existing release is missing. Both stop at a stranded draft: they can detect only ErrAlreadyExists, and the only recovery is a person deleting the draft in the forge UI. The estate runs GitLab in earnest, where this cannot happen, so this is about the contract keeping its promise on the adapters that take the draft route.

Not prescribed

Whether this is a verb to publish a draft the caller created, a verb to discard one, having GetReleaseByTag surface a draft to a caller with write access so it can be reasoned about, or a decision that the adapter's own discard on failure is the whole of the guarantee, is the maintainers' call. Raised so the gap is recorded against the contract rather than only in an adapter's comment.