Skip to content

Commit 87ba2aa

Browse files
docs: define Gallery prerelease recovery
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent ed22f0b commit 87ba2aa

2 files changed

Lines changed: 59 additions & 5 deletions

File tree

docs/content/reference/process-workflow-lifecycle-design.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ The confirmed reusable workflow runs a `Plan` job, enriches one settings object
1515

1616
The version resolver treats non-pull-request events, including `workflow_dispatch` and `schedule`, as events without a release decision. The workflow's concurrency identity contains either the pull request number or the Git ref, and its runs are not canceled. The documented scenario matrix also identifies closed-pull-request cleanup as non-stable behavior.
1717

18-
These facts establish the starting point. They do not implement the scheduled validation or manual recovery behavior proposed below.
18+
The current code detects an existing published version, resumes GitHub Release creation, and repeats GitHub Release and tag cleanup. Full reconciliation of immutable PowerShell Gallery prereleases is a design gap: it requires implementation and cancellation-boundary tests. These facts establish the starting point. They do not implement the scheduled validation or manual recovery behavior proposed below.
1919

2020
## Candidate event routing
2121

@@ -80,14 +80,25 @@ Cancellation can leave only transient partial state. Every pull-request route, i
8080

8181
| External operation | Required recovery behavior |
8282
| --- | --- |
83-
| PowerShell Gallery publication | Detect the existing resolved version and continue without duplicate publication. |
83+
| PowerShell Gallery publication | Use a deterministic pull-request-scoped prerelease identity, detect the existing resolved version, and continue without duplicate publication. |
8484
| GitHub Release creation | Resume or upsert the release and replace its asset set. |
8585
| Prerelease cleanup | Repeat safely after partial deletion and converge to the latest pull-request state. |
8686
| Prerelease lifecycle | A subsequent synchronize, label, unlabel, or close reconciles obsolete prereleases. |
8787
| Production boundary | No pull-request event creates a stable or signable production artifact. |
8888

8989
Cleanup receives a pull-request-scoped artifact set and MUST NOT perform a broad prerelease deletion while a stable release can be active. Any future broad cleanup needs a separately approved exclusive scope; it cannot share the abandoned-close route.
9090

91+
## Candidate Gallery prerelease disposition
92+
93+
PowerShell Gallery packages are immutable and cannot be overwritten. Gallery reconciliation is therefore separate from GitHub Release and tag cleanup:
94+
95+
| Obsolete Gallery prerelease condition | Candidate disposition |
96+
| --- | --- |
97+
| A supported Gallery API can unlist the version | Unlist the immutable package through that API. |
98+
| Unlisting is not feasible | Retain the immutable version and record it as retained in the lifecycle result. |
99+
100+
The selected disposition policy remains unapproved. A cancellation can leave a published immutable package even when its GitHub Release and tag cleanup has not completed; the next pull-request event must detect that version and apply the approved Gallery disposition rather than attempting to overwrite it.
101+
91102
## Candidate verification strategy
92103

93104
The lifecycle contract is exercised with event payload fixtures and publication fakes before credentials are used:
@@ -99,6 +110,7 @@ The lifecycle contract is exercised with event payload fixtures and publication
99110
| Recovery release notes | Merged-pull-request query fixtures covering an empty range, one pull request, and multiple pull requests. |
100111
| Scheduled validation | A published-version fixture that proves no release mutation is requested. |
101112
| Pull-request convergence | Canceled prerelease-publication and cleanup fixtures followed by synchronize, label, unlabel, and close events that prove the latest pull-request state is reconciled. |
113+
| Gallery immutability | Deterministic pull-request identity, existing-version detection, supported-unlist, and retained-version fixtures across the cancellation boundary. |
102114
| Non-pull-request serialization | Overlapping main-push, manual-dispatch, and scheduled fixtures that prove runs queue by ref and do not cancel. |
103115

104116
## Decisions requiring approval
@@ -109,6 +121,7 @@ The candidate does not decide the following:
109121
- Which source is authoritative when a PowerShell Gallery publication and GitHub release disagree about the last published stable version.
110122
- Which consumer-facing checks comprise scheduled published-artifact validation.
111123
- Whether removing prerelease eligibility cleans up existing prereleases immediately or leaves them until the abandoned-close cleanup route.
124+
- Whether the supported Gallery API can unlist obsolete prereleases; otherwise, how retained immutable versions are recorded.
112125
- Approval of the selected caller concurrency expression in [PSModule/Process-PSModule#514](https://github.com/PSModule/Process-PSModule/issues/514).
113126

114127
## Related

docs/content/reference/process-workflow-lifecycle-specification.md

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,25 @@ Scenario: Reject an incorrectly stamped artifact
149149
And no release is made visible for that artifact
150150
```
151151

152+
### FR8 — Pull-request prereleases MUST have deterministic scoped identities {#fr8}
153+
154+
A pull-request prerelease MUST use a deterministic identity scoped to its pull request. Reprocessing the same pull-request state MUST resolve the same prerelease identity, and different pull requests MUST NOT resolve the same identity.
155+
156+
#### Behavioral scenarios {#fr8-scenarios}
157+
158+
```gherkin
159+
Scenario: Reprocess the same pull-request state
160+
Given a pull request has resolved a prerelease identity
161+
When the same pull-request state is processed again
162+
Then the workflow resolves the same prerelease identity
163+
And it detects an existing publication instead of attempting an overwrite
164+
165+
Scenario: Publish prereleases for distinct pull requests
166+
Given two pull requests are eligible for prerelease publication
167+
When both pull requests are processed
168+
Then each pull request resolves a distinct prerelease identity
169+
```
170+
152171
## Non-functional requirements
153172

154173
### NFR1 — Lifecycle mutations MUST be idempotent {#nfr1}
@@ -201,7 +220,7 @@ Scenario: Inspect a scheduled validation result
201220

202221
### NFR4 — Pull-request mutation paths MUST resume and converge {#nfr4}
203222

204-
Every pull-request path, including prerelease publication and cleanup, MUST be idempotent and resumable after cancellation. The next `synchronize`, `labeled`, `unlabeled`, or `closed` event MUST converge release-related state to the latest pull-request state. Cancellation MAY leave transient partial state, but it MUST NOT leave a permanent duplicate or obsolete artifact.
223+
Every pull-request path, including prerelease publication and cleanup, MUST be idempotent and resumable after cancellation. The next `synchronize`, `labeled`, `unlabeled`, or `closed` event MUST converge release-related state to the latest pull-request state. Cancellation MAY leave transient partial state, but it MUST NOT leave a permanent duplicate or an obsolete artifact without the required disposition.
205224

206225
#### Behavioral scenarios {#nfr4-scenarios}
207226

@@ -216,7 +235,7 @@ Scenario: Reconcile obsolete prereleases
216235
Given a canceled pull-request run left prerelease artifacts for an earlier pull-request state
217236
When a synchronize, label, unlabel, or close event is processed
218237
Then the workflow reconciles prerelease artifacts to the latest pull-request state
219-
And no obsolete prerelease artifact remains after reconciliation
238+
And every obsolete prerelease has the required disposition
220239
```
221240

222241
### NFR5 — Pull-request events MUST NOT produce production artifacts {#nfr5}
@@ -233,6 +252,28 @@ Scenario: Evaluate an eligible prerelease pull request
233252
And it does not create a stable or signable production artifact
234253
```
235254

255+
### NFR6 — Immutable Gallery prereleases MUST have a disposition policy {#nfr6}
256+
257+
PowerShell Gallery packages MUST be treated as immutable and MUST NOT be overwritten. The candidate MUST define whether obsolete pull-request prereleases are unlisted through a supported Gallery API or retained as documented immutable versions when unlisting is not feasible. This policy is distinct from GitHub Release and tag cleanup.
258+
259+
#### Behavioral scenarios {#nfr6-scenarios}
260+
261+
```gherkin
262+
Scenario: Dispose of an obsolete Gallery prerelease
263+
Given a pull-request prerelease is obsolete
264+
And a supported Gallery API can unlist that version
265+
When the prerelease is reconciled
266+
Then the workflow unlists the immutable Gallery package
267+
And it performs GitHub Release and tag cleanup independently
268+
269+
Scenario: Retain an immutable Gallery prerelease
270+
Given a pull-request prerelease is obsolete
271+
And unlisting that Gallery version is not feasible
272+
When the prerelease is reconciled
273+
Then the workflow records the retained immutable Gallery version
274+
And it performs GitHub Release and tag cleanup independently
275+
```
276+
236277
## Cross-cutting acceptance criteria
237278

238279
### AC1 — Verifies: [FR1](#fr1), [FR6](#fr6), [FR7](#fr7), [NFR1](#nfr1)
@@ -247,7 +288,7 @@ Scenario: Recover release notes after a missed main-push publication
247288
And a retry creates no duplicate publication
248289
```
249290

250-
### AC2 — Verifies: [FR2](#fr2), [FR4](#fr4), [FR5](#fr5), [FR6](#fr6), [NFR2](#nfr2), [NFR3](#nfr3), [NFR4](#nfr4), [NFR5](#nfr5)
291+
### AC2 — Verifies: [FR2](#fr2), [FR4](#fr4), [FR5](#fr5), [FR6](#fr6), [FR8](#fr8), [NFR2](#nfr2), [NFR3](#nfr3), [NFR4](#nfr4), [NFR5](#nfr5), [NFR6](#nfr6)
251292

252293
```gherkin
253294
Scenario: Lifecycle runs preserve release ownership after cancellation

0 commit comments

Comments
 (0)