Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/docs/Capabilities/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ the same spec-and-design shape as any other capability.

| Section | Description |
| --- | --- |
| [Release Management](release-management/index.md) | How a source change becomes a versioned, immutable artifact, driven entirely on the GitHub platform. |
| [Release Management](release-management/index.md) | A generic framework for producing verified, immutable versioned release artifacts. |
| [Repository Governance](repository-governance/index.md) | How every repository in an organization is classified, protected, and continuously reconciled against the controls its classification declares. |
| [Dependency Updates](dependency-updates/index.md) | How a repository's pinned dependencies are kept current and secure through automated update pull requests. |
| [Merge Automation](merge-automation/index.md) | How a pull request's required status checks become the machine-readable signal that drives automated approval and merge — green merges, red holds, nothing bypasses the gate. |
Expand Down
108 changes: 59 additions & 49 deletions src/docs/Capabilities/release-management/design-publishing-targets.md
Original file line number Diff line number Diff line change
@@ -1,71 +1,81 @@
---
title: Publishing Targets
description: The contract every publishing destination documents, with GitHub Releases as the reference target.
title: Publishing Target Design
description: The generic adapter contract for publishing versioned release artifacts and records.
---

# Release Management — Publishing Targets
# Release Management — Publishing Target Design

A **publishing target** is any destination that accepts a versioned artifact and serves it to consumers. The [release pipeline](design.md#the-pipeline) publishes to targets through one contract, so the process is the same whether a repository has one destination or five.
A publishing target adapter receives a resolved version, a verified immutable
artifact, a frozen release-note snapshot, and provenance. The core pipeline does
not depend on target-specific behavior.

This page holds the contract and the targets that satisfy it. It is the boundary that lets a new destination be added without touching the [spec](spec.md).
## Adapter contract

## The contract
Each adapter declares the following conventions before the target enters a
required target set.

A target is described by six answers. They are the questions the release process needs answered in order to publish safely, and they are the questions that differ between destinations:

| Dimension | What it settles |
| Convention | Adapter responsibility |
| --- | --- |
| **Version scheme** | the exact string form a version takes, and what the target accepts as valid |
| **Prerelease representation** | how a prerelease is expressed, and how the target sorts it relative to stable versions |
| **Immutability** | whether a published version can be replaced, and what happens on a repeated publish of the same version |
| **Unpublish** | whether a version can be withdrawn, what withdrawal does to existing consumers, and whether the version number becomes reusable |
| **Floating tags** | whether the target supports mutable pointers such as `latest`, and how they are moved |
| **Release record** | where the durable, linkable evidence of the release lives |
| Version | Map the semantic version to the target's accepted version form. |
| Prerelease | Map and order prerelease versions below their related stable version. |
| Immutability | Reject replacement of an existing stable version with different bytes. |
| Withdrawal | Define how availability is removed while preserving version reservation. |
| Aliases | Declare whether `latest`, major, and minor aliases are supported. |
| Release record | Persist a durable record that joins source, artifact, version, and notes. |

An adapter reports one of three outcomes: unpublished, published with a
matching immutable identity, or conflicting. A matching existing publication is
a successful retry. A conflict fails the release and requires a new version.

A target MUST document all six before it is used. An undocumented dimension is a surprise waiting for the first failed release — most often around immutability, where publishing the same version twice is a success on one target and a hard error on another.
## Target transaction behavior

## Target summary
The framework stages every required adapter under the frozen release intent.
Adapters publish in a deterministic order. Completion is recorded only after all
required adapters report a matching immutable identity and release record.
There is no claim that independently operated targets provide a distributed
transaction; atomic completion is the framework's durable state rule.

| Target | Version scheme | Prerelease | Immutable | Unpublish | Floating tags | Release record |
| --- | --- | --- | --- | --- | --- | --- |
| **GitHub Releases** | `vMAJOR.MINOR.PATCH` git tag | SemVer suffix, flagged as prerelease | tag and assets are treated as immutable | delete is possible; treated as exceptional | yes — git tags | the Release itself |
| **PowerShell Gallery** | `MAJOR.MINOR.PATCH` module version | SemVer suffix on the module version | yes — a version is published once | unlist only; the version is never reusable | no | the gallery listing |
| **VS Code Marketplace** | `MAJOR.MINOR.PATCH` extension version | separate prerelease channel on the same version line | yes | unpublish removes the extension version | channel acts as the pointer | the marketplace listing |
| **NuGet** | `MAJOR.MINOR.PATCH` package version | SemVer suffix on the package version | yes | unlist only; the version is never reusable | no | the package listing |
| **Container registry** | `<image>:<version>` plus a content digest | SemVer suffix in the tag | the **digest** is immutable; the tag is not | tag or manifest deletion | yes — mutable tags | the digest |
Withdrawal is exceptional. It changes availability but never permits a stable
version identity to be reused. Prerelease cleanup uses the same rule and is
restricted to prerelease identities.

Two patterns run through the table and shape how consumers are told to pin:
## Alias behavior

- **Version numbers are single-use.** On every target above, a published version number is spent. Withdrawal removes availability, not the reservation. A fix is therefore always a new version — never a re-publish of the old one, which is the same conclusion the pipeline reaches from [build-once](design.md#the-pipeline).
- **Only content addresses are truly immutable.** Where a target offers both a name and a digest, the digest is the reference and the name is the convenience.
Aliases are optional controlled references, not release identities. If enabled,
the adapter supports only:

## GitHub Releases — the reference target
| Alias | Eligible destination |
| --- | --- |
| `latest` | Newest eligible stable version |
| Major | Newest eligible stable version in that major compatibility line |
| Minor | Newest eligible stable version in that minor compatibility line |

GitHub Releases is the reference implementation: every repository governed by this capability publishes there, and a repository with no external artifact publishes there *only*. A target-specific concern is described relative to this one.
The adapter updates aliases after immutable publication completes. Prereleases
never advance aliases. An alias update that would move backward, cross its
compatibility line, or point to an unverified artifact fails.

- **Version scheme.** A git tag `vMAJOR.MINOR.PATCH` on the release-branch commit. The tag is the artifact for Action, workflow, and source-distributed module repositories.
- **Prerelease.** The SemVer prerelease suffix, with the Release marked as a prerelease so it is excluded from *latest*.
- **Immutability.** The tag points at one commit and is not moved. Assets are uploaded once. A published version is never rewritten in place.
- **Unpublish.** A Release and its tag can be deleted, but doing so breaks consumers that resolved it, so it is reserved for a release that must not exist — a leaked secret, a legal removal — and the version number is not reused.
- **Floating tags.** Supported as additional git tags, subject to the [floating-tag rules](design.md#floating-tags).
- **Release record.** The Release itself: the version as its name, the release note as its body, and the immutable reference to whatever was published elsewhere.
## Release hosting adapter

Because every release produces a GitHub Release, it is also the **join point** across targets: a release published to a registry or marketplace records its reference there, so one link answers *what shipped, in what version, and where it went*.
A release-hosting adapter is appropriate when the target repository already
uses a public release-record feature. It publishes a version marker, attaches
or references the verified artifact, records the complete reviewed notes and
provenance, and marks prereleases so they are excluded from the current stable
release.

## Adding a target
For a GitHub Releases adapter, use the public platform documentation for the
target behavior: <https://docs.github.com/repositories/releasing-projects-on-github/about-releases>.
The adapter treats the version tag and release assets as immutable release
identities, records stable and prerelease state separately, and never reuses a
withdrawn version.

1. Document the six contract dimensions above, in the summary table.
2. Confirm the target's immutability and prerelease behaviour are compatible with [SemVer](https://semver.org/) ordering. Where the target's native convention differs, the mapping is stated rather than assumed.
3. Add the publish step. It receives the already-built artifact and the
already-resolved version, and it MUST be idempotent: publishing a version the
target already holds is a success only when its immutable identity matches the
artifact being retried. A different artifact at the same version is an error.
4. Include the target in the [all-or-nothing](design.md#publishing-targets) set, so a version cannot be present on some destinations and absent from others.
## Adding an adapter

The spec does not change. That is the purpose of the contract.
Adding an artifact or destination consists of implementing this contract,
declaring it in the target set, and proving it handles matching retries and
conflicting identities. The core resolution, build, verification, recovery,
and release-record behavior remains unchanged.

## Where this connects
## Related records

- [Spec](spec.md) — the requirements this design serves.
- [Design](design.md) — the pipeline that publishes to these targets.
- [Security](../../Coding-Standards/Security.md#supply-chain) — why consumers pin to immutable references.
- [Specification](spec.md)
- [Logical Core Design](design.md)
Loading
Loading