From 3e39fb2b0d32e9108b7ae133d97589db7be380fc Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 13 Sep 2026 10:15:38 +0200 Subject: [PATCH 01/10] Synchronize release management lifecycle documentation Align the consolidated release capability with durable intent, reservation, recovery, withdrawal, announcement, and consumer policy requirements. Add target-specific constraints and a focused moved-tag operator guide. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/docs/Capabilities/index.md | 2 +- .../accept-moved-release-tags.md | 100 ++ .../design-publishing-targets.md | 291 +++++- .../Capabilities/release-management/design.md | 901 +++++++++++------- .../Capabilities/release-management/index.md | 25 +- .../Capabilities/release-management/spec.md | 685 +++++++++++-- src/docs/Coding-Standards/GitHub-Actions.md | 6 + src/docs/Ways-of-Working/Automation-Labels.md | 17 +- src/zensical.toml | 1 + 9 files changed, 1529 insertions(+), 499 deletions(-) create mode 100644 src/docs/Capabilities/release-management/accept-moved-release-tags.md diff --git a/src/docs/Capabilities/index.md b/src/docs/Capabilities/index.md index b3b57f59..98f7b4b2 100644 --- a/src/docs/Capabilities/index.md +++ b/src/docs/Capabilities/index.md @@ -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) | Durable version resolution, publication, recovery, withdrawal, and consumer update policy for immutable releases. | | [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. | diff --git a/src/docs/Capabilities/release-management/accept-moved-release-tags.md b/src/docs/Capabilities/release-management/accept-moved-release-tags.md new file mode 100644 index 00000000..35b26c8b --- /dev/null +++ b/src/docs/Capabilities/release-management/accept-moved-release-tags.md @@ -0,0 +1,100 @@ +--- +title: Accept Moved Release Tags +description: Refresh an owned moving release alias locally and configure Git to keep it current. +--- + +# Accept moved release tags + +Use this guide when an MSX-owned producer intentionally publishes a moving Git +tag such as `v3` or `v3.4` and your local clone still resolves it to an older +release. + +Do not use this procedure for exact version tags such as `v3.4.2`. Exact version +tags are immutable. A moved exact tag is a producer integrity incident, not a +normal update. + +## Why an ordinary fetch can leave a stale tag + +Git protects existing local tags from being overwritten. An ordinary +`git fetch` can therefore update branches while silently leaving a moving tag at +its old object. Fetching all tags explicitly can instead report: + +```text +! [rejected] v3 -> v3 (would clobber existing tag) +``` + +Both outcomes leave the consumer on the previous release until it accepts the +producer-owned alias movement explicitly. + +## Refresh tags once + +Before this command, preserve or rename any local-only tags you need. Pruning +tags removes local tags that do not exist on the remote, and force permits the +remote's tag values to replace local values. + +```bash +git fetch --tags --force --prune --prune-tags +``` + +This refreshes moved aliases and removes tags deleted from the configured +remote. Review the fetch output before building or resolving a dependency. + +## Keep owned aliases current + +For a clone that should continuously accept the `origin` repository's controlled +tag aliases, inspect the current fetch refspec: + +```bash +git config --get-all remote.origin.fetch +``` + +If the output does not already contain `+refs/tags/*:refs/tags/*`, add it once: + +```bash +git config --add remote.origin.fetch '+refs/tags/*:refs/tags/*' +git config fetch.prune true +git config fetch.pruneTags true +``` + +The leading `+` allows the remote's tag namespace to update local tags +non-fast-forward. The prune settings remove local tag references no longer +present on the remote. Use this configuration only when `origin` is inside the +consumer's permitted trust boundary and the producer owns the moving aliases. + +After configuration, a normal fetch from `origin` keeps branches and tags +aligned: + +```bash +git fetch --prune origin +``` + +## Verify an alias + +Compare the local tag object with the remote tag object: + +```bash +git rev-parse refs/tags/v3 +git ls-remote --refs origin refs/tags/v3 +``` + +The first hash must equal the hash at the start of the second command's output. +Repeat with the actual alias, such as `v3.4`. + +Then resolve the exact release and immutable source before use: + +```bash +git show --no-patch --decorate refs/tags/v3 +``` + +A CI job can perform the same comparison and fail when the local alias is stale. +Consumers outside the producer's trust boundary must use an exact immutable +version or commit SHA instead of configuring automatic tag movement. + +## Where this connects + +- [Release Management design](design.md#current-version-discovery-and-aliases) — + when an owned alias can move. +- [Publishing Targets](design-publishing-targets.md#github-releases) — GitHub + exact tags, moving aliases, and release records. +- [GitHub Actions](../../Coding-Standards/GitHub-Actions.md#pin-actions-according-to-ownership) — + when an owned major tag is permitted. diff --git a/src/docs/Capabilities/release-management/design-publishing-targets.md b/src/docs/Capabilities/release-management/design-publishing-targets.md index 0b968120..908a745b 100644 --- a/src/docs/Capabilities/release-management/design-publishing-targets.md +++ b/src/docs/Capabilities/release-management/design-publishing-targets.md @@ -1,71 +1,278 @@ --- title: Publishing Targets -description: The contract every publishing destination documents, with GitHub Releases as the reference target. +description: Destination contracts for version mapping, prereleases, immutability, withdrawal, aliases, constraints, and release records. --- # Release Management — Publishing Targets -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** accepts a versioned artifact or release record and makes +it available to consumers. The [release lifecycle](design.md#build-verify-and-publish) +passes every target the same frozen version, retained artifact, note envelope, +and release-intent identity. -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). +Targets differ in native version syntax, prerelease channels, deletion, and +consumer resolution. This page makes those differences explicit so adding a +destination does not change the [release-management specification](spec.md). -## The contract +## Publishing-target contract -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: +Every target documents seven dimensions: | Dimension | What it settles | | --- | --- | -| **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 scheme** | The native coordinate and its one-to-one mapping from canonical SemVer. | +| **Prerelease representation** | How prerelease identity and ordering map to the target's syntax or channel. | +| **Immutability** | Which reference cannot change and what a repeated publication does. | +| **Withdrawal** | The strongest supported hide, unlist, yank, or delete operation and whether existing consumers retain access. | +| **Alias families** | Whether `latest`, major, or minor moving references can be represented and reconciled. | +| **Version constraints** | Whether consumers can express native ranges or need a producer-controlled alias. | +| **Release record** | Where the durable, linkable destination evidence is stored. | -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. +A target MUST answer all seven before it is enabled. It MUST also define: + +- how an idempotent retry verifies that an existing coordinate identifies the + recorded artifact; +- whether target-native state can be read back after publication; +- how canonical stable or prerelease state maps to target-native state; and +- which evidence proves publication or withdrawal. + +Distinct canonical releases MUST NOT map to one native coordinate. A collision +or stable/prerelease mismatch fails before publication. Target deletion never +frees a canonical version or prerelease identifier for reuse. ## Target summary -| 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** | `:` 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 | +| Target | Version scheme | Prerelease | Immutable reference | Withdrawal | Alias families | Native constraints | Release record | +| --- | --- | --- | --- | --- | --- | --- | --- | +| **GitHub Releases** | Exact `vMAJOR.MINOR.PATCH` or prerelease tag | SemVer suffix and native prerelease flag | Protected exact tag, source commit, and asset digest | Delete or mark unavailable; coordinate remains reserved | `latest`, major, minor as optional Git tags; native Latest separately | No range resolver | GitHub Release and durable release intent | +| **PowerShell Gallery** | `MAJOR.MINOR.PATCH` module version | SemVer suffix | Published module version | Unlist; downloads already held remain; version is not reusable | None | NuGet ranges through PSResourceGet; mapped manifest constraints | Gallery listing joined from GitHub Release | +| **NuGet** | `MAJOR.MINOR.PATCH` package version | SemVer suffix | Published package version and package hash | Unlist or deprecate; version is not reusable | None | NuGet version ranges | Package listing joined from GitHub Release | +| **VS Code Marketplace** | Marketplace-compatible extension version mapped from canonical SemVer | Separate prerelease channel and flag | Published extension version | Unpublish where permitted; version is not reusable | Native stable/prerelease channel selection, not release aliases | No consumer-selected SemVer range | Marketplace listing joined from GitHub Release | +| **Container registry** | Version tag plus content digest | SemVer suffix in exact tag | Manifest or image digest | Delete tag or manifest where permitted; reservation remains | `latest`, major, minor as optional tags | No range resolver | Registry digest joined from GitHub Release | + +Two rules apply to every row: + +- **Coordinates are single-use.** Withdrawal changes availability or + recommendation, not ownership. A corrected artifact always receives a new + version. +- **Completion is an outcome, not a claim of transactional publication.** One + target may expose content before another fails. Durable per-target progress + keeps the release incomplete until all required targets succeed, then lets a + retry resume safely. + +## GitHub Releases + +GitHub Releases is the reference target and the cross-target join point. Every +repository governed by this capability creates a GitHub Release; a repository +with no external artifact publishes there only. External target coordinates and +evidence are linked from the same release record. + +### GitHub version and prerelease mapping + +Stable versions use an exact tag: + +```text +vMAJOR.MINOR.PATCH +``` + +Prereleases preserve the canonical suffix: + +```text +vMAJOR.MINOR.PATCH-series.N +``` + +The Release's native prerelease flag MUST agree with the canonical version. +GitHub's native **Latest** selection is advertising state, not release authority. +It is updated only after durable completion and MUST NOT include prereleases or +withdrawn releases. + +### GitHub immutability + +An exact version tag identifies the fixed source revision. Assets are uploaded +from the retained artifact and verified by fingerprint. A repeated publish is +successful only when the existing tag, assets, and release record match the +frozen release intent. + +Repositories enable GitHub's immutable-release protection where the platform +supports it. Shared automation reconciles and verifies that setting rather than +assuming repository policy remained unchanged. Until setting reconciliation is +implemented, exact tags and assets remain immutable by MSX policy but lack the +full intended platform enforcement. + +### GitHub withdrawal + +GitHub permits a Release and tag to be deleted, but deletion does not erase +clones, caches, downloads, or durable lifecycle history. The withdrawal record +therefore remains authoritative and the version remains permanently reserved. +Deletion is used only where the approved withdrawal operation and repository +policy require it. + +Replaying a withdrawn intent does not recreate the Release or tag. Current +discovery and native Latest are reconciled to the greatest remaining eligible +completed stable release. + +### GitHub aliases and constraints + +Optional Git tags represent the closed `latest`, major, and minor alias families. +They are separate from exact version tags and can move only through +[alias reconciliation](design.md#current-version-discovery-and-aliases). +Consumers must explicitly accept moved owned tags; see +[Accept moved release tags](accept-moved-release-tags.md). + +Git references do not resolve SemVer range expressions. A major or minor +boundary therefore requires the corresponding producer alias. External +consumers use an exact commit SHA or another immutable fingerprint rather than a +moving tag. + +### GitHub release record + +The GitHub Release contains the contributor-authored note, publication envelope, +fixed source, and links to every destination coordinate. The durable release +intent remains the authority for lifecycle state, including partial publication, +retirement, withdrawal, alias reconciliation, and announcements. + +## PowerShell Gallery + +### PowerShell Gallery version and prerelease mapping + +The module manifest and gallery coordinate use canonical SemVer without the +leading `v`. A prerelease suffix is retained where the gallery and module +manifest permit it. Mapping validation runs before publication so a native +version cannot collide with another canonical release. + +### PowerShell Gallery immutability and withdrawal + +A published module version is immutable. Retrying succeeds only when the +existing listing and package hash identify the recorded artifact. The gallery +supports unlisting rather than reclaiming a version; existing consumers and +caches can still hold it, and the coordinate remains permanently reserved. + +### PowerShell Gallery aliases and constraints + +The gallery does not offer producer-controlled moving release aliases. +PSResourceGet accepts NuGet version ranges, and module manifests map supported +bounds into their native fields. Consumers follow +[PowerShell Version Constraints](../../Coding-Standards/PowerShell/Version-Constraints.md) +rather than placing a range-like string in a field that accepts only one +version. + +### PowerShell Gallery release record + +The gallery listing and package hash are recorded as destination evidence. The +GitHub Release links the gallery coordinate to the canonical source, notes, and +cross-target release intent. + +## NuGet + +### NuGet version and prerelease mapping + +The package version uses canonical SemVer without a leading `v`, including its +prerelease suffix. The adapter rejects any normalization or server behavior that +would make two canonical identifiers address one native package version. + +### NuGet immutability and withdrawal + +A published package version is immutable and single-use. An idempotent retry +checks the existing package hash. NuGet unlisting or deprecation changes +discovery and guidance but does not remove packages already restored, and the +version remains reserved. + +### NuGet aliases and constraints + +NuGet has no producer-controlled moving alias for package versions. Consumers +express supported movement with native +[NuGet version ranges](../../Coding-Standards/PowerShell/Version-Constraints.md). +An exact package version remains the immutable release coordinate. + +### NuGet release record + +The package listing, content hash, and withdrawal or deprecation state are +destination evidence. The GitHub Release is the human-readable join point. + +## VS Code Marketplace + +The [VS Code Extension Framework design](../vscode-extension-framework/design.md) +owns the detailed VSIX and marketplace behavior. + +### VS Code Marketplace version and prerelease mapping + +Stable extension versions map directly to the marketplace-compatible version in +the VSIX manifest. The marketplace represents prereleases through its separate +prerelease channel and `--pre-release` publication flag, including the +framework's odd-minor convention. The adapter records the canonical prerelease +and native extension version together and MUST guarantee a one-to-one mapping. + +### VS Code Marketplace immutability and withdrawal + +A published extension version is immutable and single-use. Marketplace +unpublication is applied where permitted, but cannot recall installed VSIX +files or make the canonical version reusable. + +### VS Code Marketplace aliases and constraints + +Stable and prerelease marketplace channels influence update discovery but are +not the release-management `latest`, major, or minor alias families. The +marketplace does not expose consumer-selected SemVer ranges for extension +updates. Consumers that need an exact immutable artifact use the VSIX attached +to the GitHub Release. + +### VS Code Marketplace release record + +The marketplace listing and native channel state are destination evidence. The +GitHub Release always contains the same VSIX and joins the canonical release to +optional Marketplace or Open VSX publication. + +## Container registries + +### Container registry version and prerelease mapping + +An exact canonical version maps to an image tag, while the published manifest or +image digest identifies immutable content. Prerelease suffixes remain part of +the exact version tag. -Two patterns run through the table and shape how consumers are told to pin: +### Container registry immutability and withdrawal -- **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. +Registry tags are mutable; digests are not. Publication records both and treats +the digest as artifact identity. An idempotent retry succeeds only when the +exact version tag resolves to the recorded digest. Deleting a tag or manifest +does not free the canonical release version or prove that cached content +disappeared. -## GitHub Releases — the reference target +### Container registry aliases and constraints -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. +Optional tags can implement the `latest`, major, and minor alias families. +Reconciliation updates each enabled tag to the digest of the greatest eligible +matching release. Container references do not evaluate SemVer ranges, so +consumers use a controlled producer alias inside the allowed trust boundary or +pin a digest. -- **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. +### Container registry release record -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*. +The registry digest and exact tag are destination evidence. The GitHub Release +links that digest to source, notes, verification, and lifecycle state. ## Adding a target -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. +1. Document all seven contract dimensions and add the target to the summary. +2. Define a total, collision-free mapping from canonical stable and prerelease + versions to native coordinates and flags. +3. Define the immutable identity and read-back check used by idempotent retry. +4. Define the strongest supported withdrawal behavior and its limitations. +5. State which, if any, alias families and native constraints consumers can use. +6. Define publication, withdrawal, and reconciliation evidence. +7. Add the adapter to the required destination set so durable completion and + phase-aware recovery include it. -The spec does not change. That is the purpose of the contract. +The target receives an already built and verified artifact. It does not choose a +version, rebuild content, rewrite the note snapshot, or mark the overall release +complete by itself. ## Where this connects -- [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. +- [Spec](spec.md) — the normative release and target requirements. +- [Design](design.md) — durable state, publication, recovery, discovery, and + consumer policy. +- [Accept moved release tags](accept-moved-release-tags.md) — local Git + configuration for consumers of owned aliases. +- [Security](../../Coding-Standards/Security.md#supply-chain) — immutable + references and supply-chain controls. diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index ff0a24ff..e08ce09c 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -1,397 +1,566 @@ --- title: Design -description: How release management is built — a shared reusable workflow that resolves an explicit or configured SemVer bump, builds once, and publishes. +description: Durable release intents, lifecycle transitions, recovery, withdrawal, aliases, announcements, and implementation coverage. --- # Release Management — Design -The behaviour in the [spec](spec.md) is delivered by a **shared reusable release -workflow**. A repository opts in with a short caller workflow and a small -`.github/release.config.yml`. The workflow supplies the shared mechanics; an -explicit label or an intentionally configured default supplies the release level. - -## Branching model - -A **release branch** is any branch configured as a release target, each with a -**release type** — `stable` or `prerelease`. - -- **Single branch (zero-config).** One release branch (the default branch) - produces stable releases. Prereleases are opt-in via a PR label. -- **Multi-branch.** `dev` (prerelease) collects PRs and publishes a prerelease - on every merge; `main` (stable) receives `dev`. Merging `dev → main` computes - the stable version from the **latest stable release** plus the merge PR's - resolved bump — the prerelease counter does not carry over. -- **One production authority.** At most one branch is `release-type: stable`; - every other release branch is `prerelease`. The single stable branch - (typically `main`) owns the production version — a prerelease branch can never - cut a stable release. -- **Bundled releases.** A **staging branch** collects feature PRs; merging it to - a release branch produces **exactly one** release for all bundled changes. +This page realizes the [release-management specification](spec.md) while keeping +repositories on one shared, GitHub-native release path. It describes the +**intended lifecycle** first, then identifies which parts the current shared +automation baseline implements. The specification remains normative even where +the implementation crosswalk records a gap. + +## Design principles + +1. **The release intent is authoritative.** Tags, releases, workflow runs, and + destination listings are observations that must agree with durable state. +2. **Resolve once, then resume.** A retry continues frozen work; it never turns + current repository metadata into a different release under the same identity. +3. **Build once.** Verification and every destination receive the same retained + bytes. +4. **Complete everywhere before advertising anywhere.** Current discovery, + stable aliases, and completion announcements follow durable completion. +5. **Roll forward.** Failure, retirement, and withdrawal preserve history and + reservations. Corrections use a new approved version. +6. **Consumers choose policy within a trust boundary.** Producers expose only + the controlled references required to implement that policy. + +## Release authority and interfaces {#branching-model} + +Exactly one configured stable line owns stable publication. A repository can +develop on several branches, but only a merge or approved manual request whose +fixed source is on that line can create a stable release. + +| Interface | Purpose | Release authority | +| --- | --- | --- | +| Pull-request decision check | Validates the owned release decision before merge. | None; it validates intent. | +| Merge to the stable line | Normal request for a release of the accumulated range. | Reviewed pull request and branch policy. | +| Direct push | Validates source and leaves the change pending. | None; it never inherits `DefaultBump`. | +| Manual release request | Releases an explicit stable-line source and accumulated range. | Explicit bump, complete notes, and approval for that range. | +| Retry request | Resumes one durable release intent. | The original frozen approval and intent. | +| Retirement request | Ends recovery of one incomplete intent. | Explicit maintainer authorization. | +| Withdrawal request | Makes one completed release ineligible. | Explicit maintainer authorization. | +| Announcement retry | Redelivers an unacknowledged completion message. | The completed release record. | + +The merge path remains the default because it keeps the compatibility decision, +consumer evidence, source review, and release-note source together. Manual +release exists for approved accumulated change, not as a way around review. + +The [Branching and Merging](../../Ways-of-Working/Branching-and-Merging.md) +standard owns standing development-to-stable promotion. Release management +starts when reviewed source reaches the configured stable line; it does not +duplicate the promotion process. + +## Durable release intent + +Resolve creates or loads one durable release intent before Build. Its stable +identity makes duplicate delivery and retries idempotent. + +| Field | Frozen or progressive | Purpose | +| --- | --- | --- | +| Intent identity and idempotency key | Frozen | Identifies one logical release independently of a workflow run. | +| Trigger and approval evidence | Frozen | Shows who or what authorized the release and included range. | +| Stable line, fixed source, and range baseline | Frozen | Defines the exact source history being released. | +| Aggregate decision and its source | Frozen | Records major, minor, patch, or skip and whether the fallback was used. | +| Canonical version and reservation state | Frozen after Resolve | Prevents later work from taking the same coordinate. | +| Release-note snapshot and provenance | Frozen | Preserves the reviewed contributor-authored account. | +| Required destinations and announcement routes | Frozen | Prevents configuration drift during recovery. | +| Lifecycle stage and failure detail | Progressive | Records the last successful boundary and actionable failure. | +| Artifact location and cryptographic fingerprint | Frozen after Build | Binds verification and publication to identical bytes. | +| Verification evidence | Progressive, append-only | Proves which retained artifact passed which checks. | +| Publication progress by destination | Progressive, append-only | Supports idempotent multi-target resume. | +| Alias reconciliation progress | Progressive, append-only | Records advertising after completion or withdrawal. | +| Announcement progress by destination | Progressive, append-only | Supports at-least-once delivery without republishing. | +| Retirement or withdrawal evidence | Append-only | Preserves a terminal operator decision without rewriting history. | + +The durable store can be implemented with any shared platform that provides +atomic writes, immutable history, and lookup by repository and intent. A +workflow run summary is useful evidence but is not sufficient storage: runs can +expire, retries use new run identifiers, and one run cannot safely coordinate +all later lifecycle operations. + +### Lifecycle states -```yaml -# .github/release.config.yml -release-branches: - - branch: main - release-type: stable - - branch: dev - release-type: prerelease +```mermaid +stateDiagram-v2 + [*] --> Resolved + Resolved --> Built + Built --> Verified + Verified --> Publishing + Publishing --> Publishing: Record one destination + Publishing --> Complete: All required destinations recorded + Resolved --> Resolved: Build attempt failed + Built --> Built: Verification or recovery failed + Verified --> Verified: Publication attempt failed + Publishing --> Publishing: Publication attempt failed + Resolved --> Superseded: No successful build or external visibility + Built --> Retired: Explicitly unrecoverable + Verified --> Retired: Explicitly unrecoverable + Publishing --> Retired: Explicitly unrecoverable + Complete --> Withdrawn: Explicit withdrawal ``` -## The pipeline +A failed attempt does not create a second logical state machine. It records the +failure against the last successful lifecycle boundary. `Superseded` applies +only to work that never produced a successful build and never exposed a release +coordinate. `Retired` preserves a permanently reserved coordinate for an +incomplete release. `Withdrawn` preserves completion while changing eligibility. -Every release runs the same four stages in order. The stage boundaries exist to -make **build-once** enforceable — each stage may only consume what the previous -stage produced. +## Resolve -```mermaid -flowchart LR - resolve["Resolve
version decided"] --> build["Build
artifact created once"] - build --> test["Test
same artifact validated"] - test --> publish["Publish
same artifact released"] +Resolve is the only stage that selects source, scope, decision, version, note +snapshot, destinations, and announcement routes. Every later stage consumes +those fields. + +### Identify the accumulated range + +For a new stable request: + +1. Find the source revision of the greatest completed stable release that is an + ancestor of the fixed source. If no completed stable release exists, use the + beginning of repository history. +2. Enumerate every source change after that baseline through the fixed source. +3. Associate reviewed pull requests and their owned release decisions where + possible. Keep skipped changes in the range. +4. Calculate the highest known increment in the range: major, then minor, then + patch. +5. Require one reviewed aggregate decision that is no lower than that minimum + and explicitly covers any skipped or direct change whose compatibility impact + is otherwise unknown. +6. Freeze the full range and account for every source revision in this or an + earlier durable release intent. + +The current merged pull request normally supplies the aggregate approval. If +unreviewed direct changes make that approval incomplete, Resolve stops and +requires a manual release request covering the range. `DefaultBump` applies only +when the current associated pull request has no explicit decision and the range +otherwise has complete reviewed evidence. + +An unbuilt, unexposed pending request can be coalesced into a later approved +range and marked `Superseded`. A built or externally visible request cannot be +coalesced; it must complete or be retired before later work advances. + +### Resolve the owned instruction set + +Owned labels are the contributor-facing vocabulary. Their exact definitions and +conflicts live in [Automation Labels](../../Ways-of-Working/Automation-Labels.md). + +| Marker | Resolve effect | +| --- | --- | +| `release:major` | Selects a major aggregate increment. | +| `release:minor` | Selects a minor aggregate increment. | +| `release:patch` | Selects a patch aggregate increment. | +| `release:skip` | Validates and accumulates the change without immediate publication. | +| `release:pre-release` | Publishes an ordinary prerelease series for the next stable candidate. | +| `release:rc` | Publishes the next constant-identifier release candidate for the next stable candidate. | +| `release:announce` | Enables configured completion announcements for the frozen request. | + +Exactly one of major, minor, patch, or skip can own the decision. An ordinary +prerelease or RC is a modifier on a major, minor, or patch request; neither can +modify skip, and the two prerelease modes conflict with one another. +`release:announce` does not select a version or authorize publication. + +The required pull-request check recomputes when source, owned markers, or +`.github/release.config.yml` changes. It publishes one named required result and +fails closed for missing, conflicting, invalid, stale, or unsupported input. + +### Required pre-merge decision check {#required-pre-merge-decision-check} + +The decision check is the release resolver in validation mode. It validates the +current pull-request decision, configured fallback, modifier conflicts, source +scope, and whether the known accumulated range can be approved by this request. +It never publishes or reserves a version. Branch policy requires its exact +check name, so absent and stale results block merge as well as explicit failure. + +### Resolve the stable version {#version-computation} + +Version resolution starts from `0.0.0` when there is no stable history. Otherwise +it finds the greatest SemVer among: + +- completed stable releases; and +- permanently reserved stable versions from built, visible, retired, or + withdrawn intents. + +Resolve applies the aggregate increment to that baseline. For example, a first +patch release is `0.0.1`, a first minor release is `0.1.0`, and a deliberate +first stable major release is `1.0.0`. + +The resolved version is persisted as a provisional reservation before Build. +The reservation becomes permanent after the first successful build or any +external visibility. This separates safe coalescing of untouched work from the +non-negotiable rule that one visible or built coordinate always means one source +and one artifact. + +### Resolve prereleases and release candidates + +A prerelease applies its aggregate increment to the stable baseline and permanent +stable reservations, then appends a native identifier that sorts before the +normal version: + +```text +-. ``` -| Stage | Produces | Invariant | -| --- | --- | --- | -| **Resolve** | the version | the version is known before anything is built, so it can be baked in | -| **Build** | the artifact | the artifact is created exactly **once**, carrying its version | -| **Test** | a verdict | validation runs against the built artifact, not a rebuild of its source | -| **Publish** | released versions | the artifact is transferred unchanged to every target | - -Two consequences follow, and they are the point of the model: - -- **The version is identity, not metadata.** Because Resolve precedes Build, the - version is embedded in the artifact rather than attached to it. A manifest - version, an image label, and the tag agree because they came from one decision. -- **Recovery preserves artifact identity.** Retrying validation or publication of - an unchanged, already-built artifact reuses that artifact and its resolved - version. A correction that changes the output is a new release: it resolves a - new version and builds new bytes. An artifact is never patched, re-tagged, or - rebuilt under an existing version — that would publish something other than what - was tested. - -## Version computation - -For PR-driven releases, the shared resolver reads the owned labels and optional -`DefaultBump` in `.github/release.config.yml`. The setting accepts `patch`, -`minor`, or `major`; omitting it does not supply a level. For example, this -configuration explicitly chooses patch releases when no bump label is provided: +An ordinary prerelease uses the shared workflow's validated series identifier. +A dedicated release candidate always uses `rc`: -```yaml -# .github/release.config.yml -DefaultBump: patch +```text +2.5.0-rc.1 +2.5.0-rc.2 +2.5.0-rc.3 ``` -| Label | Meaning | Valid combination | -| --- | --- | --- | -| `release:patch` | Resolve the next patch version, overriding the configured default. | Alone or with `release:pre-release`. | -| `release:minor` | Resolve the next minor version, overriding the configured default. | Alone or with `release:pre-release`. | -| `release:major` | Resolve the next major version, overriding the configured default. | Alone or with `release:pre-release`. | -| `release:pre-release` | Publish the open pull request as a prerelease using the resolved bump. | With one explicit bump or a configured default; never with `release:skip`. | -| `release:skip` | Run validation without resolving or publishing a version. | Alone. | - -Resolve the decision in this order: - -1. Validate `DefaultBump` when present and reject conflicting owned labels. - An invalid setting is an error even when an explicit label is supplied. - Bare and unrelated labels do not participate. -2. Honor a valid `release:skip` as the explicit no-release decision and stop bump - resolution. -3. Use the single owned bump label when present; otherwise use the configured - `DefaultBump`. Record the chosen level and whether the label or setting - supplied it. -4. If neither supplies a level, fail with a missing-decision error that tells the - author to select a bump, configure the default, or choose `release:skip`. - There is no built-in patch fallback. Prerelease mode does not supply a bump. - -| PR input | `DefaultBump` | Decision-check result | +The counter is the next unreserved numeric value for that core and series. It is +stored unpadded so SemVer numeric ordering remains correct. The normal core +`2.5.0` is not consumed by any prerelease, but every published prerelease +identifier remains bound to its original content even after cleanup. + +Each publishing target validates its native prerelease flag against the +canonical version. A stable canonical version cannot be sent through a native +prerelease channel, and a canonical prerelease cannot be represented as stable. + +## Build, Verify, and Publish + +The lifecycle retains the familiar four-stage pipeline: + +```text +Resolve -> Build -> Verify -> Publish +``` + +`Verify` is the specification's target-neutral name for the existing Test stage. +Workflow job names can continue to use `Test` while the stage verifies the +frozen artifact. + +### Build + +Build receives the fixed source and resolved version. It produces one artifact, +stores it in retained release storage, calculates a cryptographic fingerprint, +and records both before any verification or publication. + +Build does not discover a newer branch tip, query labels again, edit the note +snapshot, or publish. If Build fails before a complete artifact is recorded, it +can retry with the frozen inputs. Once Build succeeds, no later phase can rebuild +or mutate the artifact under that version. + +### Verify + +Verify downloads the retained artifact by intent and confirms its fingerprint +before testing it. Source-level checks can run earlier, but release evidence must +show that the artifact intended for publication passed the required target, +integration, signing, and policy checks. + +Successful verification records the fingerprint, check identity, result, and +evidence location. A retry can reuse valid frozen evidence or repeat a +non-mutating check against the same bytes. + +### Publish + +Publish creates the destination-native artifact and release record from the +retained bytes and frozen note envelope. Every destination follows +[Publishing Targets](design-publishing-targets.md). + +For each required destination, Publish: + +1. Looks for a durable successful publication record. +2. If one exists, verifies that the destination coordinate still identifies the + recorded fingerprint and reuses it. +3. If none exists, verifies that the coordinate is free or already identifies + the same artifact. +4. Publishes the retained bytes and canonical metadata. +5. Reads the destination back where supported. +6. Records the coordinate, fingerprint, release-record location, and evidence. + +The release becomes `Complete` only when every frozen required destination has a +successful durable record. Native Latest state, moving aliases, and +announcements run after that transition. A partial release remains +`Publishing`, even if one destination makes its coordinate externally visible. + +## Phase-aware recovery + +A retry names the release-intent identity. The system loads durable state and +chooses the first unfinished boundary: + +| Recorded boundary | Retry action | +| --- | --- | +| `Resolved` with no successful artifact | Run Build again from frozen inputs. | +| `Built` | Restore the retained artifact, verify its fingerprint, and run Verify. | +| `Verified` | Restore the retained artifact and begin Publish. | +| `Publishing` | Verify recorded destinations and publish only unfinished ones. | +| `Complete` | Return the completed outcome; reconcile only independently retryable advertising work. | +| `Retired` | Return the retirement outcome without rebuilding or publishing. | +| `Withdrawn` | Return the withdrawal outcome without recreating or announcing the release. | + +Recovery never asks current labels, configuration, branch head, tag order, or +edited pull-request text to redefine frozen intent. Configuration can gain a new +destination only for a new release. It cannot silently broaden an in-flight +release. + +If retained storage is missing, the operator can restore a copy only when its +cryptographic fingerprint matches the recorded successful build. Otherwise the +intent must remain failed or be explicitly retired. Rebuilding similar source is +not proof of identical bytes and is forbidden under the reserved version. + +## Retirement and withdrawal + +Retirement and withdrawal solve different problems: + +| Operation | Applies to | Effect | | --- | --- | --- | -| `release:major` | `patch` or absent | Pass: explicit major overrides the default. | -| No owned release labels | `minor` | Pass: configured minor; record the setting as the source. | -| No release decision | Absent | Fail: missing decision; merge blocked. | -| `release:skip` alone | Valid or absent | Pass: no release; no bump is required. | -| `release:pre-release` alone | `patch` | Pass: configured patch in prerelease mode. | -| `release:pre-release` alone | Absent | Fail: mode does not supply a bump; merge blocked. | -| Multiple bump labels, or skip with another owned release label | Any | Fail: conflicting decisions; no fallback. | -| Any | Invalid value | Fail: invalid configuration; no fallback. | - -- **First release** starts from a baseline (`v0.1.0` or `v1.0.0`). Pre-`1.0.0` - breaking changes are `release:minor` per [SemVer §4](https://semver.org/#spec-item-4); - `release:major` is never auto-detected pre-`1.0.0`. -- The tag is created on the commit now at the head of the release branch — - squash, merge-commit, and rebase strategies alike. - -### Required pre-merge decision check - -PR CI runs the resolver read-only against the candidate release settings and -current owned labels, without creating tags, releases, or published artifacts. -An existing version-resolution check may own this validation; do not duplicate -the resolver. The check reports the effective decision and its source, not a -promised final stable version. - -The validator runs for every PR targeting a release branch, including changes -that will not publish. It re-runs when source, release labels, or release settings -change, so a stale result is not evidence for different inputs. Missing, -invalid, or conflicting decisions produce a failed check with an actionable -error. A valid skip reports success with a no-release result; path filters do -not skip the validator. - -Configure the check's exact name as required in the protected branch's ruleset -or branch protection, following [Merge Automation](../merge-automation/spec.md). -Manual merge and auto-merge both wait for it: failure, pending execution, and -absence block merge. A warning or an advisory, unrequired check is insufficient. -Human review still assesses whether the resolved level matches the audience -impact; CI validates the deterministic decision contract. - -The release run validates its actual inputs again before Resolve and Build. -Pre-merge validation does not replace release-time validation, but a known -missing decision is never deferred until after merge. - -### Optional ad hoc releases - -The standard release path is a pull request with a validated decision merged into a release -branch. `workflow_dispatch` is an optional extension, not part of the minimum -implementation. An implementation SHOULD omit it unless its product has a real -need to release already-reviewed content outside the merge flow. - -Where an ad hoc path exists, it requires an explicit bump, source ref, complete -release-note context meeting the [release evidence contract](#release-notes), and -reason. It resolves the source ref to an immutable commit and enters -the same Resolve → Build → Test → Publish pipeline as a merged pull request. It -does not infer a bump, bypass validation, rebuild an existing version, or make a -direct push into a release interface. - -Do not create an empty pull request to manufacture a release. It contains no -artifact-affecting change and makes the review trail imply a change that did not -happen. Retrying failed validation or publication is not an ad hoc release -either: rerun the existing release with the same artifact and version under the -[recovery rule](#the-pipeline). - -## Prereleases - -- **Branch-level** — a prerelease-type branch publishes on every push, using the - branch name as the identifier: `v1.3.0-dev.1`, `v1.3.0-dev.2`, … -- **PR-level** — `release:pre-release` with a resolved explicit or configured bump publishes - `v-.`: `base` is the next version from that bump, - `identifier` is the normalized branch name, and `counter` - auto-increments per push. -- Artifact-specific conventions replace the SemVer suffix where they exist - (`-alpha.N` for npm, `.devN` for Python). Release candidates use `-rc.N`, - auto-incrementing. -- **Cleanup** deletes prerelease tags, releases, and artifacts after the PR - closes (configurable); stable releases are never touched. - -## Path filtering - -`.github/release.config.yml` declares `release-paths` as ordered include/exclude -globs (excludes win). The workflow **always runs** so validation executes on -every merge; only the release step is skipped when no artifact-affecting path -changed. - -Derive these paths from the delivered product and its -[audience-facing contracts](../../Ways-of-Working/PR-Format.md#detecting-the-change-type), -not directory names alone. Include callable workflows and build configuration -that changes delivered runtime requirements or behavior. Do not retain an -exclusion that overrides an included consumer interface or artifact input. - -This example represents a workflow producer with a public `reusable.yml` entry -point and its local implementation; each producer lists its own artifact inputs. +| Supersede | Resolved, unbuilt, unexposed intent | Coalesces untouched work into a later reviewed range. | +| Retire | Built or externally visible incomplete intent | Stops recovery, preserves failure and reservation, and leaves the release incomplete. | +| Withdraw | Completed release | Makes the release ineligible while preserving completion history and reservation. | + +An authorized withdrawal writes an append-only withdrawal event, requests the +strongest target-native hide, unlist, yank, or delete operation, and then +reconciles discovery and aliases. Target limitations are recorded rather than +represented as stronger guarantees. For example, a target may permit unlisting +but not deletion of already downloaded content. + +Withdrawal does not delete the release intent, free the version, alter the +artifact, rewrite notes, or imply that consumers already holding the artifact no +longer have it. A fixed release uses a new reviewed version. + +## Current-version discovery and aliases + +Durable completed state is the authority for current-version discovery. The +algorithm: + +1. Select stable intents whose required destinations completed. +2. Exclude retired or withdrawn releases and any release that policy marks + ineligible. +3. Order canonical versions by SemVer precedence. +4. Return the greatest match or an explicit no-current-version result. + +An API, tag, or release lookup failure is an error. It is never converted into a +successful empty result. + +Aliases are optional advertising references layered on top of discovery. The +closed families are: + +- `latest`, one alias for the greatest eligible completed stable version; +- major, one alias such as `v3` for the greatest eligible `3.x.y`; and +- minor, one alias such as `v3.4` for the greatest eligible `3.4.x`. + +Each family defaults off and is enabled independently. Completion and withdrawal +run the same reconciliation algorithm. A normal completion never moves an alias +backward. Withdrawal can move one backward to the greatest remaining eligible +match, and removes it when no match remains. Prereleases never update stable +aliases. + +Moving Git tags require explicit consumer-side fetch behavior. Operators who +consume an owned alias follow [Accept moved release tags](accept-moved-release-tags.md). + +## Completion announcements + +Announcements are a post-completion delivery channel, not part of artifact +publication. Resolve freezes whether announcements are enabled and which +configured destinations apply. Complete freezes the canonical message context: +version, immutable release link, summary, and release-intent identity. + +Each announcement destination has its own delivery record and idempotency key. +The sender records attempts and acknowledgements. If acknowledgement is missing, +it may resend the same logical message; receivers therefore observe +at-least-once delivery and should deduplicate by release identity. + +Announcement failure does not roll back a complete release and does not permit a +new version, build, or publication. It remains an independently retryable +post-completion task. + +## Release notes and evidence {#release-notes} + +Release notes preserve contributor-authored pull-request content rather than +reducing it to a generated commit list. The frozen note snapshot follows +[PR Format](../../Ways-of-Working/PR-Format.md) and covers every reviewed pull +request in the accumulated range, including skipped changes. + +Manual requests supply equivalent reviewed context for direct or otherwise +unaccounted changes. Resolve fails if a source revision in the range has neither +reviewed note context nor an explicit evidence-gap record approved with the +manual request. + +The publication envelope augments, but does not rewrite, the authored note: + +- canonical and destination-native versions; +- previous completed stable baseline; +- fixed source and included range; +- aggregate decision, decision source, and fallback use; +- artifact fingerprint and verification evidence; +- destination coordinates and release-record links; +- note snapshot provenance; and +- completion, retirement, withdrawal, alias, and announcement events. + +A later explanatory correction is another append-only metadata event containing +before and after text, reason, actor, time, and source evidence. It cannot change +the version, source, artifact, decision, or behavior attributed to the release. + +## Release scope + +`Paths` is evaluated over the complete accumulated range. With no explicit +configuration, every path is release-affecting. A repository can narrow scope +only after accounting for direct and transitive artifact inputs. ```yaml -release-paths: - - ".github/workflows/reusable.yml" # public caller contract - - ".github/actions/**" # this workflow's local implementation - - "src/**" +Paths: + - src/** + - module/** + - build/** ``` -## Release notes - -The GitHub Release **name** is the resolved version. Its **body** preserves the -release-bound PR title and complete description, using -[PR Format](../../Ways-of-Working/PR-Format.md#description-structure) as the -authoring contract. Summary, user-facing changes, adoption, release impact, -consumer change records, template evidence, and both ending details blocks stay -intact. There is no parallel JSON/YAML contract and no extraction of only the -user-facing headings. - -### Bind the note to the released source - -1. **Resolve the evidence with the version.** Identify the release-bound PR or - ad hoc context and the immutable source to build. Resolve the version base - and the source comparison baseline; confirm that the consumer record - describes that delta. Capture the applicable title and complete body together - with the PR URL or context reference, source identity, and snapshot time. - Retain that snapshot as release evidence. -2. **Keep identity separate from authored prose.** Resolve the actual publication - coordinates through the existing version pipeline, not a number assigned by - the PR author. Carry them and the snapshot through Build and Test with the - same artifact. An authored statement that coordinates resolve at publication - is not replaced with a manual prediction. -3. **Publish the complete record.** Preserve the captured title and body - unchanged, with a clearly separated publication envelope. Compare the - published authored portion with the snapshot; truncation, summarization, - missing evidence, or a source mismatch is a publication failure, not success. - Hand the same complete record to every note-bearing publishing target and - [Downstream Release Propagation](../downstream-release-propagation/design.md). - -The envelope records these resolved facts without becoming a second authored -release note: - -| Field | Value | -| --- | --- | -| Release identity | Actual version, stable/prerelease mode, tag, immutable source commit, and artifact identity or digest where applicable. | -| Effective decision | The resolved semantic effect and its owned-label or configured-policy source; [version computation](#version-computation) remains authoritative. | -| Version base | The actual version/source used to compute the version, or the explicit initial versioning baseline. | -| Change baseline | The release and immutable source against which the consumer delta is described, plus a source comparison link; explicitly no predecessor for an initial release. | -| Note provenance | Release-bound PR URL or ad hoc context, its associated source identity, and snapshot time. The retained authored snapshot is the content reference, not the PR's later mutable body. | - -Version base and change baseline can differ, particularly for prereleases and -bundled promotion. Recording both avoids presenting a versioning calculation as -proof of the code a consumer crosses. The target template identity and -compatibility evidence come from the authored record; a publisher does not -substitute the latest template or infer historical compatibility from current -documentation. - -### Release-bound records - -| Publication path | Authored record | -| --- | --- | -| Single merged PR | That PR's complete title and description, reconciled with the resolved source comparison. | -| Bundled release | The release-bound integration PR covers every bundled delta from the declared change baseline, not just the most recent feature PR. It links the contributing work as supporting evidence. | -| Optional ad hoc dispatch | Complete reviewed release-note context with the same adoption, consumer-change, template, and release-impact evidence. Record the dispatch source and reason; do not create or imply an empty PR. | -| Prerelease | The PR or integration record appropriate to that published source, captured for that release. Later edits to the final PR do not overwrite the prerelease snapshot or attribute unreleased behavior to it. | - -If the relationship between a record and its source cannot be established, -stop the affected publication and register the evidence gap. The process does -not substitute the newest note, guess a baseline, or treat an empty adoption -section as a no-action result. - -### Correct published metadata without changing history - -A note correction is an audited metadata operation, not another release run: - -1. Establish the release-to-source and PR relationship from immutable source - comparisons and contemporary evidence. Preserve source-specific prerelease - records rather than copying a later final-PR body over them. -2. Capture original and proposed content, reason, evidence links, actor, and - time in a linked audit issue or durable attached artifact. Coordinate active - PR ownership; do not add closing keywords to audit prose. -3. Re-read each target before writing. If another edit changed it, reconcile the - correction rather than overwriting that edit. Apply only the established - PR/release metadata changes and retain their correspondence. -4. Re-read the result and confirm that the correction changes no artifact, - asset, tag, SHA, release decision, or behavior attributed to an old version. - Record unverifiable facts as unresolved gaps instead of inventing actions. - -The audit belongs in GitHub issues and release/PR metadata, not a product -documentation changelog. A correction to bytes still follows the -[new-artifact recovery rule](#the-pipeline); editing notes never bypasses it. - -## Release output - -1. A git tag `vX.Y.Z` on the release-branch commit — always. -2. The published artifact where one lives outside git — a container image - (`:` and `@`), a package in its registry. For Action, - workflow, and module artifacts the tag itself **is** the artifact. -3. A GitHub Release whose name is the version, carrying the note and the - publication envelope, including the tag's resolved source commit and the - immutable artifact identity. - -## Publishing targets - -Publish is the only stage that knows where an artifact goes, and it reaches every -destination through one abstraction: a **publishing target**. A target is any -destination that accepts a versioned artifact and serves it to consumers — the -GitHub Release itself, a package registry, an extension marketplace, a container -registry. - -The release process is written against the target *contract*, never against a -specific target. Each target documents how it answers six questions — version -scheme, prerelease representation and sort order, immutability, unpublish -behaviour, floating-tag support, and where its release record lives — in -[Publishing Targets](design-publishing-targets.md). Adding a destination means -writing that contract and a publish step; it does not change Resolve, Build, -Test, or the spec. - -Where a repository has more than one target, publishing is **all-or-nothing** for -a version: - -- Targets are attempted in a defined order, and each is idempotent — publishing - an already-published version is a success only when it identifies the same - immutable artifact. A version collision with different bytes is an error, so a - re-run completes the set rather than accepting changed output. -- A target that rejects the version fails the release. The version is not - advertised as available until every target holds it. -- A partial publication resumes Publish for the **same** artifact and the same - version. It never resolves a new version to work around a single failed target, - because the targets that already succeeded hold that immutable version. - -## Floating tags - -Floating tags are optional, mutable pointers published alongside the immutable -version tag, for consumers that want to track a line rather than a point: - -| Tag | Points at | Moves when | +Validation still runs when no path is eligible, when the decision is skip, or +when a direct push cannot publish. No universal exclusion exists for docs, +tests, or workflows: a documentation site ships docs, test fixtures can be +packaged, and workflow files can define release behavior. + +## Consumer update policies + +The consumer resolves one of five policies: + +| Policy | Producer mechanism | Durable consumer reference | | --- | --- | --- | -| `latest` | the newest stable version | any stable release | -| `vMAJOR` | the newest stable version in that major | a stable release within that major | -| `vMAJOR.MINOR` | the newest stable patch in that minor | a stable patch within that minor | - -Three rules keep them safe: - -- **Prereleases never move a floating tag.** Only a stable release advances one, - so a floating tag never points at something not promoted for adoption. -- **A floating tag never moves backwards.** It only advances, so a consumer - following it never silently downgrades. -- **Only controlled release automation moves a floating tag.** Humans and ad hoc - workflows do not create or repoint one. The automation publishes the immutable - version first, then moves only the aliases that release is eligible to advance. -- **A major tag stays inside its compatibility line.** `vMAJOR` advances only - for compatible stable patch and minor releases in that major. A breaking - release creates the next major tag and leaves the previous one in place. -- **Floating tags are controlled references only for owned automation.** An - organization- or initiative-owned Action or reusable workflow may be consumed - through its controlled `vMAJOR` tag. External automation and anything requiring - byte-for-byte reproducibility pins to the immutable version, digest, or SHA - ([supply chain](../../Coding-Standards/Security.md#supply-chain)). - -## Serialised releases - -Release runs for the same ref are **serialised** and **queue rather than -cancel** — an in-flight release is never aborted mid-write, since it may be -part-way through creating a tag or pushing an artifact. The shared workflow -declares a concurrency group keyed by workflow and ref, with -`cancel-in-progress` disabled: +| `latest` | Discover the greatest eligible completed stable release. | The discovered immutable version or fingerprint required by trust policy. | +| `lock-major-boundary` | Producer major alias, such as `v3`. | Moving alias only inside the allowed trust boundary. | +| `lock-minor-boundary` | Producer minor alias, such as `v3.4`. | Moving alias only inside the allowed trust boundary. | +| `lock-specific-version` | Exact immutable version. | Exact version. | +| `lock-immutable-fingerprint` | Content digest, commit SHA, or equivalent. | Immutable fingerprint. | + +A requested boundary is unsupported when the producer does not publish the +matching alias; it is never widened silently. When a consumer field accepts only +one opaque reference, a text such as `>=3,<4` is not a range expression. The +producer carries the bound through its controlled alias. + +Moving references are allowed only for producers inside the consumer's declared +trust boundary. Another team is external even when it belongs to the same +company. External dependencies use the strongest immutable reference available. +The [Dependencies standard](../../Coding-Standards/Dependencies.md) owns the +broader pinning and update trade-off. + +Before `1.0.0`, SemVer permits a breaking change in each minor version. A major +alias such as `v0` therefore crosses potentially breaking `0.y.z` releases. A +consumer that wants patch-only movement before `1.0.0` uses a minor alias such +as `v0.4`, not `v0`. + +## Ordering, idempotency, and reconciliation + +Workflow concurrency groups queue same-line work and never cancel an in-flight +publication. Durable reconciliation provides the stronger guarantee that source +order survives missed events, worker replacement, manual retries, and finite +execution queues. + +For each stable line, the reconciler finds source revisions not yet accounted +for by a complete, retired, or superseding intent. It processes the oldest +unsettled range first. Duplicate triggers use an idempotency key derived from the +repository, stable line, fixed source, and request kind, and return the existing +intent rather than creating another. + +This ordering prevents a later fast run from taking a version or release range +that belongs to earlier unresolved work. + +## Configuration + +Repositories keep the existing MSX configuration file: + +```text +.github/release.config.yml +``` + +The current baseline surface remains: ```yaml -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: false +ReleaseBranches: + - main +DefaultBump: patch +Paths: + - src/** + - module/** ``` -Serialisation is provided once by the reusable workflow so every repository -inherits it; the mechanism is the -[GitHub Actions standard](../../Coding-Standards/GitHub-Actions.md#concurrency). -The single-stable-branch rule above is what keeps the production version under -one authority — the stable branch is the only ref that ever cuts a production -release, and its runs are serialised like any other. +- `ReleaseBranches` identifies branches evaluated by the existing schema. The + intended lifecycle permits exactly one value to authorize stable publication; + any additional branch can validate or publish prereleases only. +- `DefaultBump` accepts only `major`, `minor`, or `patch` and applies only to an + associated reviewed pull request. +- `Paths` declares artifact-affecting scope. Omission means every path. + +The intended configuration surface additionally needs independently disabled +`latest`, major, and minor aliases; publishing destinations; announcement +destinations; retained-artifact policy; and destination-specific native mapping. +Those fields are not documented as YAML keys until the shared implementation +defines and validates them. Unknown fields and values fail closed; repositories +must not invent local release schema. + +Repositories choose policy. Shared automation owns resolution, durable state, +SemVer calculation, artifact handoff, retry rules, target adapters, discovery, +alias reconciliation, and evidence format. + +## Intended and implemented behavior + +The lifecycle above is the target design. The implementation lives in shared +release automation rather than this documentation repository, and each +repository remains governed by the workflow revision it invokes. The table +records the audited shared baseline that this capability documentation +synchronizes against; an **intended** row MUST NOT be treated as available until +the invoked workflow documents and exposes it. + +| Surface | Baseline coverage | Intended behavior still required | +| --- | --- | --- | +| Pull-request release decision | Implemented for explicit major, minor, patch, skip, ordinary prerelease, and `DefaultBump`. | Aggregate the full unreleased range and preserve the frozen decision source. | +| Direct pushes | Validation and push-triggered processing exist. | Prevent fallback-based publication and require an approved manual aggregate request. | +| Manual stable releases | Not implemented as a release-creation path. | Fixed stable-line source, explicit aggregate increment, complete notes, and range approval. | +| Dedicated RC mode | Not implemented. | `release:rc`, constant `rc` identifier, monotonic counters, and conflict with `release:pre-release`. | +| Durable release intent | Workflow-run evidence exists; resolution is based on current pull-request metadata and tags. | Durable frozen inputs, lifecycle state, idempotency, and permanent version reservations. | +| Build-once recovery | A run can hand one build artifact to later jobs. | Retain successful bytes across runs, verify the fingerprint, and resume by recorded phase without rebuilding. | +| Multi-target completion | Publication can target configured destinations. | Durable per-destination progress and completion only after every required target succeeds. | +| Current-version discovery | Version calculation is tag-oriented. | Select the greatest eligible completed stable intent and exclude incomplete or withdrawn releases. | +| Moving aliases | Existing shared flows can update configured aliases. | Closed opt-in families, monotonic completion updates, and withdrawal-aware reselection or removal. | +| Announcements | Durable announcement delivery is not implemented. | Frozen message context, per-destination journal, idempotency, and at-least-once retry after completion. | +| Retirement and withdrawal | End-to-end lifecycle operations are not implemented. | Preserve failure or completion history, permanent reservations, target-native withdrawal evidence, and replay-safe terminal outcomes. | +| Immutable GitHub Releases | Exact version tags are treated as immutable by policy. | Reconcile and verify the repository's immutable-release setting where GitHub supports it. | +| Published-note correction | Release notes and evidence are published. | Append-only correction records with source evidence and unchanged release identity. | -## Configuration surface +Until the durable lifecycle is implemented, an operator MUST NOT work around a +partial release by rerunning against changed metadata or rebuilding under the +same exposed version. Stop, preserve evidence, and roll forward with a newly +approved version when byte identity cannot be proven. -| Surface | Where | -| --- | --- | -| Release branches + type | `.github/release.config.yml` | -| Optional default bump | `DefaultBump` in `.github/release.config.yml` | -| Explicit bump / prerelease / skip | `release:` PR label | -| Pre-merge decision validation | named PR check required by the branch ruleset or protection | -| Optional ad hoc release | `workflow_dispatch` inputs | -| Path filter | `.github/release.config.yml` | -| Prerelease cleanup toggle | release config / workflow input | -| Publishing targets | reusable-workflow input + GitHub environment; see [Publishing Targets](design-publishing-targets.md) | +## Design decisions + +### The durable intent, not a tag, is the release authority + +Tags can be missing, moved when explicitly used as aliases, or present before all +destinations complete. A durable intent can state which artifact, source, +approval, and destinations the tag is expected to represent and can distinguish +partial publication from completion. + +### Manual release uses the same pipeline + +A separate manual pipeline would create a second version algorithm and weaker +evidence path. Manual requests therefore change only the trigger and approval +source; they still Resolve, Build, Verify, and Publish one retained artifact. + +### Announcements follow completion + +Treating a chat or webhook message as a publishing destination would either +announce partial releases or make a transient message failure roll back a valid +artifact. Separating delivery retains truthful completion and retryable +communication. + +### Withdrawal changes eligibility, not history + +Deleting history would make audit, replay, and version reservation ambiguous. +An append-only withdrawal preserves what happened while letting discovery and +aliases stop recommending the release. ## Where this connects -- [Spec](spec.md) — the requirements this design delivers. -- [Publishing Targets](design-publishing-targets.md) — the contract each destination documents. -- [Downstream Release Propagation](../downstream-release-propagation/design.md) — consumes the release note and immutable reference. -- [GitHub Actions](../../Coding-Standards/GitHub-Actions.md) — how the workflow itself is authored (SHA pins, least privilege, concurrency). -- [Security](../../Coding-Standards/Security.md#supply-chain) — why consumers pin to immutable references. +- [Spec](spec.md) — the normative release contract. +- [Publishing Targets](design-publishing-targets.md) — destination-native + mappings and guarantees. +- [Accept moved release tags](accept-moved-release-tags.md) — consumer recovery + for controlled aliases implemented as Git tags. +- [Automation Labels](../../Ways-of-Working/Automation-Labels.md) — exact marker + meanings and conflicts. +- [GitHub Actions](../../Coding-Standards/GitHub-Actions.md) — immutable external + action pins and controlled owned aliases. +- [PR Format](../../Ways-of-Working/PR-Format.md) — release-note and consumer + evidence source. diff --git a/src/docs/Capabilities/release-management/index.md b/src/docs/Capabilities/release-management/index.md index cf760a72..e4a1338d 100644 --- a/src/docs/Capabilities/release-management/index.md +++ b/src/docs/Capabilities/release-management/index.md @@ -1,23 +1,28 @@ --- title: Release Management -description: How a source change becomes a versioned, immutable artifact, driven entirely on the GitHub platform. +description: Durable version resolution, publication, recovery, withdrawal, and consumer update policy for immutable releases. --- # Release Management -Turning a merged change into a versioned, immutable artifact — a container -image, a GitHub Action or reusable workflow, a language package, a Terraform -module — paired with a GitHub Release and a git tag, normally driven by -pull-request labels. An implementation may add a GitHub-native ad hoc release -path when its product needs one. No release CLI, no hand-edited version file, -no tagging ritual. +Turning approved source into a versioned, immutable artifact — a container +image, GitHub Action or reusable workflow, language package, Terraform module, +or documentation site — with durable release state and evidence. The ordinary +path starts from a reviewed merge; an approved manual request can release an +accumulated range. Both paths resolve once, build once, resume by recorded +phase, and advertise only completed eligible releases. + +Contributors express release intent through GitHub. Maintainers can recover, +retire, or withdraw releases without reusing versions or rewriting history, and +consumers select an update policy that matches their trust boundary. | Page | Description | | --- | --- | -| [Spec](spec.md) | Requirements for release management — automatic, policy-driven, versioned releases driven entirely on the GitHub platform. | -| [Design](design.md) | How release management is built — a shared reusable workflow that resolves an explicit or configured SemVer bump, builds once, and publishes. | -| [Publishing Targets](design-publishing-targets.md) | The contract every publishing destination documents, with GitHub Releases as the reference target. | +| [Spec](spec.md) | Requirements for durable, recoverable, policy-driven releases and trustworthy consumer updates. | +| [Design](design.md) | Durable release intents, lifecycle transitions, recovery, withdrawal, aliases, announcements, and implementation coverage. | +| [Publishing Targets](design-publishing-targets.md) | Destination contracts for version mapping, prereleases, immutability, withdrawal, aliases, constraints, and release records. | +| [Accept Moved Release Tags](accept-moved-release-tags.md) | Refresh an owned moving release alias locally and configure Git to keep it current. | diff --git a/src/docs/Capabilities/release-management/spec.md b/src/docs/Capabilities/release-management/spec.md index 67579fd4..e3d44fc1 100644 --- a/src/docs/Capabilities/release-management/spec.md +++ b/src/docs/Capabilities/release-management/spec.md @@ -1,98 +1,627 @@ --- title: Spec -description: Requirements for release management — automatic, policy-driven, versioned releases driven entirely on the GitHub platform. +description: Requirements for durable, recoverable, policy-driven releases and trustworthy consumer updates. --- # Release Management — Spec ## Premise -A release turns a source change on a release branch into a **versioned, -immutable artifact** that other systems depend on. Merging a pull request *is* -releasing. Releasing MUST be automatic, predictable, and driven entirely on the -GitHub platform — a contributor focuses on the code they contribute, not a -release CLI, a hand-edited version file, or a tagging convention. +Release management turns approved source into a **versioned, immutable release** +that consumers can trust. A release is normally the result of merging reviewed +change, while a controlled manual request can release already-reviewed +accumulated change. Both paths use the same decision, build, verification, +publication, and evidence controls. -### Principles +The capability preserves enough durable state to finish an interrupted release +without rebuilding or assigning its version to different content. Consumers can +discover only completed, eligible stable releases and can select an explicit +update policy that matches their trust boundary. -This capability rests on the [Principles](../../Ways-of-Working/Principles/index.md): +## Problem and importance -- **[Everything as Code](../../Ways-of-Working/Principles/Engineering-Practices.md#everything-as-code).** The release process and version decision are version-controlled, never a GUI action or manual tag. -- **[Decision before change](../../Ways-of-Working/Principles/AI-First-Development.md#decision-before-change).** The pull request is the decision point; its review gate approves the code *and* the release. An owned bump label records a per-change decision; a version-controlled repository default records the policy used when no level is supplied. -- **[Extensible by default](../../Ways-of-Working/Principles/Software-Design.md#extensible-by-default).** The rules are technology-agnostic at the core, with defined extension points per artifact type. A new artifact type supplies a convention and a publish step, not a new process. +A tag or successful workflow run is not enough to prove that a release completed. +Publication can expose one destination before another fails, mutable pull-request +metadata can change before a retry, and a later commit can reach the stable branch +while an earlier artifact is still incomplete. Recomputing from current state can +then publish different bytes under a reserved version, omit accumulated changes +from the notes, or advertise an incomplete release as current. + +Release management makes the release intent durable. It fixes the approved source, +decision, version, notes, artifact identity, required destinations, and stage +progress, then advances that intent safely through publication. This gives +contributors a predictable release path, operators a recoverable process, and +consumers an accurate version and update contract. + +## Users and jobs + +- **A contributor** records the compatibility impact and consumer evidence while + proposing a change, without operating separate release tooling. +- **A reviewer** approves the source, release decision, and complete consumer + effect together. +- **A maintainer** can release approved accumulated change, resume an interrupted + attempt, retire an unrecoverable attempt, or withdraw a completed release + without rewriting history. +- **A consumer** can discover the current completed stable release and choose how + far a dependency may move within the applicable trust boundary. ## Scope -Applies to any repository that produces a versioned artifact on merge to a -release branch. One test decides applicability: **does merging produce a -versioned, immutable output that something else consumes by version?** If yes, -this capability governs the release. If no, there is nothing to release. +In scope: + +- Version resolution, release approval, and publication for repositories that + produce a versioned artifact. +- Stable releases, prereleases, release candidates, manual release requests, + retries, retirement, and withdrawal. +- Release notes, immutable release evidence, announcements, current-version + discovery, and optional moving aliases. +- Consumer update policies and the producer references needed to express them. + +Out of scope: + +- Deploying a released artifact into a runtime environment. +- Processing a release in dependent repositories. +- Repository rulesets and branch protections, except for the release checks they + must require. ## Requirements -- **Semantic versioning.** Versions follow [SemVer 2.0.0](https://semver.org/) (`vMAJOR.MINOR.PATCH`), derived automatically — never written by hand. -- **A resolved PR release decision.** The repository MAY configure `DefaultBump` as `patch`, `minor`, or `major`; invalid values MUST fail. Multiple owned bump labels, or `release:skip` combined with another owned release label, MUST fail. A valid `release:skip` MUST select no release without resolving a bump. For publishing decisions, one owned `release:patch`, `release:minor`, or `release:major` label MUST take precedence over the configured default; without a bump label, a valid `DefaultBump` MUST supply the level; without either source, automation MUST fail with a missing-decision error, never assume `patch`. `release:pre-release` MAY use either the explicit or configured bump; the mode alone does not supply a level. Bare or unrelated labels MUST be ignored. Conventional commit messages are **not** required. -- **A release per merge.** One eligible merged PR with a resolved bump to a release branch is one release, and the PR review gate is the release gate. `release:skip` validates without publishing. This pull-request path is the required release interface. -- **Decision validation blocks merge.** Every PR targeting a release branch MUST receive a named release-decision CI check required by the branch ruleset or protection. Missing decisions, invalid defaults, and conflicting owned labels MUST fail that check before merge, not only during publication. Source, release-label, and release-settings changes MUST re-evaluate the decision. A failing, pending, or absent required result MUST block both manual and automated merge; a log message, warning, or skipped validator is not enforcement. A valid `release:skip` MUST report a successful no-release decision, not skip the check. -- **Ad hoc release is optional.** An implementation MAY expose `workflow_dispatch` when its product needs an ad hoc release outside the merge flow; implementations are not required to support it. A dispatch MUST require an explicit release decision and release-note context, and MUST use the same version, build, validation, immutability, and publication controls as a merged pull request. A direct push MUST NOT be an ad hoc release interface, and an empty pull request MUST NOT be created solely to trigger a release. -- **Version before build.** The version MUST be resolved before the artifact is built, so the version is part of the artifact's identity rather than a label attached afterwards. -- **Build once.** The artifact MUST be built exactly once and MUST NOT be altered after it is built. The same bytes flow through validation and publishing. Rebuilding to publish means the tested artifact and the published artifact are different artifacts. -- **Stable and prerelease.** Every release is either **stable** (the latest version to adopt) or a **prerelease** (testable, not promoted to latest). A prerelease MUST be obtainable from an open pull request carrying `release:pre-release`, using its explicit or configured bump, and/or from a prerelease branch. -- **Serialised releases.** Only one release process runs against a given version of the codebase (the same ref) at a time. A release mutates shared, version-anchored state — the tag, the version counter, the published artifact — so overlapping runs on the same ref MUST NOT race, and an in-flight release is never interrupted. -- **A single production authority.** Exactly one branch is in charge of the production (stable) version, so consumers get one unambiguous latest stable release and two branches can never publish competing production releases. -- **Notes from the contributor's own words.** The GitHub Release name is the version; its body MUST preserve the release-bound pull request title and complete description, or equivalent complete release-note context for an optional ad hoc dispatch. The authored record follows [PR Format](../../Ways-of-Working/PR-Format.md#description-structure); adoption and technical details MUST NOT be omitted or summarized away. -- **Only artifact-affecting changes release.** A change that does not affect the delivered artifact or its supported consumer contracts MUST carry `release:skip` and MUST NOT produce a release — though validation still runs on every merge. Documentation and internal CI configuration qualify only when they meet that condition. An Action or reusable workflow is itself a product for its callers; its interface and behavior MUST NOT be dismissed as internal tooling because of the file path. -- **Immutable references.** Consumers pin to the most immutable reference available — a container digest or a commit SHA — never a mutable tag. -- **Publish through a target contract.** Every publishing destination is reached through the same [publishing-target contract](design-publishing-targets.md), so the release process stays one process regardless of how many destinations a repository has. Adding a destination supplies a contract and a publish step; it MUST NOT change the release process. -- **All-or-nothing across targets.** Where a repository publishes one artifact to more than one destination, a version MUST NOT end up present on some destinations and absent from others. Partial publication is a failure, reported as one, and resumed by completing the remaining destinations with the same immutable artifact and version. -- **Recovery distinguishes retries from changed output.** Retrying validation or publication of unchanged bytes MUST reuse their artifact and version. A correction that changes the bytes MUST create a new versioned artifact; an existing version is never overwritten or reused. -- **Standard GitHub primitives only.** Pull requests, labels, comments, and, where implemented, workflow dispatch — no external tooling beyond `gh` and GitHub Actions. - -### Release evidence - -- **Incremental consumer contract.** Every release MUST describe its consumer-facing delta against an identified release/source baseline, including applicability, exact actions, and verification, or explicit no-action evidence. Breaking behavior MUST be documented independently of its semantic-version classification. An applicable integration template MUST be identified by repository and verified compatible immutable commit, with producer-source compatibility evidence and linked template work or a justified no-change result. -- **Resolved coordinates.** The release process MUST record the actual target version, tag, immutable source and artifact identity, effective release decision and its source, version-computation base, and consumer-change baseline. The version base and change baseline MUST be distinguished when they differ. A first release MUST identify its initial versioning baseline and lack of a prior release. Authors MUST NOT assign a final version before resolution. -- **Traceable publication.** Generated identity and provenance MAY surround the authored note as a distinct envelope; they MUST NOT replace or rewrite it. The release MUST retain the note's source identity and snapshot provenance so its relationship to the published code is inspectable. Every destination carrying release notes, including downstream propagation, MUST receive the complete record. -- **Correct release scope.** A bundled release's integration PR MUST cover every bundled consumer delta. An optional ad hoc release MUST provide equivalent evidence without implying a nonexistent PR. A prerelease MUST preserve the note appropriate to its immutable published source, not a later final-PR description that describes different code. -- **Metadata-only correction.** A correction to published notes MUST retain an audit of the original and corrected content, reason, supporting source evidence, actor, and time. It MUST NOT alter release artifacts, tags, source identities, or the behavior attributed to a version. Unverifiable historical facts MUST be registered as gaps, not guessed. - -### Consumer update policies - -A consumer chooses how much version movement it accepts. Selecting a policy is a **consumer-side** concern — the release capability's obligation is to publish versions that make every policy expressible: - -| Policy | Accepts | Suits | -| --- | --- | --- | -| **Latest** | any newer version, including major | consumers that track the current release and have tests to catch breakage | -| **Lock major boundary** | newer minor and patch within one major | the default for a library dependency under SemVer | -| **Lock minor boundary** | newer patch only | consumers that accept fixes but no new surface | -| **Lock specific version** | nothing; movement is an explicit change | consumers under change control | -| **Lock immutable fingerprint** | nothing; the reference is a digest or SHA | consumers that require the exact bytes to be provable | - -Because versions are semantic, immutable, and published once, a consumer can adopt any of these without the producer knowing which one it chose. - -## Success criteria - -- Merging an eligible PR with an explicit or configured bump produces a GitHub Release, a git tag, and (where one exists) a published artifact, with no manual step. -- For a publishing PR, an explicit owned bump label overrides the configured default; without that label, a valid `DefaultBump` supplies the level and is recorded as its source. -- A PR with no explicit level, configured default, or valid no-release decision fails the required decision check and cannot merge. Invalid defaults and conflicting owned labels also block merge rather than selecting a fallback. -- Removing the only decision source or changing its inputs re-evaluates the PR check; a prior result does not validate different inputs. -- An open pull request carrying `release:pre-release` and an explicit or configured bump publishes a prerelease without promoting it to latest. -- The artifact that consumers download is byte-identical to the artifact that passed validation. -- A documentation-only merge carrying `release:skip` produces no new version but still runs its CI checks. -- Two release runs for the same ref never overlap; the second waits for the first to finish rather than racing it. -- Only the single production branch ever publishes a stable release. -- A version that reaches one publishing target reaches all of them, or the release is reported as failed. -- Every release is linkable and records its immutable artifact reference. -- The published authored title and body match the release-bound snapshot in full, including adoption, consumer/template evidence, and maintainer details. -- A consumer can identify the actual target, version base, change baseline, and any applicable compatible template without relying on a moving branch, alias, or today's documentation. -- A bundled or ad hoc note covers its complete change range, and a prerelease note never gains instructions for code absent from that prerelease. -- A published-note correction is traceable to released-source evidence while all artifact and source identities remain unchanged. +Requirements use [BCP 14](https://www.rfc-editor.org/info/bcp14) keywords. +Identifiers are append-only and MUST NOT be renumbered or reused. + +### FR1 — Every release has an approved decision and fixed source {#fr1} + +The release decision MUST be major, minor, patch, or skip. For a change with an +associated pull request, one explicit owned decision MUST override the +repository's configured fallback. Missing, invalid, or conflicting decisions +MUST fail closed. A skip decision MUST suppress immediate publication without +removing the change from a later release range. Commit-message syntax MUST NOT +select the decision. + +The ordinary stable release path MUST be an approved pull request merged to the +stable line. A direct push with no associated review MUST validate but MUST NOT +inherit the repository fallback or publish a stable release. + +A manual stable release MUST name a fixed source revision on the stable line, an +explicit aggregate increment, complete release-note context, and approval that +covers the entire included change range. Invoking the release mechanism is not +approval. A retry MUST identify an existing release intent and reuse its frozen +decision. + +#### FR1 scenarios + +```gherkin +Scenario: An explicit decision overrides the fallback + Given the repository fallback is patch + And an approved pull request carries the owned minor decision + When release resolution runs + Then the resolved decision is minor + And the fallback is recorded as not used + +Scenario: A direct push does not inherit the fallback + Given the repository fallback is patch + And a direct push has no associated pull request + When release resolution runs + Then validation runs + And no release is published +``` + +### FR2 — The increment states the complete compatibility impact {#fr2} + +Versions MUST follow [Semantic Versioning 2.0.0](https://semver.org/). For a +stable public contract at `1.0.0` or later, breaking change requires major, +backward-compatible capability requires minor, and backward-compatible repair +requires patch. Before `1.0.0`, breaking or additive change requires minor and a +compatible repair requires patch; reaching `1.0.0` remains a deliberate major +decision. + +The effective increment MUST cover every unreleased change included from the +previous completed stable source through the fixed release source. Known pending +increments establish a minimum aggregate increment: major takes precedence over +minor, which takes precedence over patch. Skipped and direct changes remain in +the range and require an explicit reviewed aggregate decision when their +compatibility impact is not already approved. + +#### FR2 scenarios + +```gherkin +Scenario: Accumulated decisions establish a minimum increment + Given the unreleased range contains approved patch and major changes + When an aggregate release decision is resolved + Then the effective increment is at least major + And a patch decision is rejected +``` + +### FR3 — One stable authority produces one discoverable current version {#fr3} + +Exactly one source line MUST be authorized to produce stable releases. +Current-version discovery MUST select the greatest eligible completed stable +version by SemVer precedence, independently of tag listing order or optional +aliases. + +Incomplete, failed, retired, and explicitly withdrawn releases MUST NOT be +current. If no eligible completed stable release remains, discovery MUST report +that no current stable version exists. A lookup error MUST be surfaced and MUST +NOT be interpreted as withdrawal or absence. + +#### FR3 scenarios + +```gherkin +Scenario: Partial publication is not current + Given version 2.4.0 has reached only one of two required destinations + And version 2.3.2 is the greatest eligible completed stable release + When current-version discovery runs + Then it returns version 2.3.2 + And version 2.4.0 remains incomplete +``` + +### FR4 — Prereleases and release candidates identify the next stable candidate {#fr4} + +A published prerelease MUST use the core version produced by applying its +resolved aggregate increment to the stable baseline and permanent reservations. +It MUST sort before the normal version with the same core and MUST NOT consume +that stable version. Successive versions in one prerelease series MUST increase +by SemVer precedence. + +An ordinary prerelease MUST identify its source series. A dedicated release +candidate MUST use the constant `rc` identifier and an unpadded increasing +counter, such as `2.5.0-rc.1`. A single request MUST NOT select both ordinary +prerelease and release-candidate modes. + +A prerelease MUST be testable but MUST NOT become the current stable release or +advance stable aliases. Cleanup MAY remove an exact prerelease and its record, +but MUST NOT reuse its identifier for different content. + +#### FR4 scenarios + +```gherkin +Scenario: A release candidate leaves its stable version available + Given the stable baseline is 2.4.1 + And the approved aggregate decision is minor + When release candidates are published + Then they use 2.5.0-rc.1, 2.5.0-rc.2, and later counters + And the stable version 2.5.0 remains available +``` + +### FR5 — A durable record is authoritative for release lifecycle state {#fr5} + +Before build, the capability MUST persist a release intent containing its +identity, fixed source and included range, approval evidence, aggregate decision, +resolved version, notes, required destinations, and current stage. After build it +MUST also retain the artifact fingerprint and verification and publication +progress. + +The lifecycle MUST distinguish pending or resolved work, successful build, +successful verification, partial publication, completion, failure, explicit +retirement, and withdrawal of a completed release. Workflow runs, tags, and +destination listings are observations of that lifecycle; none alone is the +authoritative state. + +Resolve MAY allocate a version before build. The reservation becomes permanent +when a build succeeds or any release coordinate becomes externally visible. A +permanent reservation survives failure, retirement, withdrawal, and deletion at +a destination. A resolved request with no successful build and no external +visibility MAY be explicitly superseded while coalescing pending work. + +#### FR5 scenarios + +```gherkin +Scenario: External visibility permanently reserves a version + Given a release exposes version 3.1.0 at one destination + And publication then fails elsewhere + When a later release is resolved + Then version 3.1.0 remains reserved for the original source and artifact + And the later release cannot reuse it +``` + +### FR6 — The verified artifact is the artifact that is published {#fr6} + +The version MUST be fixed before the artifact is built. Build MUST create the +artifact once, after which the artifact MUST remain unchanged. Verification and +every publishing destination MUST consume those same bytes. + +The successful artifact, its fingerprint, and verification evidence MUST remain +available for the entire unresolved lifetime of its release intent. A failed +build that produced no complete artifact MAY run again. A correction that changes +bytes MUST resolve a new version and produce a new artifact. + +#### FR6 scenarios + +```gherkin +Scenario: Build, verification, and publication share one artifact + Given a release is resolved to version 1.8.0 + When build, verification, and publication succeed + Then the published fingerprint equals the verified build fingerprint + And no later stage rebuilt or modified the artifact +``` + +### FR7 — Recovery resumes the recorded phase without changing identity {#fr7} + +A retry MUST load the original release intent and resume only unfinished or +failed work. It MUST reuse the frozen source, decision, version, notes, +destinations, successful artifact fingerprint, verification evidence, and +completed publications. It MUST NOT re-resolve from edited labels, changed +configuration, a later branch tip, or a later pull-request description. + +If the retained artifact is missing, recovery MUST stop with an explicit error. +Restoring bytes that match the recorded fingerprint MAY permit resumption; +rebuilding under the same permanently reserved version MUST NOT. + +An unrecoverable built or externally visible intent MAY be explicitly retired. +Retirement MUST preserve its failure record and permanent reservation and MUST +NOT mark it complete. A corrective release requires separate approval and a new +version. + +#### FR7 scenarios + +```gherkin +Scenario: A partial publication resumes at the missing destination + Given a verified artifact reached one of two required destinations + When the release is retried + Then the completed publication is verified and reused + And the same artifact is published only to the unfinished destination + +Scenario: Missing retained bytes stop recovery + Given a release has a successful recorded build + And no retained or published copy matches its fingerprint + When recovery runs + Then recovery fails with a missing-artifact error + And no rebuild occurs under the reserved version +``` + +### FR8 — Every required destination completes before the release completes {#fr8} + +One release MAY publish to multiple destinations, but MUST use the same canonical +identity and notes at each. The release MUST remain incomplete until every +required artifact and release record is published successfully. Completed +destination work MUST be recorded and reused idempotently. + +Completion announcements MUST be separate from artifact publication. Delivery +progress MUST be retained per release and destination, and an unacknowledged +delivery MAY be retried with at-least-once semantics. Announcement failure MUST +NOT create another version, rebuild, republish the artifact, or revoke an +otherwise complete release. + +#### FR8 scenarios + +```gherkin +Scenario: Announcement retry does not create another release + Given version 4.2.0 is complete + And one announcement destination did not acknowledge delivery + When announcement delivery is retried + Then the same release identity and message context are reused + And no new version, build, or artifact publication occurs +``` + +### FR9 — Every destination satisfies the publishing-target contract {#fr9} + +Every publishing destination MUST document: + +- its native version syntax and canonical SemVer mapping; +- prerelease representation, validation, and ordering; +- immutability and the strongest consumer reference; +- withdrawal, unpublish, or yank behavior; +- supported moving-alias families; +- native version-constraint support; and +- the location of its durable release record. + +Distinct canonical releases MUST NOT map to one native coordinate. A mapping +collision or disagreement between the canonical prerelease status and a native +prerelease flag MUST fail rather than overwrite or misrepresent a release. + +#### FR9 scenarios + +```gherkin +Scenario: A native coordinate collision blocks publication + Given two canonical releases map to one destination version + When the second mapping is validated + Then publication fails before content is overwritten + And the original coordinate remains unchanged +``` + +### FR10 — The release record covers the complete included change {#fr10} + +Release notes MUST account for every change from the previous completed stable +source through the fixed release source, including skipped and direct changes. +They MUST preserve contributor-authored title, description, adoption guidance, +consumer-change evidence, and maintainer evidence under +[PR Format](../../Ways-of-Working/PR-Format.md), or equivalent reviewed aggregate +context for a manual release. + +The resolved version, version baseline, change baseline, fixed source, artifact +fingerprint, effective decision and source, destination coordinates, and note +snapshot provenance MUST be retained as a publication envelope without replacing +or rewriting the authored note. + +#### FR10 scenarios + +```gherkin +Scenario: A later release includes a skipped change + Given change A was merged with a skip decision + And approved change B triggers the next release + When release notes are frozen + Then the notes and aggregate decision cover A and B exactly once +``` + +### FR11 — Eligibility evaluates the complete unreleased artifact scope {#fr11} + +Only changes that affect the delivered artifact or a supported consumer contract +MUST produce a release. Eligibility MUST evaluate the complete unreleased range, +including direct and transitive build inputs, rather than only the latest change. +Validation MUST still run when publication is skipped. + +Without configured scope, every changed path MUST be treated conservatively as +release-affecting. A repository MAY narrow the scope explicitly. File categories +such as documentation or workflow definitions MUST NOT be universally excluded, +because they can be the product or an artifact input. + +#### FR11 scenarios + +```gherkin +Scenario: An out-of-scope change validates without publishing + Given the repository declares its artifact-affecting scope + And the full unreleased range contains no matching change + When release processing runs + Then validation runs + And no version or release is published +``` + +### FR12 — Release requests are serialized and accounted for in source order {#fr12} + +Release work on the same release line MUST NOT run concurrently and MUST queue +rather than cancel in-flight publication. Requests MUST be reconciled in source +history order, independently of worker start order. Duplicate event delivery +MUST return the same intent or outcome. + +A missed event, replaced worker, or bounded execution queue MUST NOT silently +discard a release request. Pending work MUST remain recoverable from durable +state or source history before later source revisions advance the line. + +After intervening changes, a built or externally visible intent MUST first be +resumed or explicitly retired. Remaining unbuilt and unexposed requests MAY be +backfilled individually or coalesced under a reviewed aggregate decision. Every +original request MUST record the release that accounts for it. + +#### FR12 scenarios + +```gherkin +Scenario: Later work cannot overtake an unresolved intent + Given changes A and B reached the stable line in that order + And A has a built incomplete release + When B is processed + Then A is resumed or explicitly retired first + And B cannot replace A's reserved version or artifact +``` + +### FR13 — Moving aliases are closed, optional, and withdrawal-aware {#fr13} + +The available moving-alias families MUST be exactly `latest`, major, and minor. +Each family MUST be enabled independently and MUST default to disabled. Unknown +families or unsupported target combinations MUST fail configuration validation. + +An enabled alias MUST resolve to the greatest eligible completed stable version +matching its family. A new older release MUST NOT move an alias backward. +Withdrawal MUST reselect the greatest remaining eligible match, which may be an +older version. If no eligible match remains, the alias MUST be removed or +disabled rather than left on an ineligible release. Prereleases MUST NOT move a +stable alias. + +#### FR13 scenarios + +```gherkin +Scenario: Withdrawal reselects an alias + Given the major alias points to completed stable version 3.4.0 + And completed stable version 3.3.2 remains eligible + When version 3.4.0 is explicitly withdrawn + Then the major alias is reconciled to 3.3.2 + And the withdrawn version remains reserved +``` + +### FR14 — Consumer update policy is explicit and trust-aware {#fr14} + +A consumer MAY select exactly one of these policies: + +| Policy | Accepted movement | +| --- | --- | +| `latest` | The newest eligible stable release, including a new major. | +| `lock-major-boundary` | Minor and patch releases within one selected major. | +| `lock-minor-boundary` | Patch releases within one selected major and minor. | +| `lock-specific-version` | No automatic movement from one exact version. | +| `lock-immutable-fingerprint` | No automatic movement from one exact content identity. | + +When no policy is selected, the consumer MUST use the most immutable reference +available. A boundary policy MUST be available only when the producer and target +publish the corresponding major or minor alias. Where the consumer syntax +accepts no version range, the producer alias carries that bound; a range-like +string MUST NOT be treated as a resolver expression. + +Mutable aliases MAY be used only within the consumer's permitted trust boundary. +An external producer, including one owned by another team in the same company, +MUST be pinned to an immutable fingerprint or exact immutable version. `latest` +MAY discover a release without an alias, then resolve it to the reference allowed +by the trust boundary. + +#### FR14 scenarios + +```gherkin +Scenario: An unsupported boundary policy fails explicitly + Given a consumer requests lock-minor-boundary + And the producer does not publish the minor alias family + When the policy is resolved + Then the request fails as unsupported + And it is not widened to latest or a major boundary + +Scenario: An external producer remains immutable + Given a consumer selects latest for a producer outside its trust boundary + When the current release is discovered + Then the durable consumer reference is its immutable fingerprint + And no moving producer alias is retained +``` + +### FR15 — Release-decision validation blocks an invalid merge {#fr15} + +Every pull request targeting a release line MUST receive a named release-decision +check required by branch policy. The check MUST re-evaluate when source, owned +release markers, or release settings change. A missing, conflicting, or invalid +decision MUST fail; a valid skip MUST pass with an explicit no-release result. +A failed, pending, absent, or stale required result MUST block manual and +automated merge. + +#### FR15 scenarios + +```gherkin +Scenario: Decision input changes invalidate the prior result + Given a pull request has a successful release-decision check + When its only owned decision is removed + Then the check is rerun + And merge remains blocked until the new inputs resolve validly +``` + +### FR16 — Withdrawal preserves history and requires explicit authorization {#fr16} + +A completed release MAY be withdrawn only through an explicit +maintainer-authorized operation. Withdrawal MUST be recorded separately from the +original completion and MUST preserve source history, approval evidence, +artifact identity, destination outcomes, announcements, and version reservation. +Ordinary deprecation or a temporary lookup failure MUST NOT imply withdrawal. + +Replaying a withdrawn release MUST report its withdrawn outcome. It MUST NOT +recreate removed records, resend the completion announcement, or make the +release current again. Correcting a bad release MUST roll forward with a newly +approved version. + +#### FR16 scenarios + +```gherkin +Scenario: Withdrawal does not erase completion + Given version 5.1.0 completed and was announced + When an authorized maintainer withdraws it + Then its completion and announcement history remain recorded + And replay reports the withdrawal without recreating or re-announcing it +``` + +### FR17 — Published-note corrections are auditable metadata changes {#fr17} + +A correction to published explanatory metadata MUST retain the original and +corrected content, reason, source evidence, actor, and time. It MUST NOT change +the artifact, exact version reference, fixed source, release decision, or +behavior attributed to that version. Unverifiable historical facts MUST be +recorded as evidence gaps rather than guessed. + +#### FR17 scenarios + +```gherkin +Scenario: A note correction cannot change release identity + Given a completed release has incorrect explanatory text + When an authorized correction is applied + Then the original and corrected text and evidence are retained + And the version, source, and artifact fingerprint remain unchanged +``` + +## Non-functional requirements + +### NFR1 — Published versions are immutable {#nfr1} + +One hundred percent of published stable versions MUST remain bound permanently +to their original source and artifact. A version identifier MUST NOT be reused +after failure, retirement, withdrawal, unpublish, or repository recreation. +Destination-native immutability controls MUST be enabled where available. + +#### NFR1 scenarios + +```gherkin +Scenario: A withdrawn version cannot be reused + Given stable version 2.0.0 was published and later withdrawn + When different content requests version 2.0.0 + Then publication is rejected + And the original reservation remains authoritative +``` + +### NFR2 — Recovery retains all unresolved release evidence {#nfr2} + +One hundred percent of unresolved built release intents MUST retain the artifact +fingerprint, frozen inputs, and phase progress required for safe resumption until +they complete or are explicitly retired. + +#### NFR2 scenarios + +```gherkin +Scenario: An unresolved release remains recoverable + Given a verified release is incomplete + When its worker and workflow run no longer exist + Then its durable record still identifies the artifact and remaining work +``` + +### NFR3 — Release behavior is shared and GitHub-native {#nfr3} + +One hundred percent of governed repositories MUST inherit one shared release +behavior, with zero repository-local copies of the resolution or lifecycle +algorithm. Contributors and maintainers MUST be able to drive decisions, manual +requests, retries, retirement, withdrawal, and evidence through GitHub pull +requests, owned labels, comments, checks, and workflow dispatch without a +separate local release tool. + +#### NFR3 scenarios + +```gherkin +Scenario: Equivalent repositories resolve equivalent requests consistently + Given two repositories inherit the same release capability and policy + When equivalent approved release requests are processed + Then they apply the same lifecycle, version, and recovery rules +``` + +### NFR4 — New destinations do not change the lifecycle contract {#nfr4} + +One hundred percent of new artifact types and destinations MUST be added through +the publishing-target contract without changing the requirements or release +lifecycle. + +#### NFR4 scenarios + +```gherkin +Scenario: A new destination uses the existing lifecycle + Given a destination satisfies the publishing-target contract + When it is added to a release + Then Resolve, Build, Verify, Publish, completion, and recovery retain their existing meaning +``` + +## Acceptance criteria + +```gherkin +Scenario: AC1 A reviewed merge completes one durable stable release + # Verifies: FR1, FR2, FR3, FR5, FR6, FR8, FR10 + Given the current stable release is 1.4.2 + And an approved in-scope pull request resolves to minor + When every required destination succeeds + Then exactly one completed release 1.5.0 is recorded + And its notes, fixed source, artifact fingerprint, and destination coordinates are durable + And current-version discovery returns 1.5.0 + +Scenario: AC2 An interrupted release resumes without identity drift + # Verifies: FR5, FR6, FR7, FR8, FR12 + Given a verified artifact is published to only one required destination + And later commits reach the stable line + When the original release is retried + Then it completes the missing destination with the recorded artifact + And its source, version, notes, and completed publication remain unchanged + +Scenario: AC3 Withdrawal changes eligibility without changing history + # Verifies: FR3, FR5, FR13, FR16, NFR1 + Given two completed stable releases and aliases pointing to the newer one + When the newer release is explicitly withdrawn + Then discovery and aliases select the older eligible release + And the withdrawn release's completion history and version reservation remain +``` ## Where this connects -- [Design](design.md) — how these requirements are delivered. -- [Publishing Targets](design-publishing-targets.md) — the contract each destination documents. -- [Documentation Model](../../Ways-of-Working/Documentation-Model.md) — why this spec holds only the why and the what. -- [Automation Labels](../../Ways-of-Working/Automation-Labels.md) — why release labels are owned by the `release:` namespace. -- [PR Format](../../Ways-of-Working/PR-Format.md) — the change-type labels that drive the bump. -- [Dependency Updates](../dependency-updates/spec.md) — update PRs are artifact-affecting and release through this capability. +- [Design](design.md) — how the intended lifecycle and current implementation + coverage realize these requirements. +- [Publishing Targets](design-publishing-targets.md) — the destination contract + and native behavior. +- [Automation Labels](../../Ways-of-Working/Automation-Labels.md) — the owned + release instruction vocabulary. +- [PR Format](../../Ways-of-Working/PR-Format.md) — the authored release note and + consumer evidence. +- [Dependencies](../../Coding-Standards/Dependencies.md) — dependency pinning and + update trade-offs. diff --git a/src/docs/Coding-Standards/GitHub-Actions.md b/src/docs/Coding-Standards/GitHub-Actions.md index dc8c22ec..c3411f50 100644 --- a/src/docs/Coding-Standards/GitHub-Actions.md +++ b/src/docs/Coding-Standards/GitHub-Actions.md @@ -38,6 +38,12 @@ exception is a floating major tag on automation whose release path MSX controls: release creates the next major tag; it never repoints the existing major tag across the compatibility boundary. +A local clone that consumes an allowed owned major tag must explicitly accept +producer-controlled tag movement. Follow +[Accept moved release tags](../Capabilities/release-management/accept-moved-release-tags.md) +to repair a stale tag and configure trusted fetches. This does not relax the +immutable-SHA requirement for external actions. + ```yaml # External — immutable SHA; comment carries the readable version - name: Check out the repository diff --git a/src/docs/Ways-of-Working/Automation-Labels.md b/src/docs/Ways-of-Working/Automation-Labels.md index 83b792a1..46a08800 100644 --- a/src/docs/Ways-of-Working/Automation-Labels.md +++ b/src/docs/Ways-of-Working/Automation-Labels.md @@ -54,6 +54,8 @@ namespaced, including the release set: | `release:minor` | Publish a minor release. | | `release:major` | Publish a major release. | | `release:pre-release` | Publish a prerelease from the open pull request. | +| `release:rc` | Publish the next release candidate for the resolved stable version. | +| `release:announce` | Deliver configured announcements after the release completes. | | `release:skip` | Validate the change without publishing a release. | These labels are read by @@ -62,9 +64,20 @@ One owned bump label records an explicit level and overrides the optional repository `DefaultBump`; for publishing decisions without a bump label, a valid configured default supplies it. `release:skip` records a no-release decision. `release:pre-release` is a mode used with a resolved explicit or configured bump, -never with `release:skip`. Release Management owns the +never with `release:skip`. `release:rc` is the dedicated release-candidate mode: +it uses the constant `rc` identifier with an increasing numeric counter and +conflicts with both `release:pre-release` and `release:skip`. +`release:announce` can accompany a stable or prerelease publication; it selects +configured post-completion delivery and does not authorize a version, build, or +publication by itself. + +Release Management owns the [resolver and required pre-merge validation](../Capabilities/release-management/design.md#version-computation); -an absent label and absent default are not an implicit patch decision. +an absent label and absent default are not an implicit patch decision. The +[implementation crosswalk](../Capabilities/release-management/design.md#intended-and-implemented-behavior) +identifies which labels the current shared baseline executes. An owned label +reserved by this contract but unsupported by the invoked workflow MUST fail +validation rather than be ignored or approximated. Reserving bare words would be weaker because it depends on a documented prohibition rather than making ownership visible in the label itself. diff --git a/src/zensical.toml b/src/zensical.toml index 6e19106a..e48c1030 100644 --- a/src/zensical.toml +++ b/src/zensical.toml @@ -124,6 +124,7 @@ nav = [ {"Spec" = "Capabilities/release-management/spec.md"}, {"Design" = "Capabilities/release-management/design.md"}, {"Publishing Targets" = "Capabilities/release-management/design-publishing-targets.md"}, + {"Accept Moved Release Tags" = "Capabilities/release-management/accept-moved-release-tags.md"}, ]}, {"Repository Governance" = [ "Capabilities/repository-governance/index.md", From a61cdd321053c71347a89d1d56814b90fd221e67 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 31 Oct 2026 14:09:56 +0100 Subject: [PATCH 02/10] Reconcile lifecycle guidance with the shared PR contract and native targets --- .github/CONTRIBUTING.md | 17 +- .../Capabilities/dependency-updates/design.md | 18 +- .../Capabilities/dependency-updates/spec.md | 21 +- .../Capabilities/merge-automation/design.md | 2 +- .../accept-moved-release-tags.md | 34 +- .../design-publishing-targets.md | 36 +- .../Capabilities/release-management/design.md | 20 +- .../Capabilities/release-management/spec.md | 21 +- .../vscode-extension-framework/design.md | 22 +- .../vscode-extension-framework/spec.md | 4 +- src/docs/Coding-Standards/Dependencies.md | 2 +- src/docs/Coding-Standards/GitHub-Actions.md | 3 +- src/docs/Coding-Standards/Natural-Language.md | 9 +- src/docs/Ways-of-Working/Automation-Labels.md | 37 +- .../Ways-of-Working/Branching-and-Merging.md | 4 +- .../Continuous-Delivery-And-Release.md | 5 +- .../Ways-of-Working/Contribution-Workflow.md | 12 +- .../Definition-of-Ready-and-Done.md | 2 +- .../Ways-of-Working/Documentation-Model.md | 27 +- .../Ways-of-Working/Fleet-Orchestration.md | 159 ++-- src/docs/Ways-of-Working/PR-Format.md | 771 ++++++++++++------ .../Ways-of-Working/Readme-Driven-Context.md | 2 +- .../Ways-of-Working/Repository-Standard.md | 27 +- .../Workflow-Stages/Implement.md | 10 +- .../Ways-of-Working/Workflow-Stages/Review.md | 7 +- src/docs/Ways-of-Working/Workflow.md | 5 +- src/docs/Ways-of-Working/index.md | 2 +- 27 files changed, 869 insertions(+), 410 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 959ba7b5..43de0c31 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -2,7 +2,9 @@ Every change lands through a pull request — nothing goes directly to `main`. See the [Contribution Workflow](https://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/) -for the full process: draft first, the Copilot review loop, then human review. +for the full process: draft first, the Copilot review loop, then human review. Write the +title and description according to +[PR Format](https://msxorg.github.io/docs/Ways-of-Working/PR-Format/). Everything here is a work in progress and can be improved. Fix a small problem when it is directly in scope; register a larger or unrelated one as an issue in the repository that @@ -50,6 +52,17 @@ owns it. 7. Open the pull request as a draft and follow the [Contribution Workflow](https://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/). +## Pull request template + +This repository intentionally has no local pull request template. GitHub inherits +the [MSX organization +template](https://github.com/MSXOrg/.github/blob/main/.github/pull_request_template.md) +from the special `MSXOrg/.github` repository. Treat that template as a starting +scaffold; the canonical [PR +Format](https://msxorg.github.io/docs/Ways-of-Working/PR-Format/) controls the +final title and description. Start from its +[complete description template](https://msxorg.github.io/docs/Ways-of-Working/PR-Format/#copy-the-complete-template). + ## Authoring conventions The docs are built for recursive navigation, so a reader or an agent can start at the top @@ -113,6 +126,6 @@ conventional-commit prefixes. See Push every commit, so the remote branch, CI, and the draft pull request always reflect the current state of the work. -See the [README](README.md) for what this repository is and how it is laid out, and the +See the [README](../README.md) for what this repository is and how it is laid out, and the [Ways of Working](https://msxorg.github.io/docs/Ways-of-Working/) for the conventions every pull request follows — issue format, PR format, branching, and review etiquette. diff --git a/src/docs/Capabilities/dependency-updates/design.md b/src/docs/Capabilities/dependency-updates/design.md index 56f47976..d0dcbeba 100644 --- a/src/docs/Capabilities/dependency-updates/design.md +++ b/src/docs/Capabilities/dependency-updates/design.md @@ -80,14 +80,16 @@ flowchart TD pr --> ci["Required checks run
(same gate as any PR)"] ci --> review["Review and merge"] review --> merged["Merged"] - merged --> release["Separate release decision
see Release Management"] + merged --> release["Conditional release decision
see Release Management"] ``` ### Release decision -Dependency changes are collected before the repository release decision is -made. The repository-wide effect follows [Release -Management](../release-management/design.md). +Dependency changes are collected before any repository release decision is +made. When the target route invokes [Release +Management](../release-management/design.md), that capability resolves the +repository-wide effect. Otherwise the pull request omits the `Release decisions` +block and all `release:*` labels. ## Review and merge @@ -97,8 +99,8 @@ gates. Automatic merge, where configured, never bypasses those gates. ## Security updates Raised on advisory disclosure, independently of the schedule, and -**prioritised**. They otherwise follow the same review policy and release path as -any other update. +**prioritised**. They otherwise follow the same review policy and any applicable +release path as another update. ## Configuration surface @@ -108,7 +110,7 @@ any other update. | Unsupported ecosystems | Central exception register | Centrally managed shared mechanism | | Schedule (`interval`, `day` and `time`, or `cronjob`) and `timezone` | `.github/dependabot.yml` | Organization configuration | | Cooldown | Updater default (three days); explicit mapping only for a deliberate non-default duration | Organization configuration | -| Release decision | Release Management | Decided for the collected repository change | +| Release decision | Release Management, when invoked for the target route | Decided for the collected repository change | | Merge policy | Branch protection and merge automation | Organization configuration | | Security updates | Repository security settings | On by default | @@ -121,6 +123,6 @@ rather than overwrite. - [Spec](spec.md) — the requirements this design delivers. - [Repository Governance](../repository-governance/design.md#drift-detection-and-reconciliation) — the reconciliation that compares generated configuration against what is committed. -- [Release Management](../release-management/design.md) — the release an update PR cuts. +- [Release Management](../release-management/design.md) — the conditional release decision and output for an update pull request. - [Downstream Release Propagation](../downstream-release-propagation/design.md) — the internal counterpart; propagation PRs are dependency updates too. - [GitHub Actions](../../Coding-Standards/GitHub-Actions.md#keep-pinned-actions-current) — the Action-pin specifics this builds on. diff --git a/src/docs/Capabilities/dependency-updates/spec.md b/src/docs/Capabilities/dependency-updates/spec.md index 419d833b..e4425b03 100644 --- a/src/docs/Capabilities/dependency-updates/spec.md +++ b/src/docs/Capabilities/dependency-updates/spec.md @@ -11,15 +11,18 @@ Every repository pins dependencies by version — Action SHAs, image digests, package versions, provider constraints. Those pins age: a newer version fixes a bug the repository still carries, and a disclosed advisory turns a safe pin into a vulnerability. Keeping them current MUST be automatic and driven on the GitHub -platform, producing ordinary pull requests that are reviewed and released -through the same gate as any change — never a side channel that bypasses review. +platform, producing ordinary pull requests that are reviewed through the same +gate as any change — never a side channel that bypasses review. When the target +route invokes Release Management, its release decision and publication path are +resolved separately from the updater; a route without that invocation carries +no `release:*` metadata. ### Principles This capability rests on the [Principles](../../Ways-of-Working/Principles/index.md): - **[Everything as Code](../../Ways-of-Working/Principles/Engineering-Practices.md#everything-as-code).** What is checked and how often is version-controlled configuration, not a manual audit. -- **[Decision before change](../../Ways-of-Working/Principles/AI-First-Development.md#decision-before-change).** Every update is a pull request; its review gate approves the bump, while its release impact is decided separately. +- **[Decision before change](../../Ways-of-Working/Principles/AI-First-Development.md#decision-before-change).** Every update is a pull request; its review gate approves the dependency change, while any applicable release decision is resolved separately. - **[Least-privilege](../../Ways-of-Working/Principles/Purpose-and-Direction.md#least-privilege).** The updater and any auto-merge automation carry only the permissions they need. - **[Extensible by default](../../Ways-of-Working/Principles/Software-Design.md#extensible-by-default).** Adding a package ecosystem is a configuration entry, not new machinery. @@ -31,9 +34,9 @@ other ecosystem the repository actually uses. Two questions are asked of every p **currency** (is a newer version available?) and **security** (does the pinned version carry a known advisory?). -Out of scope: what an update *does* to the artifact. That is the release the update -produces, and it is governed by [Release -Management](../release-management/spec.md). +Out of scope: what an update *does* to the artifact. Where the target route +invokes [Release Management](../release-management/spec.md), that capability +governs the release decision and output. ## Requirements @@ -69,7 +72,7 @@ Management](../release-management/spec.md). ### Review and release - **FR10 — One reviewed pull request per update.** Each dependency update is a pull request that passes the full check suite before merge. Nothing is applied unreviewed, and no update takes a side channel around the gate. -- **FR11 — Release impact is decided separately.** The dependency updater MUST NOT choose the repository's release bump. After dependency changes are collected, the repository-wide effect is decided according to [Release Management](../release-management/spec.md). +- **FR11 — Release decisions stay independent.** The dependency updater MUST NOT choose the repository's release bump or apply `release:*` labels. After dependency changes are collected, the repository-wide effect is decided according to [Release Management](../release-management/spec.md) only when the target route invokes it. - **FR12 — Review and merge follow the repository gate.** An update MUST pass the repository's normal review and required-check policy before merge. - **FR13 — Automatic merge is never a bypass.** Where automatic merge is configured, it MUST preserve review requirements and required checks. @@ -83,12 +86,12 @@ Management](../release-management/spec.md). - An outdated or vulnerable pin produces a pull request with no human trigger. - An ecosystem added to a repository without a corresponding updater entry is a detectable finding, not a silent gap. -- The repository-wide release impact of dependency changes is decided separately under Release Management. +- When the target route invokes Release Management, the repository-wide release decision for dependency changes is resolved separately under that capability. - No dependency pull request merges without passing the same checks as any other pull request. ## Where this connects - [Design](design.md) — the updater, review, and automatic-merge policy. -- [Release Management](../release-management/spec.md) — the separate repository-wide release decision for merged dependency changes. +- [Release Management](../release-management/spec.md) — the conditional, separate repository-wide release decision for merged dependency changes. - [Repository Governance](../repository-governance/spec.md) — the reconciliation that detects an uncovered ecosystem. - [GitHub Actions](../../Coding-Standards/GitHub-Actions.md#keep-pinned-actions-current) — keeping pinned Actions current. diff --git a/src/docs/Capabilities/merge-automation/design.md b/src/docs/Capabilities/merge-automation/design.md index 72abac74..9d30134e 100644 --- a/src/docs/Capabilities/merge-automation/design.md +++ b/src/docs/Capabilities/merge-automation/design.md @@ -103,5 +103,5 @@ approval to the eligible set the ruleset actually lets it satisfy. - [Spec](spec.md) — the requirements this design delivers. - [GitHub Actions](../../Coding-Standards/GitHub-Actions.md#gate-merges-with-a-named-status-check) — authoring the named checks this consumes. - [Dependency Updates](../dependency-updates/design.md) — the auto-merge policy this generalises; dependency update PRs are the canonical eligible set. -- [Release Management](../release-management/design.md) — the release a merge triggers. +- [Release Management](../release-management/design.md) — the release a merge triggers on an invoked route. - [Branching and Merging](../../Ways-of-Working/Branching-and-Merging.md) — pull-request-only integration and readable history. diff --git a/src/docs/Capabilities/release-management/accept-moved-release-tags.md b/src/docs/Capabilities/release-management/accept-moved-release-tags.md index 35b26c8b..379bd396 100644 --- a/src/docs/Capabilities/release-management/accept-moved-release-tags.md +++ b/src/docs/Capabilities/release-management/accept-moved-release-tags.md @@ -28,16 +28,28 @@ producer-owned alias movement explicitly. ## Refresh tags once -Before this command, preserve or rename any local-only tags you need. Pruning -tags removes local tags that do not exist on the remote, and force permits the -remote's tag values to replace local values. +Before this command, back up any needed local-only tags **outside `refs/tags/`** +and verify the backup. Renaming a local tag within that namespace does not +protect it: the renamed tag is still absent from the remote and will be pruned. +A Git bundle can preserve the original tag objects and reachable history: ```bash -git fetch --tags --force --prune --prune-tags +git bundle create owned-tags-backup.bundle --tags +git bundle verify owned-tags-backup.bundle +``` + +Keep that backup private and outside checked-in paths. Pruning removes local tags +that do not exist on the selected remote, and force permits that remote's tag +values to replace local values. Confirm that `origin` is the intended trusted +producer and that no exact-version-tag integrity incident is being normalized. + +```bash +git fetch --tags --force --prune --prune-tags origin ``` This refreshes moved aliases and removes tags deleted from the configured -remote. Review the fetch output before building or resolving a dependency. +`origin` remote. Review the fetch output before building or resolving a +dependency; never let an implicit upstream choose the source of this refresh. ## Keep owned aliases current @@ -51,15 +63,17 @@ git config --get-all remote.origin.fetch If the output does not already contain `+refs/tags/*:refs/tags/*`, add it once: ```bash -git config --add remote.origin.fetch '+refs/tags/*:refs/tags/*' -git config fetch.prune true -git config fetch.pruneTags true +git config --local --add remote.origin.fetch '+refs/tags/*:refs/tags/*' +git config --local remote.origin.prune true +git config --local remote.origin.pruneTags true ``` The leading `+` allows the remote's tag namespace to update local tags non-fast-forward. The prune settings remove local tag references no longer -present on the remote. Use this configuration only when `origin` is inside the -consumer's permitted trust boundary and the producer owns the moving aliases. +present on `origin`. These settings are specific to that remote, not clone-wide +`fetch.prune` or `fetch.pruneTags` defaults that could affect another remote. +Use this configuration only when `origin` is inside the consumer's permitted +trust boundary and the producer owns the moving aliases. After configuration, a normal fetch from `origin` keeps branches and tags aligned: diff --git a/src/docs/Capabilities/release-management/design-publishing-targets.md b/src/docs/Capabilities/release-management/design-publishing-targets.md index 11c3626e..58c3e786 100644 --- a/src/docs/Capabilities/release-management/design-publishing-targets.md +++ b/src/docs/Capabilities/release-management/design-publishing-targets.md @@ -45,7 +45,7 @@ frees a canonical version or prerelease identifier for reuse. | Target | Version scheme | Prerelease | Immutable reference | Withdrawal | Alias families | Native constraints | Release record | | --- | --- | --- | --- | --- | --- | --- | --- | | **GitHub Releases** | Exact `vMAJOR.MINOR.PATCH` or prerelease tag | SemVer suffix and native prerelease flag | Protected exact tag, source commit, and asset digest | Delete or mark unavailable; coordinate remains reserved | `latest`, major, minor as optional Git tags; native Latest separately | No range resolver | GitHub Release and durable release intent | -| **PowerShell Gallery** | `MAJOR.MINOR.PATCH` module version | SemVer suffix | Published module version | Unlist; downloads already held remain; version is not reusable | None | NuGet ranges through PSResourceGet; mapped manifest constraints | Gallery listing joined from GitHub Release | +| **PowerShell Gallery** | Numeric manifest core plus validated `PSData.Prerelease` | Two-field module/label mapping | Published module version | Unlist; downloads already held remain; version is not reusable | None | NuGet ranges through PSResourceGet; mapped manifest constraints | Gallery listing joined from GitHub Release | | **NuGet** | `MAJOR.MINOR.PATCH` package version | SemVer suffix | Published package version and package hash | Unlist or deprecate; version is not reusable | None | NuGet version ranges | Package listing joined from GitHub Release | | **VS Code Marketplace** | Marketplace-compatible extension version mapped from canonical SemVer | Separate prerelease channel and flag | Published extension version | Unpublish where permitted; version is not reusable | Native stable/prerelease channel selection, not release aliases | No consumer-selected SemVer range | Marketplace listing joined from GitHub Release | | **Container registry** | Version tag plus content digest | SemVer suffix in exact tag | Manifest or image digest | Delete tag or manifest where permitted; reservation remains | `latest`, major, minor as optional tags | No range resolver | Registry digest joined from GitHub Release | @@ -139,10 +139,18 @@ retirement, withdrawal, alias reconciliation, and announcements. ### PowerShell Gallery version and prerelease mapping -The module manifest and gallery coordinate use canonical SemVer without the -leading `v`. A prerelease suffix is retained where the gallery and module -manifest permit it. Mapping validation runs before publication so a native -version cannot collide with another canonical release. +The manifest's `ModuleVersion` is a numeric three-part `System.Version`, not a +SemVer prerelease string. For a prerelease, put its supported label in +`PrivateData.PSData.Prerelease`; the Gallery combines the numeric core and label +into its native package coordinate. + +For example, canonical `2.5.0-alpha` maps to `ModuleVersion = '2.5.0'` and +`PrivateData.PSData.Prerelease = 'alpha'`, not `ModuleVersion = '2.5.0-alpha'`. +The adapter validates the label against the selected publishing client's actual +syntax; dotted or build-metadata forms are not assumed to be accepted. A +non-preserving conversion requires an explicit collision-free, ordering-aware +mapping or fails as unsupported before publication. Record both canonical and +native identities. See [PowerShell prerelease module fields](https://learn.microsoft.com/en-us/powershell/gallery/concepts/module-prerelease-support). ### PowerShell Gallery immutability and withdrawal @@ -201,11 +209,19 @@ owns the detailed VSIX and marketplace behavior. ### VS Code Marketplace version and prerelease mapping -Stable extension versions map directly to the marketplace-compatible version in -the VSIX manifest. The marketplace represents prereleases through its separate -prerelease channel and `--pre-release` publication flag, including the -framework's odd-minor convention. The adapter records the canonical prerelease -and native extension version together and MUST guarantee a one-to-one mapping. +The owning framework declares and verifies stable and prerelease mappings +together before enabling Marketplace publication. The Marketplace accepts a +numeric three-part extension version and a separate prerelease channel/flag, +not an arbitrary canonical prerelease suffix. There is no assumed direct stable +mapping plus an independently invented prerelease mapping. + +An odd-minor convention is valid only when the declared stable mapping reserves +that space and the series/counter allocation is proven collision-free across +every supported canonical identity. Record canonical and native versions +together; an unsupported mapping or coordinate collision blocks publication. +The [owning framework's mapping contract](../vscode-extension-framework/design.md#marketplace-version-mapping) +controls that conversion, while the immutable GitHub VSIX install path remains +available without Marketplace support. ### VS Code Marketplace immutability and withdrawal diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index 2c0dc375..4b00e727 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -26,7 +26,7 @@ Documentation alone does not make a lifecycle control or setting available. 6. **Consumers choose policy within a trust boundary.** Producers expose only the controlled references required to implement that policy. -## Release authority and interfaces {#branching-model} +## Applicability The effective pipeline establishes whether the target route produces a versioned, immutable output consumed by version. Managed routes participate @@ -34,6 +34,8 @@ whether they use a shared workflow or a native producer pipeline, and whether `.github/release.config.yml` exists. Unmanaged routes omit release metadata and every `release:*` label; a Pages deployment alone is not a versioned release. +## Release authority and interfaces {#branching-model} + Release branches are keyed by `ReleaseType.Stable`, `ReleaseType.Prerelease`, and `ReleaseType.ReleaseCandidate`, each with its own `Branch`. The stable branch defaults to the repository default branch; the other keys are optional. @@ -483,15 +485,17 @@ The consumer resolves one of five policies: | Policy | Producer mechanism | Durable consumer reference | | --- | --- | --- | | `latest` | Discover the greatest eligible completed stable release. | The discovered immutable version or fingerprint required by trust policy. | -| `lock-major-boundary` | Producer major alias, such as `v3`. | Moving alias only inside the allowed trust boundary. | -| `lock-minor-boundary` | Producer minor alias, such as `v3.4`. | Moving alias only inside the allowed trust boundary. | +| `lock-major-boundary` | Supported native major-bounded constraint, or producer major alias for an opaque reference field. | The resolved immutable reference required by trust policy, or an allowed owned alias. | +| `lock-minor-boundary` | Supported native minor-bounded constraint, or producer minor alias for an opaque reference field. | The resolved immutable reference required by trust policy, or an allowed owned alias. | | `lock-specific-version` | Exact immutable version. | Exact version. | | `lock-immutable-fingerprint` | Content digest, commit SHA, or equivalent. | Immutable fingerprint. | -A requested boundary is unsupported when the producer does not publish the -matching alias; it is never widened silently. When a consumer field accepts only -one opaque reference, a text such as `>=3,<4` is not a range expression. The -producer carries the bound through its controlled alias. +A requested boundary is unsupported only when neither the consumer/target's +native constraints nor a permitted matching producer alias can express it; it +is never widened silently. PowerShell Gallery and NuGet consumers can use their +supported native bounds without producer aliases. When a field accepts only +one opaque Git or container reference, a text such as `>=3,<4` is not a range +expression; its bound requires the corresponding controlled alias. Moving references are allowed only for producers inside the consumer's declared trust boundary. Another team is external even when it belongs to the same @@ -528,6 +532,8 @@ Repositories keep the existing MSX configuration file: .github/release.config.yml ``` +### Configuration surface + The canonical settings surface is: ```yaml diff --git a/src/docs/Capabilities/release-management/spec.md b/src/docs/Capabilities/release-management/spec.md index 30d10bcc..52e795f8 100644 --- a/src/docs/Capabilities/release-management/spec.md +++ b/src/docs/Capabilities/release-management/spec.md @@ -373,6 +373,8 @@ consumer-change evidence, and maintainer evidence under [PR Format](../../Ways-of-Working/PR-Format.md), or equivalent reviewed aggregate context for a manual release. +#### Release evidence + The complete description MUST contain exactly one announcement boundary after its leading summary. Each result MUST explain what changed, why, affected supported uses, compatibility, exact adoption actions with prerequisites, @@ -492,10 +494,12 @@ A consumer MAY select exactly one of these policies: | `lock-immutable-fingerprint` | No automatic movement from one exact content identity. | When no policy is selected, the consumer MUST use the most immutable reference -available. A boundary policy MUST be available only when the producer and target -publish the corresponding major or minor alias. Where the consumer syntax -accepts no version range, the producer alias carries that bound; a range-like -string MUST NOT be treated as a resolver expression. +available. A boundary policy MUST use a supported native version constraint or, +when the consumer syntax has no range resolver, the corresponding producer +major or minor alias. A target with native bounded ranges MUST NOT require a +moving alias merely to express that bound. Resolve and retain the immutable +reference required by the trust policy. A range-like string in an opaque Git or +container reference field MUST NOT be treated as a resolver expression. Mutable aliases MAY be used only within the consumer's permitted trust boundary. An external producer, including one owned by another team in the same company, @@ -508,11 +512,20 @@ by the trust boundary. ```gherkin Scenario: An unsupported boundary policy fails explicitly Given a consumer requests lock-minor-boundary + And its consumer field has no native range resolver And the producer does not publish the minor alias family When the policy is resolved Then the request fails as unsupported And it is not widened to latest or a major boundary +Scenario: A native bounded range does not require an alias + Given a consumer requests lock-minor-boundary + And its target supports a native minor-bounded range + And the producer publishes no minor alias + When the policy is resolved + Then the supported native range supplies the bound + And the selected version is retained with the immutable reference required by trust policy + Scenario: An external producer remains immutable Given a consumer selects latest for a producer outside its trust boundary When the current release is discovered diff --git a/src/docs/Capabilities/vscode-extension-framework/design.md b/src/docs/Capabilities/vscode-extension-framework/design.md index 05a266c2..68939422 100644 --- a/src/docs/Capabilities/vscode-extension-framework/design.md +++ b/src/docs/Capabilities/vscode-extension-framework/design.md @@ -117,8 +117,26 @@ VSIX artifact — this framework does not re-implement it: - A prerelease is requested by `release:prerelease` with a resolved bump on an open pull request (or by a prerelease branch), producing a prerelease VSIX that is never promoted to latest. When such a build is also published to the - VS Code Marketplace, it goes out with `@vscode/vsce publish --pre-release` and - an odd minor-version number, the Marketplace's pre-release-channel convention. + VS Code Marketplace, its native prerelease flag and declared native version + mapping must agree with the canonical identity. + +### Marketplace version mapping + +The adapter declares stable and prerelease numeric-version mappings together +before Marketplace publication is enabled. The Marketplace accepts a three-part +numeric version and a separate prerelease flag, not an arbitrary canonical +SemVer suffix. No direct stable mapping plus an independently invented +prerelease mapping is assumed. + +The producer's mapping contract must identify supported canonical identities, +reserve distinct native coordinates, define series/counter allocation, and +prove collision-free stable/prerelease publication and retry behavior. An +odd-minor convention applies only when the stable mapping reserves that space; +it is not a universal conversion for arbitrary stable minor versions. Record +both identities with immutable producer and artifact evidence. Unsupported +mappings and collisions fail before build/publication rather than silently +changing a version or channel. The GitHub VSIX path does not require Marketplace +publication, but an enabled required target is not silently skipped. ## Publishing and distribution diff --git a/src/docs/Capabilities/vscode-extension-framework/spec.md b/src/docs/Capabilities/vscode-extension-framework/spec.md index 544cae01..3b13fa60 100644 --- a/src/docs/Capabilities/vscode-extension-framework/spec.md +++ b/src/docs/Capabilities/vscode-extension-framework/spec.md @@ -25,7 +25,7 @@ extension inherits a working build-test-release path on day one. This capability rests on the [Principles](../../Ways-of-Working/Principles/index.md): - **[Everything as Code](../../Ways-of-Working/Principles/Engineering-Practices.md#everything-as-code).** The pipeline, the version decision, and the extension's configuration are version-controlled workflow and settings — never a GUI action or a hand-run packaging command. -- **[Decision before change](../../Ways-of-Working/Principles/AI-First-Development.md#decision-before-change).** The pull request is the decision point; its review gate approves the code *and* the release it produces. An owned bump label supplies the level or overrides a configured repository default; the effective decision and its source are recorded. +- **[Decision before change](../../Ways-of-Working/Principles/AI-First-Development.md#decision-before-change).** The pull request is the decision point; its review gate approves the code *and* the release it produces. An owned bump label overrides the valid effective default, including shared policy and supported caller inputs; the decision and its source are recorded. - **[Extensible by default](../../Ways-of-Working/Principles/Software-Design.md#extensible-by-default).** The lifecycle is the stable core; host versions, the operating-system matrix, and publish targets are extension-specific settings that slot in. A new publish destination is a configured step, not a new pipeline. - **[Least-privilege](../../Ways-of-Working/Principles/Purpose-and-Direction.md#least-privilege).** The pipeline runs read-only by default; only the stage that cuts the release holds write, and only the scope it needs. @@ -74,7 +74,7 @@ framework itself. - Creating a repository from the template and providing a valid release decision yields a green build, a passing test run, and a packaged VSIX with no extension-specific configuration written. - An eligible pull request merged to a release branch produces a GitHub Release carrying an installable VSIX whose version matches the explicit or default bump. Omitting a bump label uses the valid effective default; invalid settings and conflicting owned labels fail required CI before merge. - The tests that gate the release exercise the exact VSIX that is released, on every supported host version and operating system. -- A documentation-only or CI-only change carrying `release:skip` runs its checks but produces no new version. +- On a managed VSIX route, a change outside the artifact/consumer scope carrying `release:skip` runs its checks without publication. An unmanaged route has no release metadata or labels. - A user installs any released version straight from its GitHub Release with no marketplace account; where marketplace publishing is enabled, that same version also appears in the marketplace. - An open pull request can publish a prerelease VSIX for testing that never becomes the latest stable version, and it is cleaned up when the pull request closes. - Adopting the framework in a new extension is a short caller plus a settings file — the pipeline itself is never copied into the repository. diff --git a/src/docs/Coding-Standards/Dependencies.md b/src/docs/Coding-Standards/Dependencies.md index 8d106dec..bc83265c 100644 --- a/src/docs/Coding-Standards/Dependencies.md +++ b/src/docs/Coding-Standards/Dependencies.md @@ -44,7 +44,7 @@ The resolution is not to pick a point and freeze — it is to **control integrit 1. **Pin tightly by default** — an identity pin plus a deliberate version, or a lockfile — so every build is reproducible and nothing changes unvetted. A controlled owned-major tag is the narrow exception for automation whose release path the organization or initiative operates. 2. **Automate updates** so currency never depends on a human watching upstream: the [Dependency Updates](../Capabilities/dependency-updates/index.md) bot opens one reviewed pull request per bump. -3. **Gate every update through CI and review** — every update passes the repository's normal merge policy; security advisories are raised out of band and prioritized. After related changes are collected, decide the repository release bump under [Release Management](../Capabilities/release-management/design.md). +3. **Gate every update through CI and review** — every update passes the repository's normal merge policy; security advisories are raised out of band and prioritized. After related changes are collected, resolve the repository release decision under [Release Management](../Capabilities/release-management/design.md) when the target route invokes it. Tight pinning is safe *because* the updates are automated: the bot closes the currency gap and CI plus review close the vetting gap. A controlled owned-major tag applies the same principle at the producer: compatible releases pass the controlled release gate once, then the major pointer rolls them out centrally. It trades consumer-level reproducibility for coordinated rollout and is never valid for an external dependency. diff --git a/src/docs/Coding-Standards/GitHub-Actions.md b/src/docs/Coding-Standards/GitHub-Actions.md index c3411f50..192895c8 100644 --- a/src/docs/Coding-Standards/GitHub-Actions.md +++ b/src/docs/Coding-Standards/GitHub-Actions.md @@ -73,7 +73,8 @@ a fleet of pin-update pull requests. version comment. - **Apply the updater's default three-day cooldown** before adopting a freshly published version. Omit an explicit `cooldown` mapping unless the repository deliberately adopts a non-default duration. - **Make the release decision separately** after dependency changes are - collected, under [Release Management](../Capabilities/release-management/design.md). + collected when the target route invokes [Release + Management](../Capabilities/release-management/design.md). - **Publish owned floating major tags only through controlled release automation.** The release gate validates compatibility, publishes the immutable version tag first, and then advances the major tag to that stable release. diff --git a/src/docs/Coding-Standards/Natural-Language.md b/src/docs/Coding-Standards/Natural-Language.md index a14101b8..2883689b 100644 --- a/src/docs/Coding-Standards/Natural-Language.md +++ b/src/docs/Coding-Standards/Natural-Language.md @@ -33,7 +33,7 @@ The split is per artifact, not per repository. A repository that serves a Norweg | `scripts/Test-Link.mjs` | `scripts/Test-Lenker.mjs` | | `Update-Source.ps1 -Offline` | `Update-Source.ps1 -Frakoblet` | | `Source not found: ` | `Kilden finnes ikke: ` | -| `🪲 [Fix]: Broken links no longer reach main` | `🪲 [Fix]: Brutte lenker stoppes` | +| `Broken links no longer reach main` | `Brutte lenker stoppes` | Repository artifacts are read by contributors, reviewers, and agents who do not share one first language, and by tooling built for English. Mixed-language automation splinters the vocabulary — `-Frakoblet` and `-Offline` are the same switch — and makes shared standards, linters, and scripts unreusable across repositories. @@ -76,7 +76,7 @@ Prefer specific, observable language over vague intent. | Prefer | Avoid | | --- | --- | | The workflow fails when the release decision is missing. | There may be some issues with labels. | -| Add `release:skip` to documentation-only PRs. | Make sure docs PRs are handled correctly. | +| On a release-managed route, add `release:skip` when documentation does not affect the artifact. | Make sure docs PRs are handled correctly. | | The agent reads `AGENTS.md` before editing files. | The agent should probably look at the instructions. | Use **MUST**, **SHOULD**, and **MAY** only when a sentence is intentionally normative. If a rule is optional, say what trade-off decides it. @@ -169,10 +169,11 @@ PR titles and descriptions are written for the user of the change first, then th | Prefer | Avoid | | --- | --- | -| `📖 [Docs]: Agentic development framework documented` | `Update framework docs` | +| `Agentic development guidance defines the framework` | `Update framework docs` | | `Agents segment project context before loading standards.` | `Refactor AGENTS.md instructions.` | -Technical implementation details belong in a clearly named technical section at the bottom of the PR body. +Technical implementation details belong in the `Technical details` block for +the reader-facing result they support. ## Prompts diff --git a/src/docs/Ways-of-Working/Automation-Labels.md b/src/docs/Ways-of-Working/Automation-Labels.md index 8f2cd333..fd3b4439 100644 --- a/src/docs/Ways-of-Working/Automation-Labels.md +++ b/src/docs/Ways-of-Working/Automation-Labels.md @@ -53,32 +53,27 @@ namespaced, including the release set: | `release:patch` | Publish a patch release. | | `release:minor` | Publish a minor release. | | `release:major` | Publish a major release. | -| `release:prerelease` | Publish a prerelease from the open pull request using the resolved bump. | +| `release:prerelease` | Publish a prerelease from the open pull request. | | `release:skip` | Validate the change without publishing a release. | -The owned set is exactly these five labels. It applies only on managed release -routes, including native producer pipelines. Unmanaged routes omit every -`release:*` label; absence of `.github/release.config.yml` does not determine -applicability. +This set applies only when the pull request's target route invokes Release +Management, including through a native producer pipeline. An unmanaged route +does not apply or report any +`release:*` label, including `release:skip`. The optional +`.github/release.config.yml` file refines an invocation; its absence alone does +not determine whether the route invokes the capability. These labels are read by [release management](../Capabilities/release-management/spec.md) and by nothing else. -One owned bump label overrides the valid effective `DefaultBump`; without one, -documented defaults, repository settings, and supported caller inputs supply the -level. `release:skip` records a no-release decision. `release:prerelease` uses -the resolved bump and never combines with skip. Multiple bumps and skip with -another owned release label fail. Release-candidate routing and announcement -delivery are supported settings, not additional labels. - -Release Management owns the -[resolver and required pre-merge validation](../Capabilities/release-management/design.md#version-computation). -Omitted settings inherit the documented patch default; invalid supplied -settings and conflicting owned labels fail rather than select a fallback. -[Producer conformance](../Capabilities/release-management/design.md#intended-and-implemented-behavior) -requires the actual immutable producer revision's mapping to be verified before -canonical signals are used. A differing interface needs a verified adapter or -producer/configuration migration; an unsupported signal is never a successful -ignored skip. +One owned bump label records an explicit level and overrides the valid effective +`DefaultBump`; without a bump label, documented defaults, repository settings, +and supported caller overrides supply it. `release:skip` records a no-release decision. +`release:prerelease` is a mode used with a resolved explicit or default bump, +never with `release:skip`. Release Management owns the +[resolver and required pre-merge validation](../Capabilities/release-management/design.md#version-computation); +an omitted setting inherits the documented patch default, while invalid settings +and conflicting owned labels fail rather than select a fallback. Settings, not +additional release labels, select configured release-candidate and announcement behavior. Reserving bare words would be weaker because it depends on a documented prohibition rather than making ownership visible in the label itself. diff --git a/src/docs/Ways-of-Working/Branching-and-Merging.md b/src/docs/Ways-of-Working/Branching-and-Merging.md index cc2bdf6a..b71c1d62 100644 --- a/src/docs/Ways-of-Working/Branching-and-Merging.md +++ b/src/docs/Ways-of-Working/Branching-and-Merging.md @@ -35,7 +35,7 @@ Every layer follows the ordinary [Contribution Workflow](Contribution-Workflow.m 1. **Plan the dependency.** Give each layer its own Task or Bug issue. Add a native blocked-by edge from every dependent leaf to its prerequisite as described in [Issue Relationships](Issues/Process/Relationships.md#execution-order); prose, sub-issue order, and stack position do not create the gate. 2. **Open every layer as a draft.** After the initial commit, push the branch and open its pull request immediately. Use the standard user-facing title and description from [PR Format](PR-Format.md); do not add stack position or an internal branch name to the title. -3. **Link the stack in Technical Details.** Add fully qualified pull request links for the immediate dependency and dependent, using `Depends on Owner/Repo#N` and `Followed by Owner/Repo#N`. Each pull request closes only its own Task or Bug. +3. **Link the stack in Related references.** Add fully qualified pull request links for the immediate dependency and dependent to the applicable section's `Related references` block, using `Depends on Owner/Repo#N` and `Followed by Owner/Repo#N`. Each pull request closes only its own Task or Bug. 4. **Keep each delta isolated.** The pull request diff against its current base contains only that layer's change. Run its tests, checks, and automated review even when an earlier layer already exercised the combined code. 5. **Make one layer ready at a time.** Only the lowest unmerged layer is marked ready and given auto-merge. Every later layer stays draft, even when its current checks are green. 6. **Advance after merge.** When the lowest layer lands, refresh the next branch against the landed target, retarget its pull request to that target, and verify that the diff still contains only its intended change. Run CI and the automated review loop again before marking it ready. @@ -59,7 +59,7 @@ A repository on the promotion model MAY keep a **standing draft pull request** f - **One long-lived pull request, not one per promotion.** Merging it promotes; a new draft opens immediately, so the candidate view is never absent. - **Draft is the resting state.** It is marked ready when the integrated state is deemed promotable, which is what turns review and any promotion gate on. - **Its description is the promotion note.** Assembled from the changes it carries, it is the record of what a promotion contained, written for whoever operates the destination. -- **Its resolved release decision determines the production version.** Promotion is a release like any other, so the level comes from this pull request's explicit bump label or the configured repository default, not from the versions of the changes it bundles ([release management](../Capabilities/release-management/spec.md)). +- **Its release metadata follows the target route.** When the route invokes [Release Management](../Capabilities/release-management/spec.md), the pull request's `Release decisions` block records the production decision and the level comes from its explicit owned bump label or the valid effective `DefaultBump`, including shared defaults, repository settings, and supported caller overrides, not from the versions of the changes it bundles. A route without that invocation omits the block and all `release:*` labels. The value is continuous visibility: at any moment, the difference between what is integrated and what is live is one link. It suits repositories where promotion is a deliberate, gated event and costs more than it returns where every merge already ships. diff --git a/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md b/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md index aaa74329..2a90765b 100644 --- a/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md +++ b/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md @@ -90,10 +90,11 @@ Several signals suggest what kind of change a pull request contains: the shape o diff, whether tests were added or changed, the commit messages, and an AI-assisted reading of the change. Those signals MUST be treated as input. The [resolved release decision](../Capabilities/release-management/design.md#version-computation) -comes from an explicit owned label or the repository's configured default, and +comes from an explicit owned bump label or the valid effective `DefaultBump`, +including shared defaults, repository settings and supported caller overrides, and its suitability for the audience is reviewed at the pull-request gate. -A configured default is a prior policy decision, not an omission to interpret +A documented effective default is a prior policy decision, not an omission to interpret later. The pull request records the effective level and its source, and review confirms that the level fits the declared user/integrator impact. A missing decision fails a required CI check and blocks merge; publication diff --git a/src/docs/Ways-of-Working/Contribution-Workflow.md b/src/docs/Ways-of-Working/Contribution-Workflow.md index 9809968a..1cd8f4e9 100644 --- a/src/docs/Ways-of-Working/Contribution-Workflow.md +++ b/src/docs/Ways-of-Working/Contribution-Workflow.md @@ -34,10 +34,15 @@ flowchart TD that delivery issue and the pull request, not in the spec, design, or parent aggregate. 2. **Open the pull request as a draft.** A draft attaches CI and keeps the change - out of people's review queues while you iterate. + out of people's review queues while you iterate. Assign the pull request to + its author and apply any repository-owned workflow labels. 3. **Run the Copilot review loop** (below) until Copilot reports a clean round — no changes requested and no new inline comments. -4. **Mark the pull request ready for review** once it meets the +4. **Finalize and mark the pull request ready for review.** Re-read the complete + diff and finalize the title and description per [PR Format](PR-Format.md). + If the target route invokes Release Management, reconcile the conditional + decision block and `release:*` labels with its effective configuration. If it + does not, omit both. Then confirm the [Definition of Ready for Review](Definition-of-Ready-and-Done.md#definition-of-ready-for-review). 5. **Enable auto-merge** so the change lands automatically when human review approves and the required checks stay green. Human review takes over from there. @@ -121,7 +126,8 @@ the approval identity that satisfies the gate. - [Workflow](Workflow.md) — the spec-led loop this operates within. - [Issue Lifecycle](Issues/Process/Lifecycle.md) — why only ready Task and Bug leaves enter this flow. -- [PR Format](PR-Format.md) — the pull request title, description, and labels. +- [PR Format](PR-Format.md) — the pull request title, description, and + route-conditional release metadata. - [Definition of Ready and Done](Definition-of-Ready-and-Done.md#definition-of-ready-for-review) — the readiness gate this hands off at. - [Branching and Merging](Branching-and-Merging.md) — the branch model a pull request builds on. - [Review Etiquette](Review-Etiquette.md) — how human review proceeds once the pull request is ready. diff --git a/src/docs/Ways-of-Working/Definition-of-Ready-and-Done.md b/src/docs/Ways-of-Working/Definition-of-Ready-and-Done.md index c68b48b2..fe00242d 100644 --- a/src/docs/Ways-of-Working/Definition-of-Ready-and-Done.md +++ b/src/docs/Ways-of-Working/Definition-of-Ready-and-Done.md @@ -33,7 +33,7 @@ A pull request is ready for review when: - The automated review loop has converged — a clean [Copilot round](Contribution-Workflow.md#the-copilot-review-loop) with no unresolved review threads. - The [standards and framework alignment pass](Workflow-Stages/Implement.md#5-standards-and-framework-alignment-pass) has run against the finished change, its result covers every changed surface in the pull request, and every exception links a follow-up issue. - The [issue convergence sweep](Workflow-Stages/Implement.md#6-issue-convergence-sweep) has run against scoped open issues, and every fully convergent issue is linked in the pull request with a closing keyword. -- The title, release-note description, and effective release decision and its source are finalized per [PR Format](PR-Format.md). Where Release Management applies, its [required decision check](../Capabilities/release-management/design.md#required-pre-merge-decision-check) passes; an explicit label is not mandatory when a valid configured default supplies the level. +- The title and release-note-ready description are finalized per [PR Format](PR-Format.md). When the target route invokes Release Management, the `Release decisions` block, effective configuration, and applied `release:*` labels agree, and the [required decision check](../Capabilities/release-management/design.md#required-pre-merge-decision-check) passes; an explicit bump label is not mandatory when the valid effective default supplies the level, including supported caller overrides. When the route does not invoke Release Management, the block and labels are absent. Absent checks are not a pass. When a pull request reports no checks at all, the usual cause is that the workflow's triggers do not cover it — a base branch outside the `pull_request` trigger's `branches` filter is the common one — and that is a gap to fix or file, not a gate to wave through. Manually dispatching the workflow against the branch does not substitute for it either: jobs gated on the event type are skipped silently, so a green `workflow_dispatch` run can hide verification that never ran. If the checks genuinely cannot be made to run before merge, say so in the pull request and link the issue tracking it, so the reviewer knows the gate was not met instead of assuming it was. diff --git a/src/docs/Ways-of-Working/Documentation-Model.md b/src/docs/Ways-of-Working/Documentation-Model.md index 6f53dbb8..9bd9c2c6 100644 --- a/src/docs/Ways-of-Working/Documentation-Model.md +++ b/src/docs/Ways-of-Working/Documentation-Model.md @@ -105,6 +105,7 @@ with no reader, so a folder appears the first time it has something to hold | **How the work is done** — process, principles, conventions | [Ways of Working](index.md) | | **How code looks** — style applied to code | [Coding Standards](../Coding-Standards/index.md) | | **How this one change is implemented** — paths, trade-offs | the Task or Bug delivery leaf and its PR; see [Issue Planning](Issues/Process/Planning.md) | +| **What a release changes, why, and how consumers align** | its source-bound release record, authored in the release-bound PR; see [PR Format](PR-Format.md) | Keeping implementation out of the spec is what makes the spec durable: implementation detail rots fastest, so the spec leaves it to the design, the @@ -149,8 +150,9 @@ history records what changed; the document records only what is true now. trusts any line as the current contract. - **Normative.** Requirements use MUST / SHOULD / MAY so obligations are unambiguous. -- **No status, deltas, phasing, or open questions.** Those rot the moment they - are written; they belong in issues, PRs, and git history. +- **No status, deltas, phasing, or open questions.** Delivery plans belong in + issues and PRs; release-specific changes and adoption instructions belong in + release records. - **Measurable success criteria.** A spec states outcomes a reader can verify — *"a repository list returns every repository by default, with no silent truncation"* — never *"the sync is fast."* @@ -160,6 +162,27 @@ requirement testable, are criteria measurable and implementation-free, is it present-tense and free of status? — applied in the reviewer's head and the PR ([4-eyes](Principles/AI-First-Development.md#4-eyes-or-n-eyes-principle)), leaving no artifact behind. +### Current product guidance and release history + +Resource docs, including READMEs, specs, designs, implementation docs, guides, +and references, describe supported target-state behavior and usage for their +readers. Update them in place as that contract changes. Keep release-specific +old-to-new transitions, migration instructions, and change history in the +[release records](../Capabilities/release-management/design.md#release-notes), +not a parallel history file or migration-guide hierarchy. + +Release notes explain what changed, why, who is affected, compatibility, and +exact applicable adoption actions or an explicit no-action result. Reading all +applicable records after the actual consumed baseline through the target is +sufficient to compose the required upgrade actions; PRs and diffs provide +optional depth. General upgrade procedures may explain how to use those +records, without becoming another source of release-specific instructions. + +Decision records and research retain their distinct purposes: decisions preserve +the choices, rationale, and supersession links, while research preserves +point-in-time findings. Keeping resource docs evergreen does not erase these +records. + ## Concise by default Respect the reader's attention — human or agent. A document earns nothing by diff --git a/src/docs/Ways-of-Working/Fleet-Orchestration.md b/src/docs/Ways-of-Working/Fleet-Orchestration.md index ed34da61..4ad9f611 100644 --- a/src/docs/Ways-of-Working/Fleet-Orchestration.md +++ b/src/docs/Ways-of-Working/Fleet-Orchestration.md @@ -36,10 +36,13 @@ tool, can read and drive a campaign with the GitHub CLI alone. A campaign is one change rolled out across a set of repositories. Each repository's slice is one Task or Bug delivery leaf and its pull request. A campaign has a short, stable **slug** (for example `process-psmodule-v6`) that -names both artifacts everywhere. +prefixes every delivery issue. A campaign pull request carries that identity +through its native Development link to the prefixed issue, leaving the pull +request title free for its reader-facing result. A closing keyword creates that +link only when the pull request targets the repository's default branch. An **existing open pull request can be adopted** when its scope matches the -campaign slice. Ensure it closes exactly one correctly typed Task or Bug, +campaign slice. Link it to exactly one correctly typed Task or Bug, creating that delivery issue first when it is missing, then add the remaining change to the existing branch instead of opening a duplicate. Reusing what is already open avoids competing pull requests without bypassing the canonical @@ -65,18 +68,34 @@ copied into another state-bearing field, because duplicated state drifts. | Review outcome | `reviewDecision` and unresolved review threads | | Mergeability | `mergeable` / merge-state status | | Done | pull request **merged**; Task or Bug **closed** | -| Issue ↔ PR link | the pull request's one closing reference | +| Issue ↔ PR link | the native Development link; a supported default-branch closing reference or an explicit manual link | -"Ready for review" is the draft flag flipping off; "done" is the merge. The two -signals people care about most are native, and are set by the same act that does -the work — [marking ready](Contribution-Workflow.md) and merging. +"Ready for review" is the draft flag flipping off; "Merged" is the pull request's +merge state. Delivery completion also requires the Task or Bug to close after +its recorded Done gate. These are native signals, not copied stage fields. -### Campaign identity lives in the title +### Campaign identity lives on the delivery issue Campaign membership is carried in a stable square-bracket prefix on every -delivery issue and pull request title, for example `[process-psmodule-v6]`. The -prefix is the cross-repository join key; labels stay reserved for mutable -workflow state. +delivery issue title, for example `[shared-workflow-alignment]`. Each campaign +pull request is natively linked to exactly one of those issues, so the +Development relationship joins it to the campaign without copying internal metadata into +its title. Labels stay reserved for mutable workflow state. + +### Link and close for the actual target + +For a default-branch target, use the scoped closing reference from [PR +Format](PR-Format.md). For a non-default target, explicitly link the pull request +and delivery issue through GitHub's **Development** sidebar and verify the native +link; description closing keywords are ignored on those targets. See +[GitHub's linking rules](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue). + +A non-default merge does not close the issue automatically. Keep the delivery +issue open until its recorded [Definition of Done](Definition-of-Ready-and-Done.md#repository-delivery-leaf) +holds, including any required default-branch integration or publication. The +recorded completion owner then verifies the evidence and closes it explicitly, +or links the completed delivery to a qualifying default-branch integration PR. +Never close it merely to make the dashboard show Done. ### Process labels fill the gap @@ -91,11 +110,13 @@ same way. | `stage:in-progress` | Actively being changed; the assignee owns it. | | `stage:blocked` | Needs a human decision or a manual, off-platform action before it can proceed. | -Rules: the campaign prefix is mandatory on every delivery issue and pull request; at most one -`stage:*` label applies at a time; and `stage:*` may be dropped once a pull -request carries the signal itself (a ready pull request needs no `stage` label, -but `stage:blocked` stays explicit because "a human must act" has no built-in -equivalent). The slug inside the prefix is lowercase and hyphenated. +Rules: the campaign prefix is mandatory on every delivery issue; each campaign +pull request is natively linked to one prefixed issue and uses the reader-facing title from [PR +Format](PR-Format.md) without the prefix; at most one `stage:*` label applies at +a time; and `stage:*` may be dropped once a pull request carries the signal +itself (a ready pull request needs no `stage` label, but `stage:blocked` stays +explicit because "a human must act" has no built-in equivalent). The slug inside +the issue prefix is lowercase and hyphenated. ## Effective status @@ -135,21 +156,22 @@ flowchart TD ``` 1. **Queue the work.** Create one Task or Bug delivery issue per repository, with - the campaign prefix in the title and `stage:queued`. Route it through the - [Issue Hierarchy](Issues/Types/Hierarchy.md) and follow its canonical type - page. The whole fleet starts as *Queued*. + the campaign prefix in the title and `stage:queued`. Route it through the + [Issue Hierarchy](Issues/Types/Hierarchy.md) and follow its canonical type + page. The whole fleet starts as *Queued*. 2. **Branch and open a draft.** Create a worktree and branch - ([Git Worktrees](Git-Worktrees.md)), then open a **draft** pull request that - closes exactly that delivery issue, per [PR Format](PR-Format.md). Use the same - campaign prefix in the pull request title and move the stage to - `stage:in-progress`, clearing the issue's `stage:queued` so the repository - delivery never carries two stages at once. If the repository already has an open - pull request that covers part of the change, adopt it instead of opening a - new one: add the remaining change to its branch, return it to **draft** while - work is in progress, and give it the same campaign prefix and - `stage:in-progress` label (clearing `stage:*` from its closing issue). Add the - one closing Task or Bug reference before continuing if the adopted pull - request did not already have it. + ([Git Worktrees](Git-Worktrees.md)), then open a **draft** pull request natively + linked to exactly that prefixed delivery issue, per [PR Format](PR-Format.md) + and the target-specific linking rules above. + The Development link carries campaign membership, so the pull request title + states only its reader-facing result. Move the stage to `stage:in-progress`, + clearing the issue's `stage:queued` so the repository delivery never carries + two stages at once. If the repository already has an open pull request that + covers part of the change, adopt it instead of opening a new one: add the + remaining change to its branch, return it to **draft** while work is in + progress, and give it `stage:in-progress` (clearing `stage:*` from its delivery + issue). Verify its native link to the prefixed Task or Bug before continuing + if the adopted pull request did not already have one. 3. **Apply the change and run the loop.** Make the change and take the pull request through the [Contribution Workflow](Contribution-Workflow.md) — the Copilot review loop — exactly as any single-repository change. The @@ -162,8 +184,9 @@ flowchart TD and CI is green, mark the pull request ready for review per the [Definition of Ready and Done](Definition-of-Ready-and-Done.md). The draft flag flips and the repository delivery becomes *Ready for review*. -6. **Human review and merge land it.** Merging lands the change and closes its - Task or Bug through the pull request's one closing reference. +6. **Human review and merge land it.** Merging lands the change. A qualifying + default-branch closing reference closes its Task or Bug automatically; + non-default delivery follows the recorded completion and closure rules above. The campaign's job is to get every pull request to *Ready*; [Branching and Merging](Branching-and-Merging.md) governs how it merges. @@ -215,10 +238,16 @@ identical diff. A campaign is watched through a **dashboard** — a deterministic projection of GitHub state, not a store of its own. A script enumerates the campaign's -repository deliveries by title prefix (`[]` across the owners), reads each pull request's -built-in properties, computes the effective status, and renders a page. It can -regenerate on an interval so the view refreshes as GitHub changes; deleting it -loses nothing, because GitHub is the source of truth. +delivery issues by title prefix (`[]` across the owners), follows each +native Development link to its pull request, reads the built-in properties, +computes the effective status, and renders a page. It can regenerate on an +interval so the view refreshes as GitHub changes; deleting it loses nothing, +because GitHub is the source of truth. + +Read linked pull requests with full pagination and include closed or merged +ones. Verify explicit links for non-default targets rather than reconstructing +them from ignored keywords. A missing or unreadable link on an in-progress +delivery is a discovery gap to report, not an empty or completed delivery. Typical columns: effective status, repository, delivery issue and pull request, draft/ready, CI, review decision and open-thread count, assignee, the latest progress note, @@ -244,11 +273,12 @@ a deterministic label-and-comment write, so it is scripted; the judgement of Because all state is on GitHub and the workflow labels are generic: - **A person** can run a whole campaign from the GitHub UI — filter by - the campaign prefix in the title, read each pull request's draft and merge state, move - `stage:*` labels, and merge. + the campaign prefix in delivery issue titles, follow each issue's linked pull + request, read its draft and merge state, move `stage:*` labels, and merge. - **An automated system** — a scheduled workflow, a different agent framework, or - a teammate's tooling — can enumerate the work with one query and pick up any - delivery. The state is portable and self-describing. + a teammate's tooling — can enumerate the issues with one query, follow their + native pull request references, and pick up any delivery. The state is + portable and self-describing. If an automated run stops midway, nothing is lost: the board is complete, every in-flight pull request shows its true state, and anyone can finish the job. This @@ -261,9 +291,24 @@ hand. Labels and comments use the issues API, which serves issues and pull requests alike. ```powershell -# enumerate a campaign's pull requests across an owner -gh search prs 'in:title "[]"' --owner ` - --json number,repository,title,url,isDraft,state +# enumerate a campaign's delivery issues across an owner +gh search issues 'in:title "[]"' --owner ` + --json number,repository,title,url,state + +# follow native issue links, including closed/merged PRs, with full pagination +$query = @' +query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) { + repository(owner: $owner, name: $repo) { + issue(number: $number) { + closedByPullRequestsReferences(first: 100, after: $endCursor, includeClosedPrs: true) { + nodes { number url state } + pageInfo { hasNextPage endCursor } + } + } + } +} +'@ +gh api graphql --paginate -f query="$query" -f owner='' -f repo='' -F number='' # read one pull request's authoritative state gh pr view --repo / --json ` @@ -278,26 +323,30 @@ gh api -X POST repos///issues//comments -f body="" gh pr ready --repo / ``` -## Worked example: Process-PSModule and Pester 6 +## Worked example: A shared workflow upgrade -A concrete campaign from the [PSModule](../Initiatives/PSModule.md) initiative: -adopt the latest Process-PSModule reusable workflow across every consumer, add -the Pester version requirement to the test files, and migrate the tests. +A campaign aligns consumers with one fixed producer release. Its release records +own the version-specific migration actions; this general procedure does not +invent or duplicate them. -- **Slug:** `process-psmodule-v6`. +- **Slug:** `shared-workflow-alignment`. - **Discover the fleet:** find consumers of the reusable workflow with a code search for its `uses:` reference, then queue a Task delivery issue in each. -- **Per repository:** bump the workflow pin, add the - `#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' }` - requirement to each `*.Tests.ps1`, migrate the tests, and take the pull request - through the [Contribution Workflow](Contribution-Workflow.md). -- **Track it:** every issue and pull request starts with `[process-psmodule-v6]`; - the dashboard shows the fleet advancing from *Queued* to *Merged*. +- **Per repository:** establish its actual consumed baseline and fixed target, + read every applicable source-bound release record, compose the required + actions and intermediate operations, preserve local intent, and verify the + result with its existing checks. A required instruction missing from the + records blocks that delivery. +- **Track it:** every delivery issue starts with `[shared-workflow-alignment]`; + each pull request uses a reader-facing title and a verified native issue link. + Default-branch closing keywords and explicit non-default linking follow the + target-specific rules above. The dashboard retains both live and merged PRs. ## What this is not - **Not a database.** Any `JSON` or `HTML` is a disposable projection of GitHub. - **Not agent-specific.** The model stays fully operable by people and non-agent tools; nothing in it depends on a particular assistant. -- **Not a shared label store.** Labels are per-repository; the campaign title - prefix is the shared contract, created in each participating repository. +- **Not a shared label store.** Labels are per-repository; the delivery-issue + prefix plus the native Development link is the shared contract in each + participating repository. diff --git a/src/docs/Ways-of-Working/PR-Format.md b/src/docs/Ways-of-Working/PR-Format.md index 028fc544..ffb444bd 100644 --- a/src/docs/Ways-of-Working/PR-Format.md +++ b/src/docs/Ways-of-Working/PR-Format.md @@ -1,353 +1,640 @@ --- title: PR Format -description: Pull request title, description, change types, and labels. +description: Audience-first pull request titles and descriptions with evidence-based, conditional release decisions. --- # PR Format -Pull requests in the MSX ecosystem double as **release notes**. Write for end users, including downstream integrators: what changes, who is affected, and how to adopt it. Keep consumer instructions distinct from reviewer and maintainer evidence. - -## The source of truth - -The release-bound PR title and complete description are the authored release note. The contract lives in structured Markdown in that body, not a parallel JSON/YAML file or a version-specific migration guide. [Release Management](../Capabilities/release-management/design.md#release-notes) owns publication, resolved release coordinates, provenance, and traceable corrections. - -Describe the **incremental change introduced by this release**, not a migration manual from every previous version. Consumers compose the applicable records across their upgrade range; a note for the newest release does not replace the intervening evidence. - -## Title +A pull request title and description are release-note-ready artifacts. They +explain one complete change to the people who use what the repository delivers, +while carrying the evidence reviewers and maintainers need. + +The release-bound title and complete description author the eventual release +note. Published release records are the consumer's sufficient upgrade history: +what changed, why, who is affected, compatibility, and exactly how to adopt each +release, including an explicit no-action result when applicable. PRs and diffs +provide optional depth, not required instructions missing from the notes. + +Consumers read every applicable release after their actual consumed baseline +through the chosen target in release order and compose the necessary actions. +Reading those records does not require installing every intermediate version; +an intermediate installation or run is required only when a note explicitly +requires it. [Resource documentation](Documentation-Model.md#current-product-guidance-and-release-history) +describes supported target-state behavior and usage, not release-specific +transitions or history. + +This page owns the title and description format. The +[Contribution Workflow](Contribution-Workflow.md) owns draft, assignment, +review, and handoff mechanics; [Branching and Merging](Branching-and-Merging.md) +owns branches, commits, and integration. + +## Analyze before writing + +Write from evidence, not from the branch name, commit messages, or the existing +pull request text. Those surfaces are useful leads, but the complete change is +the source. + +### Identify the readers + +Start with the repository [README audience +declaration](Readme-Driven-Context.md#target-audience), then inspect linked user +documentation, capability specifications, and effective configuration. + +Treat every supported interface as reader-facing when someone depends on it. +Commands, APIs, configuration, reusable workflows, Actions, templates, and +published guidance can all be the product. Do not classify an integration as +internal merely because its readers write scripts or maintain another product. + +For documentation-only work, the delivered result is guidance. State what a +reader can now understand or do; do not present documentation as product +behavior that the change did not implement. + +### Read the whole change + +Inspect the complete base-to-head diff before writing. For a release-bound +record, reconcile the complete delivered change since its identified +release/source baseline, including earlier merged or skipped changes in that +range. A promotion or bundled release must retain every applicable consumer +delta, not just the latest commit or pull request. + +Check claims against the changed public interfaces, documentation, +configuration, tests, and generated output. Commit messages and an earlier pull +request description may be incomplete or stale and never replace this check. + +### Keep claims accurate + +State only outcomes the evidence supports: + +- Describe a dependency update's behavior or security benefit only when upstream + notes, tests, or product evidence establish that result. +- Describe documentation work as changed guidance unless the same change also + changes the documented product. +- Distinguish a public contract change from the internal implementation that + delivers it. +- Check affected supported uses for compatibility, prerequisites, and exact + adoption actions, including required ordering or intermediate operations. +- State an explicit no-action result and its compatibility basis when adoption + needs no consumer change beyond selecting the release reference. +- Treat missing applicability or migration instructions as an evidence gap to + resolve in the note, not a reason to send consumers to PRs, diffs, or + historical product docs. + +### Resolve release decisions + +Before adding release metadata or changing a `release:*` label, determine +whether the repository invokes [Release +Management](../Capabilities/release-management/spec.md) for the pull request's +target route. Inspect the effective pipeline and its inputs, including native +producer pipelines that publish versioned artifacts without calling a named +shared workflow. The [applicability contract](../Capabilities/release-management/design.md#applicability) +is about the route's release behavior, not one implementation. The optional +`.github/release.config.yml` file refines the route's settings; its absence alone +does not prove that release management is absent. + +Verify the immutable producer revision's supported settings and owned-label +mapping before using the canonical signals below. A native producer participates +in the contract but does not gain support for those signals from this +documentation alone. If its released interface differs, require a verified +adapter or a producer/configuration migration with complete adoption actions in +that producer's PR/release record. Hold finalization until the effective mapping +and required decision check are verified; do not apply a label the pipeline +ignores, silently translate it, or classify an incompatible producer as unmanaged. + +If the route does not invoke Release Management, omit the entire `Release +decisions` block and do not apply or report any `release:*` label, including +`release:skip`. + +If the route does invoke Release Management, resolve these decisions from the +complete change and the effective +[configuration](../Capabilities/release-management/design.md#configuration-surface): + +1. **Release or skip.** Release when the change affects the versioned artifact + or a supported consumer contract. Otherwise select `release:skip`. +2. **Version bump.** For a release, choose Patch, Minor, or Major from the + compatibility impact. An explicit bump label overrides a valid + effective `DefaultBump`; a matching default supplies the level without a + per-PR bump label. Resolve the documented shared default, repository settings, + and supported caller overrides under + [settings and caller overrides](../Capabilities/release-management/design.md#settings-and-caller-overrides). +3. **Mode.** Record Stable or Prerelease from the target route and any valid + `release:prerelease` override. Identify a configured release-candidate route + in the mode evidence; release candidates are prereleases, not another bump. + +Use only the labels owned by the +[`release:` namespace](Automation-Labels.md#every-set-is-namespaced). Missing, +invalid, or conflicting decisions are errors to resolve before review, not +reasons to invent a fallback. Inheriting the documented patch default is a valid +decision source, not an error recovery path. + +### Select the news + +Keep the summary and named sections focused on results that matter to the +identified readers without omitting a consumer delta or required action. Put +implementation facts, validation, and process evidence in supporting details. +Omit internal facts that neither explain a reader-facing result nor help review +it. + +Internal-only work can still have a clear result, such as a shared automation +configuration. When it has no reader-facing classified section, summarize the +result and put necessary supporting blocks directly after the summary marker. + +### Group related changes + +Group changes by audience-facing result or affected interface, not by commit, +file, issue, or implementation step. One section may describe several files +that jointly deliver one result. Separate unrelated reader outcomes into their +own sections and classify each result once. + +## Write the title + +Use one short statement of the most important user-facing result: ```text - []: +LLM Gateway streaming requests report usage ``` -- The **Icon** matches the change type. -- The **Type** in brackets is one of: `Major`, `Feature` (Minor), `Patch`, `Fix`, `Docs`, `Maintenance`. -- The **outcome** describes what changed from the end user's perspective. Do not lead with private function or class names or refactoring verbs; public commands, inputs, APIs, paths, and settings are consumer-facing concepts. - -### Good titles +For internal-only work, name the operational result: -- `🌟 [Major]: Legacy export command removed` -- `🚀 [Feature]: Custom templates now supported` -- `🩹 [Patch]: Default timeout value corrected` -- `🪲 [Fix]: Parameter validation no longer fails on null input` -- `📖 [Docs]: Installation guide updated with prerequisites` -- `⚙️ [Maintenance]: Internal build tooling stays current` - -### Bad titles - -- `Add support for custom templates` — describes the action, not the outcome. -- `Refactor parameter validation logic` — implementation language. -- `Update stuff` — meaningless. - -## Change types - -| Type | Icon | Label | Description | -| ----------- | ---- | ---------------- | ----------------------------------------------------- | -| Major | 🌟 | `release:major` | Breaking changes that affect compatibility | -| Feature | 🚀 | `release:minor` | New features or enhancements | -| Patch | 🩹 | `release:patch` | Small fixes or improvements | -| Fix | 🪲 | `release:patch` | Bugfixes (patch-level release impact) | -| Docs | 📖 | `release:skip` | Documentation changes only | -| Maintenance | ⚙️ | `release:skip` | Internal upkeep with no change to shipped behavior or integration contracts | +```text +Release automation uses a shared configuration +``` -`release:prerelease` is a release mode, not a change type. It uses one explicit -bump label or the valid effective `DefaultBump` when an open pull request -must publish a prerelease. The mode alone supplies no level. Never combine it -with `release:skip`; [Release Management](../Capabilities/release-management/design.md#version-computation) -owns resolution and validation. +The title must not contain: -Resolve the actual target route before applying release metadata or labels. -Managed routes include native producer pipelines publishing versioned artifacts; -unmanaged routes omit release metadata and every `release:*` label, including -`release:skip`. The documented shared default, repository settings, and supported -caller inputs resolve under the shared -[settings contract](../Capabilities/release-management/design.md#settings-and-caller-overrides). -An explicit owned bump label overrides the valid effective default; invalid -supplied settings and conflicting owned signals fail even when another input -supplies a valid level. +- an icon or type prefix; +- a Conventional Commit prefix such as `feat:` or `docs:`; +- an issue reference; +- a list of unrelated changes; +- AI or agent attribution; +- an implementation detail when a reader-facing result is available. -Verify the immutable producer revision's actual supported settings and label -mapping. A differing interface requires a verified adapter or a -producer/configuration migration before canonical signals are used. Its exact -adoption instructions belong in the producer's PR/release record. Missing -support blocks finalization rather than making an ignored label a successful -skip or opting the managed route out. +## Write the description -### Detecting the change type +The description stands on its own for a reader who has not inspected the diff. +Use the following structure. -Decide the type from the change **for the declared target audience**, including its integrators, not from the maintainer's implementation effort or the names of changed files. Read the [audience declaration in the README](Readme-Driven-Context.md#target-audience) and any explicitly adopted initiative definition first. Resolve and record missing or ambiguous audience context before finalizing the type; do not guess it from repository ownership. +### Summarize the result -Assess every affected supported use: commands, parameters, APIs, output shapes, configuration, permissions, installation, and runtime/tool requirements. User and integrator may be the same person, as the [PSModule audience](../Initiatives/PSModule.md#target-audience) illustrates. An interactive command still working does not make a change compatible if the same user's supported script integration breaks. +Start with one or two short paragraphs and no `Summary` heading. Lead with +required action and breaking impact when either exists. A short unordered list +is acceptable only when the change has several distinct result groups that +cannot be stated clearly in prose. -The change type is decided in this order: +Use the vocabulary of the supported interface. Describe what changes, who is +affected, and what they need to do. Keep implementation narration out of the +summary. -1. **Explicit user input** — if the contributor / Shipper specified a type, verify it against the audience impact and applicable version policy. Resolve a conflict before finalizing the release decision; a label does not make a breaking change compatible. -2. **Pre-1.0.0 rule** — projects with no version tags or latest tag below `v1.0.0` follow [SemVer §4](https://semver.org/#spec-item-4). Major is **never** auto-detected for pre-1.0.0 projects. Breaking changes there are classified as Minor (`0.x.0`). -3. **Find the affected consumer contracts** in the branch diff. Paths help locate evidence; they do not determine impact: +### End the shareable summary - | Artifact type | Recognition hints | Consumer contract to inspect | - | --- | --- | --- | - | Library / Module | Source and package manifest | Public commands/APIs, parameters, output shapes, defaults, installation, and supported runtimes. | - | GitHub Action | `action.yml` and its implementation | Inputs, outputs, permissions, execution environment, and behavior. | - | Reusable Workflow | Callable workflows under `.github/workflows/` | Caller inputs, secrets, permissions, configuration, tool requirements, and behavior. | - | Infrastructure module | Module source, variables, and outputs | Variable/output contracts, defaults, provider requirements, and managed-resource behavior. | +End the summary with the exact HTML marker shown in the +[complete template](#copy-the-complete-template). -4. **Classification rules** (apply in order, against those contracts): - 1. **Docs** — documentation-only changes, not a functional change merely stored in a documentation file. - 2. **Maintenance** — internal-only changes with no effect on shipped behavior or supported integration contracts. - 3. **Major** — a supported user or integration contract breaks (pre-1.0.0 auto-detection maps this to Minor). - 4. **Feature (Minor)** — backward-compatible capabilities are added. - 5. **Patch or Fix** — backward-compatible fixes or small improvements. +The marker appears exactly once, on its own line, outside a code fence, and +before the first detailed section. Text before it must remain useful when shared +without the rest of the description. -Use the highest impact across the affected supported contracts, then apply the version policy. A small fix can be breaking; unrelated internal changes or documentation do not lower that impact. +### Explain each reader-facing result -A configured default supplies a release level, not evidence of compatibility. Check it against the audience impact and apply an explicit override when the change requires a different level. +Use these classifiers in this order and omit empty groups: -Illustrative cases, not release history: +1. `## Breaking: ` +2. `## Removed: ` +3. `## New: ` +4. `## Changed: ` +5. `## Fixed: ` -| Change | Audience-based classification | +| Classifier | Use when | | --- | --- | -| Remove a supported `Process-PSModule` caller input | Breaking for module maintainers integrating the workflow, not Maintenance because the edit is under `.github/`. | -| Change a module's supported output shape or raise its minimum PowerShell version | Breaking for PowerShell users and their integrations, even if only a manifest or one line changes. | -| Add an optional module parameter without changing existing calls | Feature (Minor): a compatible capability for the same PowerShell audience. | - -## Description structure +| `Breaking` | A supported consumer must act or an existing supported use becomes incompatible. | +| `Removed` | A supported capability, interface, or documented path is no longer available. | +| `New` | Readers gain a capability, interface, or body of guidance. | +| `Changed` | Existing behavior, configuration, or guidance changes compatibly. | +| `Fixed` | An incorrect behavior or guidance now works as intended. | + +Each section heading states one result, not a component name. Open the section +with one or two prose paragraphs that explain what changes, why, affected +supported uses, compatibility, and exact adoption actions or an explicit +no-action result. Include applicable prerequisites, verification, and ordering +constraints. A later release that supersedes an earlier action explains how +consumers compose the remaining actions through its target; preserve any +required intermediate installation or run. A documentation change uses the +classifier that describes what its guidance now provides. + +### Show interfaces after the prose + +After the opening prose, add an interface example or compact table only when it +makes the reader's action clearer. Do not lead a section with a code block or +table. Include necessary old-to-new examples, before-and-after comparisons, or +diagrams in the note itself when they explain an applicable transition. Keep +release-specific migration details here; evergreen resource docs show supported +usage without accumulating those transitions. + +Link optional usage documentation using an absolute default-branch URL or the +canonical published URL so the link survives when the pull request becomes a +release record. Such links supplement the note; consumers must not need them to +discover required upgrade actions. Never include secret values. + +### Close each section with supporting details + +A named section may end with either or both of these optional blocks, in this +order: -Ordered, top to bottom. +```markdown +
+Technical details -### 1. Leading paragraph — Summary +Implementation and validation evidence for this result. -A concise paragraph describing **what changes for the user**. Present tense, active voice. Never open with implementation language ("Refactored", "Updated class", "Added null checks"). +
-End the leading summary with the single announcement boundary shown in the -example below, on its own line and outside code fences in the actual PR body. -The complete title and description remain the release record; sharing the -summary never truncates the published body. +
+Related references -### 2. User-facing changes — sections with headers +- Resolves MSXOrg/repository#123 +- Depends on MSXOrg/other-repository#456 -Organize by **what the user experiences**, not by what was changed internally. +
+``` -- `## Breaking Changes` — what stopped working or changed incompatibly, regardless of the selected change type. Include pre-1.0 breaking behavior even when the version policy classifies it as Minor. -- `## New: ` — new things the user can do. -- `## Changed: ` — existing behavior that now works differently. -- `## Fixed: ` — problems now resolved. +The blocks are section-scoped. Do not add global catch-all `Technical details` +or `Related references` blocks after several classified sections. If the pull +request is internal-only and has no classified section, place its supporting +blocks directly after the summary marker. + +Put the standards and framework alignment evidence required by +[Implement](Workflow-Stages/Implement.md#5-standards-and-framework-alignment-pass) +in the `Technical details` block for the result it supports. For a +release-managed result, include the applicable consumer, template, and baseline +evidence required by [Release +Management](../Capabilities/release-management/spec.md#release-evidence) in that +same scoped block. Keep the consumer's instructions in the result's prose and +examples; the supporting evidence verifies those instructions rather than +replacing them. + +Record the closing delivery leaf's implementation-plan progress and the +[issue convergence sweep](Workflow-Stages/Implement.md#6-issue-convergence-sweep) +search scope and outcome in that same block, including when no additional issue +converges. For internal-only work without classified sections, the block after +the summary marker carries this evidence and any applicable release evidence. + +Use fully qualified `owner/repository#number` references for every same-instance +GitHub issue or pull request, including references to the current repository. +Use closing keywords only for issues the complete change actually resolves. +Prefix non-closing relationships with terms such as `References`, `Depends on`, +or `Followed by`. Use absolute Markdown links for Jira, cross-instance GitHub, +and references that will render outside GitHub. + +Do not include AI or agent attribution anywhere in the description. + +### Record release decisions only when invoked + +When the target route invokes Release Management, add one `Release decisions` +block after the classified sections and apply the exact labels the block +reports: -Under each header: +```markdown +
+Release decisions -- What the user can now do, or what changed for them. -- Who is affected, including changed public parameters and defaults. -- A link to the release-wide adoption path rather than a second sequence of instructions. -- Examples or code snippets showing new usage. +- **Release:** Yes - the delivered artifact and supported caller contract change. +- **Version bump:** Minor - callers gain a compatible optional input. +- **Mode:** Stable - the target route publishes stable releases. +- **Labels:** `release:minor` -Do **not** include private implementation details or refactoring decisions here. Exact public interface names belong here when users need them to understand or adopt the change. +
+``` -### 3. Adopting this release +For a no-release decision, include only the decision and its label: -Every PR includes `## Adopting this release` before the technical details. Give one ordered, release-wide path for the affected consumers, with applicability, prerequisites, and any required intermediate steps. Adapt the actions to the artifact: a library call, workflow input, service setting, or infrastructure module may need different consumer changes. +```markdown +
+Release decisions -When updating the reference is sufficient, state: **No configuration, code, or invocation changes are required beyond selecting this release.** For a non-releasing change, state its adoption outcome explicitly too. An empty section or an absent migration paragraph is not evidence that no action is needed. +- **Release:** No - the change does not affect the artifact or its supported consumer contracts. +- **Labels:** `release:skip` -### 4. Release impact +
+``` -Only a PR targeting a managed release route includes `## Release impact`. -Unmanaged routes omit this section and all `release:*` labels. Report the release -resolver's decision; do not introduce a second version-selection policy. +The evidence after each decision must identify the applicable route, +configuration, and audience impact. List the exact resulting labels, or `None` +when effective configuration supplies the release decision and no override +label applies. Do not predict the final version; Release Management resolves it +from the actual base. + +When the target route does not invoke Release Management, omit this block and +all `release:*` labels. Do not add `release:skip` merely because the repository +has no `.github/release.config.yml`. + +### Assemble the body + +Use this order: + +1. Summary prose. +2. The shareable-summary marker. +3. Classified sections in the required order, each with its own optional + `Technical details` and `Related references` blocks. +4. Supporting blocks directly after the marker only when internal-only work has + no classified section. +5. The conditional `Release decisions` block, only when the target route + invokes Release Management. + +Do not add a `Summary` heading, empty classified sections, global supporting +blocks, or parallel release-note metadata. + +### Copy the complete template + +Start from this complete body. Replace every placeholder and delete every +classifier section, supporting block, example, or release field that does not +apply. Repeat a complete classifier section when several distinct results share +the same classifier, and keep every remaining classifier group in the order +shown. + +For internal-only work with no classified result, delete all five classifier +groups and place one applicable `Technical details` block and `Related +references` block directly after the marker. Delete the complete `Release +decisions` block when the target route does not invoke Release Management. On an +invoked route with a no-release decision, replace the release block with the +shorter no-release form shown in +[Record release decisions only when invoked](#record-release-decisions-only-when-invoked). + +For a publishing decision, retain the resolved bump and mode with their input +sources. A valid effective `DefaultBump` needs no per-PR bump label: report +`Labels: None` when no owned override applies, or the exact mode label when it +does. Include configured release-candidate routing in the mode evidence. Never +turn invalid settings or conflicting owned labels into a no-action result. -When `DefaultBump` supplies an MSX release level, record its value and whether -the shared default, repository setting, or supported caller input supplied it. -A valid effective default needs no per-PR bump label. Omission inherits the -documented patch default; invalid settings, unresolved decisions, and conflicting -owned labels fail the [required decision check](../Capabilities/release-management/design.md#required-pre-merge-decision-check). -Removing a bump override re-evaluates that default rather than making a decision -missing. +````markdown +{{ One or two short summary paragraphs that state what changes, why, who is +affected, and required adoption actions or an explicit no-action result. }} -| Field | Required content | -| --- | --- | -| Effective decision | The selected owned label and its semantic effect, or the configured policy that supplies the decision where supported. Identify the decision's source; do not assume a label name across producers. | -| Semantic effect | Major, minor, patch, or no release, plus stable/prerelease mode where applicable. Describe breaking behavior separately from its version classification. | -| Release/base coordinates | Before publication, state that final coordinates are resolved by the release process. The published record supplies the actual target version, tag, immutable source, version-computation base, and release/source baseline for the consumer delta, distinguishing the two bases when they differ. | + -Before publication, name the intended semantic effect and state that final coordinates are **resolved by the release process**. Do not assign a final version in advance or retain a numeric prediction after the base changes. The publisher records the actual coordinates in a distinct publication envelope without rewriting the authored body. For a first release, identify the initial versioning baseline and state that there is no prior release; for `release:skip`, state that no version is produced. +## Breaking: {{ Reader-facing result }} -### 5. Required ending blocks +{{ Explain what changes, why, affected supported uses, compatibility, and exact +adoption actions or an explicit no-action result. Include applicable +prerequisites, verification, ordering, and any required intermediate installation +or run. }} -At the very end of every PR description, use this exact structure: +{{ Interface or old-to-new example, comparison, or diagram after the prose when +needed to make adoption unambiguous. Keep required transition details in this +note; link to evergreen usage docs only for optional depth. Delete when prose +is sufficient. }} -```markdown ----
Technical details -### Consumer change record - - - -### Template baseline - - +{{ Implementation and validation evidence, closing delivery-leaf plan progress, +and issue-convergence search scope and outcome for this result, even when no +additional issue converges. }} -### Maintainer evidence +| Changed surface | Standards checked | Framework docs checked | Result | +| --- | --- | --- | --- | +| `{{ Path or interface }}` | {{ Applicable standards }} | {{ Applicable framework docs, or `None (no framework-specific docs)` }} | {{ `Aligned`, `Fixed in this PR`, or `Exception - MSXOrg/repository#123` }} | - +{{ For an applicable release-managed result, identify the consumer-change release +and source baseline and evidence supporting the actions or no-action result +above. For an affected integration template, identify its repository, verified +compatible immutable commit, and compatibility evidence. Publication resolves +actual release coordinates; do not predict a final version. Delete inapplicable +evidence. }}
-Relevant issues (or links) - -- Resolves Org/Repo#123 -- Resolves Org/OtherRepo#124 +Related references -### Related work - -- Depends on Org/OtherRepo#124 -- Followed by Org/OtherRepo#125 -- References Org/OtherRepo#126 +- Resolves MSXOrg/repository#123 +- References MSXOrg/repository#456 +- Depends on MSXOrg/other-repository#789
-``` -The **Technical details** block uses the three `###` headings shown above to separate consumer evidence from maintainer evidence. The deeper headings below organize this standard, not the PR body. +## Removed: {{ Reader-facing result }} -#### Consumer change record +{{ Explain what changes, why, affected supported uses, compatibility, and exact +adoption actions or an explicit no-action result. Include applicable +prerequisites, verification, ordering, and any required intermediate installation +or run. }} -Use one row per affected surface. A stable identifier within the record lets the adoption steps and later release records refer to the same change. +{{ Interface or old-to-new example, comparison, or diagram after the prose when +needed to make adoption unambiguous. Keep required transition details in this +note; link to evergreen usage docs only for optional depth. Delete when prose +is sufficient. }} -| Identifier / surface | Before | After | Applicability / prerequisites | Consumer action | Verification | -| --- | --- | --- | --- | --- | --- | -| `` | `` | `` | `` | `` | `` | +
+Technical details -Record exact changed configuration keys, workflow contracts, permissions, secret **names, never values**, public APIs, runtime/tool requirements, defaults, removals, and behavior. A list of changed filenames alone is insufficient. Link to numbered detail in the adoption path when commands or coordinated edits need more room; do not maintain competing instructions. +{{ Implementation and validation evidence, closing delivery-leaf plan progress, +and issue-convergence search scope and outcome for this result, even when no +additional issue converges. }} -Record no-action outcomes explicitly, including changes that affect behavior but require no consumer edit. If no consumer-facing surface changes, say so instead of leaving an empty table. Applicability distinguishes consumers that need an action from those already using the released contract. +| Changed surface | Standards checked | Framework docs checked | Result | +| --- | --- | --- | --- | +| `{{ Path or interface }}` | {{ Applicable standards }} | {{ Applicable framework docs, or `None (no framework-specific docs)` }} | {{ `Aligned`, `Fixed in this PR`, or `Exception - MSXOrg/repository#123` }} | -#### Template baseline +{{ For an applicable release-managed result, identify the consumer-change release +and source baseline and evidence supporting the actions or no-action result +above. For an affected integration template, identify its repository, verified +compatible immutable commit, and compatibility evidence. Publication resolves +actual release coordinates; do not predict a final version. Delete inapplicable +evidence. }} -Where a framework or product has an applicable integration template, record: +
-| Field | Required content | -| --- | --- | -| Producer identity | Producer version and immutable source, or the immutable candidate source before publication. | -| Template identity | Template repository and full immutable commit SHA, not a branch, floating tag, or today's latest template. | -| Compatibility evidence | Evidence that this template commit works with the identified producer source, including required integration surfaces and the relevant validation result. | -| Template work | Linked template PRs and their delivery state, or a justified no-change result. An earlier compatible commit may be reused when the evidence supports it. | +
+Related references -Every applicable release identifies its verified compatible baseline; a claim of compatibility without evidence is insufficient. If no template applies, state that fact and why. Do not invent a template or describe pending template work as delivered. +- Resolves MSXOrg/repository#123 +- References MSXOrg/repository#456 +- Depends on MSXOrg/other-repository#789 -#### Maintainer evidence +
-Keep internal implementation notes separate from the consumer record: +## New: {{ Reader-facing result }} -- Which internal functions, classes, or files were changed. -- Implementation approach and design decisions. -- Internal compatibility considerations not already owned by the consumer record. -- **Implementation plan progress** — cross-reference the closing Task or Bug's plan. Which plan steps does this PR complete? Which were moved to follow-up delivery issues? -- **Standards and framework alignment** — the result of the [alignment pass](Workflow-Stages/Implement.md#5-standards-and-framework-alignment-pass), as one row per changed surface. The stage procedure owns when and how the pass is run; this block only carries its evidence. -- **Issue convergence sweep** — the scope used for the [session-end sweep](Workflow-Stages/Implement.md#6-issue-convergence-sweep) and which additional open issues (if any) the finished diff fully satisfied. +{{ Explain what changes, why, affected supported uses, compatibility, and exact +adoption actions or an explicit no-action result. Include applicable +prerequisites, verification, ordering, and any required intermediate installation +or run. }} -| Changed surface | Standards checked | Framework docs checked | Result | -| --- | --- | --- | --- | -| `src/**` (PowerShell) | Naming, Functions | Module source layout | Aligned | -| `.github/workflows/**` | GitHub Actions | Reusable workflow contract | Exception — Org/Repo#123 | +{{ Interface or old-to-new example, comparison, or diagram after the prose when +needed to make adoption unambiguous. Keep required transition details in this +note; link to evergreen usage docs only for optional depth. Delete when prose +is sufficient. }} -A result is `Aligned`, `Fixed in this PR`, or `Exception` with a link to the follow-up issue that carries it. A surface with no framework or domain documentation of its own is recorded as `None (no framework-specific docs)`. +
+Technical details -The **Relevant issues (or links)** block is required and uses fully qualified references (`Org/Repo#N`) so links work across repositories. +{{ Implementation and validation evidence, closing delivery-leaf plan progress, +and issue-convergence search scope and outcome for this result, even when no +additional issue converges. }} -Use one bullet per linked reference. Begin with the closing issues, each prefixed with `Resolves`; this applies to the scoped Task or Bug delivered by the pull request and to additional issues the [issue convergence sweep](Workflow-Stages/Implement.md#6-issue-convergence-sweep) confirms are fully satisfied by the same finished diff. When the PR relates to other issues or pull requests, add a `### Related work` header below the `Resolves` list, then list each qualified reference with its relationship, such as `Depends on`, `Followed by`, or `References`. Closing keywords do not close pull requests. A parent PBI or Epic may appear as context without a closing keyword; never close an aggregate through a delivery pull request. Partially convergent or supporting issues are linked as non-closing context. +| Changed surface | Standards checked | Framework docs checked | Result | +| --- | --- | --- | --- | +| `{{ Path or interface }}` | {{ Applicable standards }} | {{ Applicable framework docs, or `None (no framework-specific docs)` }} | {{ `Aligned`, `Fixed in this PR`, or `Exception - MSXOrg/repository#123` }} | -A PR that delivers a scoped Task or Bug must include at least one `Resolves` link. A PR that does not resolve an issue must include a `### Related work` header and an unordered list of qualified relationship references. If additional `Resolves` links are used, include sweep evidence in Technical details that shows those issues are fully satisfied. The [Issue Hierarchy](Issues/Types/Hierarchy.md) and [Issue Lifecycle](Issues/Process/Lifecycle.md) own type and closure semantics. +{{ For an applicable release-managed result, identify the consumer-change release +and source baseline and evidence supporting the actions or no-action result +above. For an affected integration template, identify its repository, verified +compatible immutable commit, and compatibility evidence. Publication resolves +actual release coordinates; do not predict a final version. Delete inapplicable +evidence. }} -## Formatting +
-- Paragraphs are written as a **single unbroken line**. GitHub renders mid-paragraph newlines as spaces. -- The PR description is **the release note**. Write it for users, not reviewers. -- The PR title and description align with the closing Task or Bug's user-facing framing and recorded technical decisions. -- Refer to every issue or pull request as `Org/Repo#N`, including references in the current repository; do not use bare `#N` references. +
+Related references -## Example +- Resolves MSXOrg/repository#123 +- References MSXOrg/repository#456 +- Depends on MSXOrg/other-repository#789 -This illustrative configuration change uses the same record shape for any artifact type; it does not depend on a particular package manager, language, or deployment mechanism. +
-````markdown -Job timeouts use the explicit `timeoutSeconds` setting. Existing timeout values and the 30-second default are unchanged. +## Changed: {{ Reader-facing result }} - +{{ Explain what changes, why, affected supported uses, compatibility, and exact +adoption actions or an explicit no-action result. Include applicable +prerequisites, verification, ordering, and any required intermediate installation +or run. }} -## Breaking Changes +{{ Interface or old-to-new example, comparison, or diagram after the prose when +needed to make adoption unambiguous. Keep required transition details in this +note; link to evergreen usage docs only for optional depth. Delete when prose +is sufficient. }} -The `timeout` configuration key is removed. Configurations that still supply it are rejected. Rename it using the [adoption path](#adopting-this-release); configurations that omit the key need no configuration edit. +
+Technical details -## Adopting this release +{{ Implementation and validation evidence, closing delivery-leaf plan progress, +and issue-convergence search scope and outcome for this result, even when no +additional issue converges. }} -1. If the job configuration sets `timeout`, rename that key to `timeoutSeconds`, preserving its positive integer value in seconds. For example, `timeout: 20` becomes `timeoutSeconds: 20`. Do not supply both keys. If the key is absent, retain the 30-second default without adding a setting. -2. Select the published release through the integration's version reference or deployment mechanism. Apply the configuration edit with that version change, not to the previous version. -3. Run the existing configuration validation against the selected version: `timeoutSeconds: 20` is accepted and the removed `timeout: 20` is rejected. Run the existing timeout check to confirm cancellation at the configured limit, or 30 seconds when omitted. +| Changed surface | Standards checked | Framework docs checked | Result | +| --- | --- | --- | --- | +| `{{ Path or interface }}` | {{ Applicable standards }} | {{ Applicable framework docs, or `None (no framework-specific docs)` }} | {{ `Aligned`, `Fixed in this PR`, or `Exception - MSXOrg/repository#123` }} | -## Release impact +{{ For an applicable release-managed result, identify the consumer-change release +and source baseline and evidence supporting the actions or no-action result +above. For an affected integration template, identify its repository, verified +compatible immutable commit, and compatibility evidence. Publication resolves +actual release coordinates; do not predict a final version. Delete inapplicable +evidence. }} -| Field | Value | -| --- | --- | -| Effective decision | `release:major`, selected for removal of a supported configuration key. | -| Semantic effect | Major, stable; existing explicit configurations require the edit above. | -| Release/base coordinates | The release process resolves the actual version base, change baseline, target version, tag, and immutable source at publication. No final numeric version is assigned in this PR. | +
----
-Technical details +Related references -### Consumer change record +- Resolves MSXOrg/repository#123 +- References MSXOrg/repository#456 +- Depends on MSXOrg/other-repository#789 -| Identifier / surface | Before | After | Applicability / prerequisites | Consumer action | Verification | -| --- | --- | --- | --- | --- | --- | -| TIMEOUT-KEY / job configuration | Optional `timeout`, a positive integer in seconds; default 30. | Optional `timeoutSeconds`, with the same units and default; `timeout` is rejected. | Every integration; only configurations using the removed key need an edit. | Rename the key without changing its value; see adoption steps 1-2. No configuration change when omitted. | Adoption step 3 accepts the new key, rejects the old key, and confirms the timeout behavior. | +
-### Template baseline +## Fixed: {{ Reader-facing result }} -Not applicable: this product does not distribute an integration template. +{{ Explain what changes, why, affected supported uses, compatibility, and exact +adoption actions or an explicit no-action result. Include applicable +prerequisites, verification, ordering, and any required intermediate installation +or run. }} -### Maintainer evidence +{{ Interface or old-to-new example, comparison, or diagram after the prose when +needed to make adoption unambiguous. Keep required transition details in this +note; link to evergreen usage docs only for optional depth. Delete when prose +is sufficient. }} + +
+Technical details -- The configuration parser accepts `timeoutSeconds` and reports the removed key as invalid. -- Implementation plan progress: all steps in Org/Repo#218 are complete, including explicit-value and default-value coverage. -- Issue convergence sweep: configuration and timeout issues were inspected; no additional issue is fully satisfied. +{{ Implementation and validation evidence, closing delivery-leaf plan progress, +and issue-convergence search scope and outcome for this result, even when no +additional issue converges. }} | Changed surface | Standards checked | Framework docs checked | Result | | --- | --- | --- | --- | -| Configuration parsing and timeout behavior | Naming, Error Handling, Testing | Product configuration contract | Aligned | +| `{{ Path or interface }}` | {{ Applicable standards }} | {{ Applicable framework docs, or `None (no framework-specific docs)` }} | {{ `Aligned`, `Fixed in this PR`, or `Exception - MSXOrg/repository#123` }} | + +{{ For an applicable release-managed result, identify the consumer-change release +and source baseline and evidence supporting the actions or no-action result +above. For an affected integration template, identify its repository, verified +compatible immutable commit, and compatibility evidence. Publication resolves +actual release coordinates; do not predict a final version. Delete inapplicable +evidence. }}
-Relevant issues (or links) +Related references -- Resolves Org/Repo#218 +- Resolves MSXOrg/repository#123 +- References MSXOrg/repository#456 +- Depends on MSXOrg/other-repository#789 -### Related work +
-- References Org/Repo#220 +
+Release decisions + +- **Release:** {{ Yes or No }} - {{ Evidence from the artifact, route, and + supported consumer contract. }} +- **Version bump:** {{ Patch, Minor, or Major }} - {{ Compatibility evidence. + Identify the explicit label, supported caller input, repository setting, or + documented shared default that supplies it. Delete this field when Release + is No. }} +- **Mode:** {{ Stable or Prerelease }} - {{ Target-route or override evidence. + Identify configured release-candidate routing when applicable. Delete this + field when Release is No. }} +- **Labels:** {{ Exact `release:*` labels, or `None` when effective configuration + supplies the decision without an override label. }}
```` -For a no-action patch, keep both required user-facing blocks. State the no-action adoption outcome and record either the affected behavior with `No consumer edit required` or `No consumer-facing surface changes` under Consumer change record. Do not copy the breaking example's configuration actions into an unaffected release. - -## Drafts and readiness - -- The Shipper always creates the PR as **draft** so CI attaches immediately. -- A pull request is marked ready only when it meets every item in the [Definition of Ready for Review](Definition-of-Ready-and-Done.md#definition-of-ready-for-review) — nothing in that gate is left open. That page is the single checklist; this section does not restate it. -- Marking ready is a gate, not a person: anyone who can verify that gate — a contributor, or an agent acting on their behalf — may mark it ready. The gate, not the actor, is what makes it ready. -- Once ready, enable auto-merge (squash) so the change lands when review approves and the required checks stay green. See [Branching and Merging](Branching-and-Merging.md#required-checks-and-auto-merge). - -## Branches and commits - -- Branch naming: `/-`, e.g. `fix/123-pagination-truncation`. -- Commit messages: plain, direct, descriptive. **No conventional-commit prefixes** (`fix:`, `feat:`, `docs:`). See [Commit Conventions](Commit-Conventions.md). -- Self-review the staged diff before each commit. Unintended files (debug output, editor temp, credentials) get caught before they reach the remote. - -## Labels and assignment - -- Apply release labels only on a verified managed route. A valid effective `DefaultBump` supplies the bump without a per-PR bump label; record its source. An explicit owned bump label overrides it, and `release:skip` selects no release. Unmanaged routes omit all `release:*` labels. -- Apply phase labels if the repo uses them (Planning, Implementation, etc.). -- Assign the current user. -- Request reviewers per `CODEOWNERS`; if none, fall back to repo defaults or skip. +## Check readiness + +Before marking the pull request ready, verify: + +- the title states one result and contains none of the prohibited prefixes, + references, lists, or attribution; +- the summary is accurate on its own and the marker appears exactly once in the + required position; +- every claim matches the complete diff or promotion range; +- the complete delivered range since the identified consumer-change baseline is + covered, including every bundled consumer delta; +- classified sections are non-empty, ordered, and grouped by reader-facing + result; +- the notes explain what changed, why, affected supported uses, compatibility, + and exact applicable actions or an explicit no-action result, without + requiring PRs, diffs, or historical product docs to discover instructions; +- release-order composition preserves required intermediate operations without + assuming every intermediate version must be installed; +- prose precedes optional examples and tables; +- supporting blocks are scoped to their section and ordered correctly; +- same-instance references are fully qualified and closing keywords are + accurate; +- release metadata and `release:*` labels are absent when the route does not + invoke Release Management; +- when Release Management applies, the decision block, labels, effective + configuration, and complete-change evidence agree; +- the description contains no AI or agent attribution. + +The pull request still follows the complete [Definition of Ready for +Review](Definition-of-Ready-and-Done.md#definition-of-ready-for-review). + +## Where this connects + +- [README-Driven Context](Readme-Driven-Context.md) — where the product audience + and supported interfaces are declared. +- [Contribution Workflow](Contribution-Workflow.md) — how a draft pull request + moves through automated and human review. +- [Definition of Ready and Done](Definition-of-Ready-and-Done.md) — the gate + before review and completion. +- [Branching and Merging](Branching-and-Merging.md) — branch, integration, and + merge rules. +- [Automation Labels](Automation-Labels.md) — ownership and meaning of + `release:*` labels. +- [Release Management](../Capabilities/release-management/design.md) — release + invocation, configuration, decision resolution, and publication. diff --git a/src/docs/Ways-of-Working/Readme-Driven-Context.md b/src/docs/Ways-of-Working/Readme-Driven-Context.md index d495da86..bd15d676 100644 --- a/src/docs/Ways-of-Working/Readme-Driven-Context.md +++ b/src/docs/Ways-of-Working/Readme-Driven-Context.md @@ -38,7 +38,7 @@ Every repository README MUST identify its target audience, the jobs the product **User and integrator are roles, not necessarily different people.** An integration interface is user-facing when the audience depends on it; it does not become internal because its users write scripts, compose APIs, or maintain another product. The audience is not inferred from who authors or reviews a pull request. -Detailed users and jobs belong in the [capability specification](Spec-Driven-Development.md#what-a-specification-is), linked from the README rather than copied. This declared audience anchors [change classification](PR-Format.md#detecting-the-change-type) and the consumer evidence in release notes. +Detailed users and jobs belong in the [capability specification](Spec-Driven-Development.md#what-a-specification-is), linked from the README rather than copied. This declared audience anchors [reader identification](PR-Format.md#identify-the-readers) and the evidence in pull request descriptions. ## When to update the README diff --git a/src/docs/Ways-of-Working/Repository-Standard.md b/src/docs/Ways-of-Working/Repository-Standard.md index 1bbc6b9c..013f710a 100644 --- a/src/docs/Ways-of-Working/Repository-Standard.md +++ b/src/docs/Ways-of-Working/Repository-Standard.md @@ -166,20 +166,23 @@ When a tool only discovers config at the repository root, keep it there and docu ## Pull request defaults -Repository pull requests must use the PR Manager style for title and description when a release note may be generated from the PR. - -Default title pattern: - -```text - []: -``` - -Use [PR Format](PR-Format.md) for audience-based change classification and the complete description structure, including its required consumer evidence and ending blocks. A PR closes one scoped Task or Bug, with any additional closing links limited to issues the session-end convergence sweep shows are fully delivered by the same diff. +Repository pull requests follow [PR Format](PR-Format.md): one short +reader-facing result in the title, an audience-first description of the complete +change, and supporting evidence scoped to the result it supports. Repository or +initiative guidance MUST NOT add an icon, type prefix, issue reference, or +internal campaign identifier to the title. + +A pull request closes one scoped Task or Bug, with any additional closing links +limited to issues the session-end convergence sweep shows are fully delivered by +the same diff. When the target route invokes Release Management, the description +and labels carry its evidence-based release decision. A route without that +invocation carries neither the `Release decisions` block nor `release:*` labels. The organization-level `.github` repository supplies the default template. The repository-local contribution guide directs humans and agents to the -organization template and its required format. A repository carries a local -template only for a documented exception. +organization template and the canonical format. The inherited template is a +scaffold; PR Format remains authoritative. A repository carries a local template +only for a documented exception. ## Managed files @@ -218,7 +221,7 @@ For example, PSModule can define its module-specific managed files in `PSModule/ - [Agentic Development](../Capabilities/agentic-development/index.md) — which agent files a repository carries and why the entry point is a pointer. - [Repository Type Property](Repository-Type-Property.md) — the `Type` custom property that classifies a repository and drives which type-specific files and controls apply. - [README-Driven Context](Readme-Driven-Context.md) — why the README is the front door. -- [PR Format](PR-Format.md) — the PR Manager-style title and description format. +- [PR Format](PR-Format.md) — the audience-first title and description format. - [Natural Language](../Coding-Standards/Natural-Language.md) — which language each artifact is written in, and how English prose is written. - [GitHub Actions](../Coding-Standards/GitHub-Actions.md) — workflow and automation standards. - [Dependency Updates](../Capabilities/dependency-updates/spec.md) — supply-chain update requirements. diff --git a/src/docs/Ways-of-Working/Workflow-Stages/Implement.md b/src/docs/Ways-of-Working/Workflow-Stages/Implement.md index 021b4854..cb7ac6f0 100644 --- a/src/docs/Ways-of-Working/Workflow-Stages/Implement.md +++ b/src/docs/Ways-of-Working/Workflow-Stages/Implement.md @@ -5,7 +5,7 @@ description: Procedure for the Workflow stage that delivers one ready Task or Bu # Implement -Implement is the delivery stage of the canonical [Workflow](../Workflow.md). It takes one ready, unblocked Task or Bug and produces working software in a review-ready pull request. The stage owns branching, coding, committing, opening the pull request, tracking progress, running the automated review loop, responding to feedback, and finalizing the release note. Implement builds delivery leaves; it does not implement an Epic or PBI aggregate, plan from scratch, or supply the independent review. +Implement is the delivery stage of the canonical [Workflow](../Workflow.md). It takes one ready, unblocked Task or Bug and produces working software in a review-ready pull request. The stage owns branching, coding, committing, opening the pull request, tracking progress, running the automated review loop, responding to feedback, and finalizing the pull request description and any applicable release metadata. Implement builds delivery leaves; it does not implement an Epic or PBI aggregate, plan from scratch, or supply the independent review. ## Enter this stage when @@ -64,7 +64,7 @@ Record the outcome as one row per changed surface: | `src/functions/**` (PowerShell) | Naming, Functions, Error Handling | Module source layout | Aligned | | `.github/workflows/**` | GitHub Actions | Reusable workflow contract | Exception — Owner/Repo#123 | -A result is `Aligned`, `Fixed in this PR`, or `Exception` with a link that justifies it. Where a changed surface has no framework or domain documentation of its own, write `None (no framework-specific docs)` rather than inventing a pseudo-link. Carry the table into the pull request's Technical details block per [PR Format](../PR-Format.md), so [Review](Review.md) can verify the pass instead of guessing whether it happened. +A result is `Aligned`, `Fixed in this PR`, or `Exception` with a link that justifies it. Where a changed surface has no framework or domain documentation of its own, write `None (no framework-specific docs)` rather than inventing a pseudo-link. Put each row in the `Technical details` block for the pull request section whose result it supports. For internal-only work without a classified section, put the table in the supporting block after the summary marker. This keeps the evidence scoped per [PR Format](../PR-Format.md) so [Review](Review.md) can verify the pass instead of guessing whether it happened. **Stop rule.** Fix what is in scope for the closing Task or Bug and small enough to keep the pull request reviewable. When a finding is out of scope, systemic across the repository, or would change the shape of the pull request, file a follow-up issue through [Define](Define.md), link it in the table as an exception, and leave the change as it is. The pass improves alignment; it does not turn into a second delivery. @@ -75,15 +75,15 @@ Run this once per implementation session, at the same timing as the standards/fr 1. Search for already-open issues whose asks are already satisfied by the finished diff, not only the issue originally linked when the branch was opened. 2. Scope the sweep deliberately so it scales: prioritize the delivery leaf's parent and siblings in the [Issue Hierarchy](../Issues/Types/Hierarchy.md), then narrow by affected component, labels, keywords, or code paths. Do not read every open issue serially in large repositories. 3. Treat convergence as outcome-based: - - **Fully satisfied** — the diff already delivers the issue's ask. Add it to the pull request's Relevant issues block with `Resolves` so merge closes it. - - **Partially satisfied** — the diff helps but does not fully deliver the ask. Link it as non-closing context and keep or create a follow-up delivery leaf for the remaining gap. + - **Fully satisfied** — the diff already delivers the issue's ask. Add it to the applicable section's `Related references` block with `Resolves` so merge closes it. + - **Partially satisfied** — the diff helps but does not fully deliver the ask. Add it to the applicable `Related references` block as non-closing context and keep or create a follow-up delivery leaf for the remaining gap. 4. Keep this pass focused on convergence and linkage. It does **not** rewrite, reformat, or otherwise "fix up" issue bodies to match issue templates; issue quality edits are separate work routed through [Define](Define.md). ### 7. Finalize and hand off When the change meets the [Definition of Ready for Review](../Definition-of-Ready-and-Done.md): -1. Finalize the title, release-note description, and effective release decision and its source per [PR Format](../PR-Format.md). +1. Finalize the title and release-note-ready description per [PR Format](../PR-Format.md). When the target route invokes Release Management, also reconcile the `Release decisions` block and applied `release:*` labels with the effective configuration; otherwise omit them. 2. Mark the pull request ready and enable auto-merge per [Branching and Merging](../Branching-and-Merging.md). ## Operating rules diff --git a/src/docs/Ways-of-Working/Workflow-Stages/Review.md b/src/docs/Ways-of-Working/Workflow-Stages/Review.md index 0fd096d8..1e28ee89 100644 --- a/src/docs/Ways-of-Working/Workflow-Stages/Review.md +++ b/src/docs/Ways-of-Working/Workflow-Stages/Review.md @@ -33,6 +33,10 @@ Check each dimension per [Review Etiquette](../Review-Etiquette.md): - **Taste** — readability, naming, structure, tests that exercise behaviour. - **Security** — input validation, no secrets in logs, external action and reusable-workflow references pinned to full commit SHAs, owned major-tag references meeting the controlled-release exception, and least privilege. Escalate a deep pass to [Security Review](Security-Review.md). - **Documentation** — updated where user-facing behaviour changed. +- **Pull request artifact** — the title states one result, the description follows + [PR Format](../PR-Format.md), supporting evidence is section-scoped, and + release metadata appears only when the target route invokes Release + Management. - **Standards and framework alignment** — the pull request records the author's [alignment pass](Implement.md#5-standards-and-framework-alignment-pass), the result covers every changed surface, and each exception links a real follow-up issue. Spot-check at least one row against the canonical standard or framework page rather than trusting the summary; a missing or hollow pass is a blocking finding. - **Issue convergence sweep** — the pull request records the author's [sweep](Implement.md#6-issue-convergence-sweep), including scoped search coverage and any convergent issues linked with closing keywords. Spot-check at least one linked closing issue against the delivered diff; a claimed convergence with no visible delivery evidence is a blocking finding. - **Tests** — new behaviour has tests; bugs get regression tests. @@ -58,6 +62,7 @@ An approval co-signs the change, so approve once the blocking concerns are resol - [Review Etiquette](../Review-Etiquette.md) — tone, severity, and how to disagree well. - [Implement](Implement.md#5-standards-and-framework-alignment-pass) and [Implement](Implement.md#6-issue-convergence-sweep) — the author-side session-end passes this stage verifies. -- [PR Format](../PR-Format.md) — delivery-leaf closure and contextual aggregate links. +- [PR Format](../PR-Format.md) — reader-facing titles and descriptions, + supporting references, and conditional release metadata. - [Branching and Merging](../Branching-and-Merging.md) — who approves and how a change lands. - [Security Review](Security-Review.md) — the specialized security path. diff --git a/src/docs/Ways-of-Working/Workflow.md b/src/docs/Ways-of-Working/Workflow.md index 58f1b0a2..bad46722 100644 --- a/src/docs/Ways-of-Working/Workflow.md +++ b/src/docs/Ways-of-Working/Workflow.md @@ -136,7 +136,10 @@ See [Review Etiquette](Review-Etiquette.md). Human review approves the ready pull request and the required checks stay green, so auto-merge lands the change — squash-merged into the protected branch, its branch deleted — and closes its Task or Bug. Where the project releases from the trunk, the merge cuts the release. -The pull request description becomes the release note. Write it for end users, not reviewers. +The pull request description is release-note-ready. When Release Management +publishes it, the description becomes part of the release record; otherwise it +remains the durable change record. Write it for the identified readers, not +only for reviewers. Parent PBI and Epic issues close separately when their native children and aggregate acceptance criteria are complete. See [PR Format](PR-Format.md), [Issue Lifecycle](Issues/Process/Lifecycle.md), and [Branching and Merging](Branching-and-Merging.md#required-checks-and-auto-merge). diff --git a/src/docs/Ways-of-Working/index.md b/src/docs/Ways-of-Working/index.md index 4ae7e6e9..67d4386c 100644 --- a/src/docs/Ways-of-Working/index.md +++ b/src/docs/Ways-of-Working/index.md @@ -35,7 +35,7 @@ This section documents the principles, processes, and norms that every contribut | [Goal-Setting Framework](Goal-Setting.md) | Mission, OKRs, and Initiatives — the strategy above repository Epics. | | [Definition of Ready and Done](Definition-of-Ready-and-Done.md) | The three gates that bracket every piece of work. | | [Issues](Issues/index.md) | How issues are formatted and organized across the MSX ecosystem. | -| [PR Format](PR-Format.md) | Pull request title, description, change types, and labels. | +| [PR Format](PR-Format.md) | Audience-first pull request titles and descriptions with evidence-based, conditional release decisions. | | [Commit Conventions](Commit-Conventions.md) | How commit messages are written. | | [Branching and Merging](Branching-and-Merging.md) | Delivery-leaf topic branches, pull-request-only integration, and merge models. | | [Review Etiquette](Review-Etiquette.md) | Tone, scope, severity, and how to disagree well. | From 89a6643f024ff1e5e471b456030975bbbec1014e Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 31 Oct 2026 14:22:36 +0100 Subject: [PATCH 03/10] Keep lifecycle continuous-delivery policy aligned with defaults --- .../Ways-of-Working/Continuous-Delivery-And-Release.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md b/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md index 2a90765b..573ff8da 100644 --- a/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md +++ b/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md @@ -90,12 +90,14 @@ Several signals suggest what kind of change a pull request contains: the shape o diff, whether tests were added or changed, the commit messages, and an AI-assisted reading of the change. Those signals MUST be treated as input. The [resolved release decision](../Capabilities/release-management/design.md#version-computation) -comes from an explicit owned bump label or the valid effective `DefaultBump`, -including shared defaults, repository settings and supported caller overrides, and +comes from an explicit owned bump label or the valid effective `DefaultBump`, and its suitability for the audience is reviewed at the pull-request gate. -A documented effective default is a prior policy decision, not an omission to interpret -later. The pull request records the effective level and its source, and review +A documented default is a prior policy decision, not an omission to interpret +later. Repository settings and supported caller inputs can override it; an +explicit owned bump label overrides the valid effective default. Invalid +supplied settings and conflicting owned labels fail rather than use a fallback. +The pull request records the effective level and its source, and review confirms that the level fits the declared user/integrator impact. A missing decision fails a required CI check and blocks merge; publication does not discover the missing decision only after integration. From 67a20c6eeee7390232881a492f64989cad6097ee Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 31 Oct 2026 14:34:30 +0100 Subject: [PATCH 04/10] Separate reservation transitions and preserve release provenance --- .../Capabilities/release-management/design.md | 21 ++++++- .../vscode-extension-framework/design.md | 20 ++++--- .../vscode-extension-framework/spec.md | 6 +- .../Ways-of-Working/Fleet-Orchestration.md | 55 ++++++++++++++++++- 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index 4b00e727..a6443d11 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -77,7 +77,9 @@ identity makes duplicate delivery and retries idempotent. | Trigger and approval evidence | Frozen | Shows who or what authorized the release and included range. | | Stable line, fixed source, and range baseline | Frozen | Defines the exact source history being released. | | Aggregate decision and its source | Frozen | Records major, minor, patch, or skip and the owned label, caller input, repository setting, or shared default that supplied it. | -| Canonical version and reservation state | Frozen after Resolve | Prevents later work from taking the same coordinate. | +| Version-computation base and consumer-change baseline | Frozen | Distinguishes the actual calculation base from the completed source against which the consumer delta is described. | +| Canonical version | Frozen after Resolve | Identifies the coordinate selected for this intent. | +| Reservation state | Progressive, append-only | Starts provisional and becomes permanently reserved after successful build or external visibility; later events never free it for different content. | | Release-note snapshot and provenance | Frozen | Preserves the reviewed contributor-authored account. | | Required destinations and announcement routes | Frozen | Prevents configuration drift during recovery. | | Lifecycle stage and failure detail | Progressive | Records the last successful boundary and actionable failure. | @@ -109,6 +111,7 @@ stateDiagram-v2 Verified --> Verified: Publication attempt failed Publishing --> Publishing: Publication attempt failed Resolved --> Superseded: No successful build or external visibility + Resolved --> Retired: Externally visible and explicitly unrecoverable Built --> Retired: Explicitly unrecoverable Verified --> Retired: Explicitly unrecoverable Publishing --> Retired: Explicitly unrecoverable @@ -121,6 +124,11 @@ only to work that never produced a successful build and never exposed a release coordinate. `Retired` preserves a permanently reserved coordinate for an incomplete release. `Withdrawn` preserves completion while changing eligibility. +`Resolved → Retired` requires explicit maintainer authorization and a permanent +reservation established by external visibility; untouched unbuilt and unexposed +work follows the guarded supersession path instead. Reservation transitions are +append-only evidence, not mutations of the frozen canonical version. + ## Resolve Resolve is the only stage that selects source, scope, decision, version, note @@ -448,7 +456,11 @@ authorizes a publisher to invent a no-action result. The publication envelope augments, but does not rewrite, the authored note: - canonical and destination-native versions; -- previous completed stable baseline; +- version-computation base, including the stable version or permanently reserved + coordinate actually used, and explicit `0.0.0` when no stable version or + permanent reservation exists; +- consumer-change baseline: the previous completed stable release/source for + the included delta, or explicitly no predecessor for an initial release; - fixed source and included range; - aggregate decision and its owned-label or effective-setting source; - artifact fingerprint and verification evidence; @@ -456,6 +468,11 @@ The publication envelope augments, but does not rewrite, the authored note: - note snapshot provenance; and - completion, retirement, withdrawal, alias, and announcement events. +These bases can differ. With completed `1.4.2` and permanently reserved retired +`1.5.0`, a patch resolves from `1.5.0` to `1.5.1`, while its consumer delta still +starts from completed source `1.4.2`. Freeze and publish both identities rather +than presenting the completed source as proof of the version calculation. + A later explanatory correction is another append-only metadata event containing before and after text, reason, actor, time, and source evidence. It cannot change the version, source, artifact, decision, or behavior attributed to the release. diff --git a/src/docs/Capabilities/vscode-extension-framework/design.md b/src/docs/Capabilities/vscode-extension-framework/design.md index 68939422..5f7f3c49 100644 --- a/src/docs/Capabilities/vscode-extension-framework/design.md +++ b/src/docs/Capabilities/vscode-extension-framework/design.md @@ -29,12 +29,14 @@ flowchart LR ``` - **Find version** — validate the release decision and compute the version once, - from the latest `vX.Y.Z` tag or release plus the explicit or configured bump. + from the latest `vX.Y.Z` tag or release plus the valid effective bump. Resolve + the canonical release identity and any declared native numeric mapping before + Build; retain both with their source evidence. Independent of the other stages and required by the merge ruleset; a missing decision is a failed check, not a post-merge surprise. - **Lint & type-check** — static analysis and the type checker. Independent, so it fails fast in parallel with the build. -- **Build** — stamp the computed version into the manifest, compile the +- **Build** — stamp the resolved native extension version into the manifest, compile the production bundle, and package **one** VSIX. Uploads the bundle, the VSIX, and the stamped manifest as artifacts. - **Test** — download a real editor host and run the extension test suite @@ -47,13 +49,17 @@ flowchart LR The version is computed once and flows through the pipeline as artifacts, so the thing that ships is the thing that was tested: -1. **Find version** decides `vX.Y.Z` from tags plus the resolved explicit or configured bump. -2. **Build** stamps it into `package.json` (and `package-lock.json`), compiles +1. **Find version** decides the canonical release version and validated native + extension version together, before Build. +2. **Build** stamps the resolved native version into `package.json` (and + `package-lock.json`), compiles the bundle, and runs the packaging CLI to produce a single VSIX. The stamped manifest is uploaded alongside the VSIX so the manifest under test — including the version the running extension reports — matches the packaged artifact. 3. **Test** restores that bundle and manifest and tests them. -4. **Release** restores and publishes that same VSIX. +4. **Release** restores and publishes that same VSIX. Its GitHub Release uses + the canonical identity and records the native mapping; enabled marketplaces + receive the unchanged VSIX and the corresponding native version/channel. Build, test, and release never re-compile or re-package; they pass the built artifact forward. @@ -112,8 +118,8 @@ VSIX artifact — this framework does not re-implement it: - The version check re-evaluates source, release labels, release settings, supported caller inputs, and the effective pipeline, following the shared [pre-merge gate](../release-management/design.md#required-pre-merge-decision-check). -- The version is computed once and stamped into the manifest; it is never - hand-edited. +- Canonical and native versions are resolved once before Build; the native + extension version is stamped into the manifest, never hand-edited. - A prerelease is requested by `release:prerelease` with a resolved bump on an open pull request (or by a prerelease branch), producing a prerelease VSIX that is never promoted to latest. When such a build is also published to the diff --git a/src/docs/Capabilities/vscode-extension-framework/spec.md b/src/docs/Capabilities/vscode-extension-framework/spec.md index 3b13fa60..8d5860cc 100644 --- a/src/docs/Capabilities/vscode-extension-framework/spec.md +++ b/src/docs/Capabilities/vscode-extension-framework/spec.md @@ -59,7 +59,7 @@ framework itself. - **A reproducible, self-contained bundle.** The extension is compiled into a single self-contained bundle with no unbundled runtime dependencies; the same commit always produces the same output. - **Tested on a real host.** The extension is tested against a real VS Code host, across the host versions and operating systems the extension declares as supported. Tests exercise the exact bundle that ships — never a separately compiled copy. - **A static quality gate.** Every change is linted and type-checked, and the pipeline holds on any error. Quality is validated at pull-request time, not after merge. -- **Built once, shipped once.** The version is computed once, stamped into the manifest, and the same packaged VSIX is what is tested and what is published. Build, test, and release MUST NOT diverge. +- **Built once, shipped once.** The canonical release identity and validated native extension version MUST be resolved before Build. The native version is stamped into the manifest, and the same packaged VSIX is tested and published unchanged. The GitHub Release records the canonical/native mapping; destination-native numbers need not be textually identical. Build, test, and release MUST NOT diverge. - **Policy-driven, semantic versioning.** Versioning follows [Release Management](../release-management/spec.md): an explicit owned bump label overrides the valid effective `DefaultBump`; without a bump label, the documented default supplies the level. Invalid settings and conflicting owned labels MUST fail the required PR check and block merge. `release:skip` prevents publication, and `release:prerelease` MAY use the resolved explicit or default bump. The version is [SemVer](https://semver.org/) and is derived automatically — never hand-edited in the manifest. - **An installable artifact on every release.** Each release produces an installable VSIX attached to its [GitHub Release](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases), together with an immutable reference. A user MUST be able to install a specific released version without a marketplace account. - **Optional marketplace publication.** Where configured, the same VSIX is also published to an extension marketplace (the VS Code Marketplace and/or Open VSX). Marketplace publication is opt-in and MUST NOT be a prerequisite for the GitHub-Release install path. @@ -72,10 +72,10 @@ framework itself. ## Success criteria - Creating a repository from the template and providing a valid release decision yields a green build, a passing test run, and a packaged VSIX with no extension-specific configuration written. -- An eligible pull request merged to a release branch produces a GitHub Release carrying an installable VSIX whose version matches the explicit or default bump. Omitting a bump label uses the valid effective default; invalid settings and conflicting owned labels fail required CI before merge. +- An eligible merged PR produces a GitHub Release whose canonical version reflects the resolved bump and whose unchanged VSIX uses the recorded native version mapping. Omitting a bump label uses the valid effective default; invalid settings and conflicting owned labels fail required CI before merge. - The tests that gate the release exercise the exact VSIX that is released, on every supported host version and operating system. - On a managed VSIX route, a change outside the artifact/consumer scope carrying `release:skip` runs its checks without publication. An unmanaged route has no release metadata or labels. -- A user installs any released version straight from its GitHub Release with no marketplace account; where marketplace publishing is enabled, that same version also appears in the marketplace. +- A user installs any released version from its canonical GitHub Release without a marketplace account; enabled marketplaces publish the unchanged VSIX under its recorded native version/channel mapping. - An open pull request can publish a prerelease VSIX for testing that never becomes the latest stable version, and it is cleaned up when the pull request closes. - Adopting the framework in a new extension is a short caller plus a settings file — the pipeline itself is never copied into the repository. diff --git a/src/docs/Ways-of-Working/Fleet-Orchestration.md b/src/docs/Ways-of-Working/Fleet-Orchestration.md index 4ad9f611..ed68b192 100644 --- a/src/docs/Ways-of-Working/Fleet-Orchestration.md +++ b/src/docs/Ways-of-Working/Fleet-Orchestration.md @@ -245,8 +245,20 @@ interval so the view refreshes as GitHub changes; deleting it loses nothing, because GitHub is the source of truth. Read linked pull requests with full pagination and include closed or merged -ones. Verify explicit links for non-default targets rather than reconstructing -them from ignored keywords. A missing or unreadable link on an in-progress +ones. `closedByPullRequestsReferences` retrieves closing associations, not every +manual Development link. Also read the issue's native `ConnectedEvent` and +`DisconnectedEvent` timeline entries, including both source and subject. +Fold those entries in returned timeline order for each issue–PR pair: a +connection adds the manual association and a disconnection removes it. Keep only +pairs with the queried issue's node ID at one endpoint and a PR at the other; +use PR node IDs, not display numbers, as the identity. Combine +the current manual associations with closing references, deduplicate by PR +identity, then read each PR's live state. Ordinary prose cross-references do not +replace a verified Development association. + +Verify explicit links for non-default targets rather than reconstructing +them from ignored keywords or assuming the closing-reference query is complete. +A missing or unreadable link on an in-progress delivery is a discovery gap to report, not an empty or completed delivery. Typical columns: effective status, repository, delivery issue and pull request, draft/ready, @@ -295,7 +307,7 @@ requests alike. gh search issues 'in:title "[]"' --owner ` --json number,repository,title,url,state -# follow native issue links, including closed/merged PRs, with full pagination +# read closing associations, including closed/merged PRs, with full pagination $query = @' query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) { repository(owner: $owner, name: $repo) { @@ -310,6 +322,43 @@ query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) { '@ gh api graphql --paginate -f query="$query" -f owner='' -f repo='' -F number='' +# read manual Development associations separately; fold connect/disconnect pairs +$developmentQuery = @' +fragment DevelopmentSubject on ReferencedSubject { + __typename + ... on Issue { id url } + ... on PullRequest { id number url } +} +query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) { + repository(owner: $owner, name: $repo) { + issue(number: $number) { + id + timelineItems( + first: 100 + after: $endCursor + itemTypes: [CONNECTED_EVENT, DISCONNECTED_EVENT] + ) { + nodes { + __typename + ... on ConnectedEvent { + createdAt + source { ...DevelopmentSubject } + subject { ...DevelopmentSubject } + } + ... on DisconnectedEvent { + createdAt + source { ...DevelopmentSubject } + subject { ...DevelopmentSubject } + } + } + pageInfo { hasNextPage endCursor } + } + } + } +} +'@ +gh api graphql --paginate -f query="$developmentQuery" -f owner='' -f repo='' -F number='' + # read one pull request's authoritative state gh pr view --repo / --json ` isDraft,state,reviewDecision,statusCheckRollup,mergeStateStatus,assignees From 0daf7da34f10a5a311646d0c2900f9f6836d54f5 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 31 Oct 2026 14:50:01 +0100 Subject: [PATCH 05/10] Honor aggregate release minima and authoritative version bases --- src/docs/Capabilities/release-management/design.md | 10 ++++++---- .../Capabilities/vscode-extension-framework/design.md | 3 ++- .../Ways-of-Working/Continuous-Delivery-And-Release.md | 5 +++++ src/docs/Ways-of-Working/Fleet-Orchestration.md | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index a6443d11..38769a14 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -468,10 +468,12 @@ The publication envelope augments, but does not rewrite, the authored note: - note snapshot provenance; and - completion, retirement, withdrawal, alias, and announcement events. -These bases can differ. With completed `1.4.2` and permanently reserved retired -`1.5.0`, a patch resolves from `1.5.0` to `1.5.1`, while its consumer delta still -starts from completed source `1.4.2`. Freeze and publish both identities rather -than presenting the completed source as proof of the version calculation. +These bases can differ. With completed `1.4.2`, a permanently reserved retired +`1.5.0` attempt containing an approved unreleased minor change still establishes +minor as the minimum aggregate increment. A reviewed minor resolves from the +reserved base `1.5.0` to `1.6.0`, while its consumer delta starts from completed +source `1.4.2`; patch is rejected for that range. Freeze and publish both bases +rather than presenting the completed source as proof of the calculation. A later explanatory correction is another append-only metadata event containing before and after text, reason, actor, time, and source evidence. It cannot change diff --git a/src/docs/Capabilities/vscode-extension-framework/design.md b/src/docs/Capabilities/vscode-extension-framework/design.md index 5f7f3c49..ab8e2261 100644 --- a/src/docs/Capabilities/vscode-extension-framework/design.md +++ b/src/docs/Capabilities/vscode-extension-framework/design.md @@ -29,7 +29,8 @@ flowchart LR ``` - **Find version** — validate the release decision and compute the version once, - from the latest `vX.Y.Z` tag or release plus the valid effective bump. Resolve + through the shared release resolver's authoritative version base and valid + effective bump, not a separate latest-tag algorithm. Resolve the canonical release identity and any declared native numeric mapping before Build; retain both with their source evidence. Independent of the other stages and required by the merge ruleset; a missing diff --git a/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md b/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md index 573ff8da..3b829874 100644 --- a/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md +++ b/src/docs/Ways-of-Working/Continuous-Delivery-And-Release.md @@ -86,6 +86,11 @@ guarantee instead. ### D2 — Version signals feed in, the decision is reviewed at the PR gate {#d2-version-signals-feed-in-the-label-decides-at-the-pr-gate} +This decision protocol applies only to actual Release Management routes, +including native producer pipelines. An unmanaged route has no release-decision +block, `release:*` labels, or missing-decision check; continuous delivery alone +does not opt it into a versioned release process. + Several signals suggest what kind of change a pull request contains: the shape of the diff, whether tests were added or changed, the commit messages, and an AI-assisted reading of the change. Those signals MUST be treated as input. The diff --git a/src/docs/Ways-of-Working/Fleet-Orchestration.md b/src/docs/Ways-of-Working/Fleet-Orchestration.md index ed68b192..475c150e 100644 --- a/src/docs/Ways-of-Working/Fleet-Orchestration.md +++ b/src/docs/Ways-of-Working/Fleet-Orchestration.md @@ -313,7 +313,7 @@ query($owner: String!, $repo: String!, $number: Int!, $endCursor: String) { repository(owner: $owner, name: $repo) { issue(number: $number) { closedByPullRequestsReferences(first: 100, after: $endCursor, includeClosedPrs: true) { - nodes { number url state } + nodes { id number url state } pageInfo { hasNextPage endCursor } } } From 43aea63d28556fd827fc4df0fb453c3b3415c043 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 31 Oct 2026 15:10:34 +0100 Subject: [PATCH 06/10] Bind template evidence and separately approved corrective intents --- src/docs/Capabilities/release-management/design.md | 13 +++++++++++-- src/docs/Capabilities/release-management/spec.md | 6 ++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index 38769a14..bc22ab0c 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -71,6 +71,12 @@ duplicate the promotion process. Resolve creates or loads one durable release intent before Build. Its stable identity makes duplicate delivery and retries idempotent. +The identity includes the separately approved logical request, not only its +source commit. Duplicate delivery or retry of that request loads the same +frozen intent. A new corrective request requires distinct approval/request +identity and explicitly records which prior intent it replaces; it cannot reuse +the retired or withdrawn version, even when its reviewed source is unchanged. + | Field | Frozen or progressive | Purpose | | --- | --- | --- | | Intent identity and idempotency key | Frozen | Identifies one logical release independently of a workflow run. | @@ -537,8 +543,11 @@ execution queues. For each stable line, the reconciler finds source revisions not yet accounted for by a complete, retired, or superseding intent. It processes the oldest unsettled range first. Duplicate triggers use an idempotency key derived from the -repository, stable line, fixed source, and request kind, and return the existing -intent rather than creating another. +repository, stable line, fixed source, request kind, and immutable approved +request identity, and return the existing intent rather than creating another. +A separately approved corrective release has a new request identity and version +and retains its relationship to the prior intent; changing a delivery ID alone +does not authorize a new release. This ordering prevents a later fast run from taking a version or release range that belongs to earlier unresolved work. diff --git a/src/docs/Capabilities/release-management/spec.md b/src/docs/Capabilities/release-management/spec.md index 52e795f8..75d3863a 100644 --- a/src/docs/Capabilities/release-management/spec.md +++ b/src/docs/Capabilities/release-management/spec.md @@ -383,6 +383,12 @@ compatibility basis. Supporting evidence MUST remain scoped to its result; internal-only work without a classifier uses the supporting block after the summary marker. Announcements MUST NOT truncate the full release record. +An affected integration template MUST be identified by repository and verified +compatible immutable commit, with evidence for the exact producer source and +linked template delivery or a justified no-change result. A moving branch, +today's template, or an unsupported compatibility claim MUST NOT replace that +evidence. If no template applies, record that result and its basis explicitly. + Reading every applicable source-bound release record after the actual consumed baseline through the target in release order MUST be sufficient to compose the required actions. Notes MUST explain superseded actions while retaining required From 10deef66f93a38727f91cf1927b3c38c1090ff3f Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 31 Oct 2026 15:42:19 +0100 Subject: [PATCH 07/10] Constrain consumer alias policy by artifact pinning standards --- .../release-management/accept-moved-release-tags.md | 5 +++++ src/docs/Capabilities/release-management/design.md | 13 +++++++++++-- src/docs/Capabilities/release-management/spec.md | 7 +++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/docs/Capabilities/release-management/accept-moved-release-tags.md b/src/docs/Capabilities/release-management/accept-moved-release-tags.md index 379bd396..92298d78 100644 --- a/src/docs/Capabilities/release-management/accept-moved-release-tags.md +++ b/src/docs/Capabilities/release-management/accept-moved-release-tags.md @@ -13,6 +13,11 @@ Do not use this procedure for exact version tags such as `v3.4.2`. Exact version tags are immutable. A moved exact tag is a producer integrity incident, not a normal update. +Use a mutable alias only when the consumer's artifact-specific pinning standard +permits it. The owned Action/reusable-workflow major-tag exception does not +authorize minor aliases; the examples here describe generic alias recovery, not +permission to relax that narrower standard. + ## Why an ordinary fetch can leave a stale tag Git protects existing local tags from being overwritten. An ordinary diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index bc22ab0c..ab17d462 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -528,10 +528,19 @@ company. External dependencies use the strongest immutable reference available. The [Dependencies standard](../../Coding-Standards/Dependencies.md) owns the broader pinning and update trade-off. +The consumer's artifact-specific pinning standard is an additional constraint, +not replaced by trust or alias availability. The owned-automation controlled +major-tag exception does not authorize a minor alias for Actions or reusable +workflows. Such a consumer can express patch-only update selection while +retaining the required immutable reference; it does not acquire broader mutable +pinning permission from this policy table. + Before `1.0.0`, SemVer permits a breaking change in each minor version. A major alias such as `v0` therefore crosses potentially breaking `0.y.z` releases. A -consumer that wants patch-only movement before `1.0.0` uses a minor alias such -as `v0.4`, not `v0`. +consumer that wants patch-only movement before `1.0.0` uses a native minor bound +or a permitted minor alias such as `v0.4`, not `v0`. Where its narrower pinning +standard permits only an immutable reference, bounded update selection resolves +and records the exact version or fingerprint instead. ## Ordering, idempotency, and reconciliation diff --git a/src/docs/Capabilities/release-management/spec.md b/src/docs/Capabilities/release-management/spec.md index 75d3863a..aafba54b 100644 --- a/src/docs/Capabilities/release-management/spec.md +++ b/src/docs/Capabilities/release-management/spec.md @@ -513,6 +513,13 @@ MUST be pinned to an immutable fingerprint or exact immutable version. `latest` MAY discover a release without an alias, then resolve it to the reference allowed by the trust boundary. +Policy expressibility does not grant permission to retain a mutable reference. +Consumers MUST also satisfy their artifact-specific pinning standard. For owned +Actions and reusable workflows, the controlled major-tag exception does not +authorize a minor alias; a patch-only policy uses immutable references with +bounded update selection when that standard requires them. Producer alias +availability alone MUST NOT relax the narrower consumer rule. + #### FR14 scenarios ```gherkin From 67a91f7fa79ba87ffc96878d15f704e58ddab7e8 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 31 Oct 2026 16:05:45 +0100 Subject: [PATCH 08/10] Allow immutable bounded updates in release conformance scenarios --- .../Capabilities/release-management/design.md | 17 +++++++----- .../Capabilities/release-management/spec.md | 26 ++++++++++++++----- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index ab17d462..93704dd1 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -510,17 +510,20 @@ The consumer resolves one of five policies: | Policy | Producer mechanism | Durable consumer reference | | --- | --- | --- | | `latest` | Discover the greatest eligible completed stable release. | The discovered immutable version or fingerprint required by trust policy. | -| `lock-major-boundary` | Supported native major-bounded constraint, or producer major alias for an opaque reference field. | The resolved immutable reference required by trust policy, or an allowed owned alias. | -| `lock-minor-boundary` | Supported native minor-bounded constraint, or producer minor alias for an opaque reference field. | The resolved immutable reference required by trust policy, or an allowed owned alias. | +| `lock-major-boundary` | Supported native major-bounded constraint, permitted bounded update selection, or a permitted producer major alias. | The resolved immutable reference required by trust policy, or an allowed owned alias. | +| `lock-minor-boundary` | Supported native minor-bounded constraint, permitted bounded update selection, or a permitted producer minor alias. | The resolved immutable reference required by trust policy, or an allowed owned alias. | | `lock-specific-version` | Exact immutable version. | Exact version. | | `lock-immutable-fingerprint` | Content digest, commit SHA, or equivalent. | Immutable fingerprint. | A requested boundary is unsupported only when neither the consumer/target's -native constraints nor a permitted matching producer alias can express it; it -is never widened silently. PowerShell Gallery and NuGet consumers can use their -supported native bounds without producer aliases. When a field accepts only -one opaque Git or container reference, a text such as `>=3,<4` is not a range -expression; its bound requires the corresponding controlled alias. +native constraints, permitted bounded update selection, nor a permitted +matching producer alias can express it; it is never widened silently. +PowerShell Gallery and NuGet consumers can use their supported native bounds +without producer aliases. Bounded update selection can likewise retain an +immutable reference without requiring an alias. When a field accepts only one +opaque Git or container reference, a text such as `>=3,<4` is not a range +expression. Without a permitted resolver outside that field, its bound +requires the corresponding permitted controlled alias. Moving references are allowed only for producers inside the consumer's declared trust boundary. Another team is external even when it belongs to the same diff --git a/src/docs/Capabilities/release-management/spec.md b/src/docs/Capabilities/release-management/spec.md index aafba54b..fd7fdb88 100644 --- a/src/docs/Capabilities/release-management/spec.md +++ b/src/docs/Capabilities/release-management/spec.md @@ -500,12 +500,15 @@ A consumer MAY select exactly one of these policies: | `lock-immutable-fingerprint` | No automatic movement from one exact content identity. | When no policy is selected, the consumer MUST use the most immutable reference -available. A boundary policy MUST use a supported native version constraint or, -when the consumer syntax has no range resolver, the corresponding producer -major or minor alias. A target with native bounded ranges MUST NOT require a -moving alias merely to express that bound. Resolve and retain the immutable -reference required by the trust policy. A range-like string in an opaque Git or -container reference field MUST NOT be treated as a resolver expression. +available. A boundary policy MUST use a supported native version constraint, +permitted bounded update selection, or a permitted corresponding producer major +or minor alias. Native bounded ranges and permitted bounded update selection +MUST NOT require a moving alias merely to express that bound. When neither +resolver is available, an opaque reference field requires the matching +permitted alias; otherwise the boundary is unsupported. Resolve and retain the +immutable reference required by the trust policy. A range-like string in an +opaque Git or container reference field MUST NOT be treated as a resolver +expression. Mutable aliases MAY be used only within the consumer's permitted trust boundary. An external producer, including one owned by another team in the same company, @@ -526,11 +529,22 @@ availability alone MUST NOT relax the narrower consumer rule. Scenario: An unsupported boundary policy fails explicitly Given a consumer requests lock-minor-boundary And its consumer field has no native range resolver + And permitted bounded update selection is unavailable And the producer does not publish the minor alias family When the policy is resolved Then the request fails as unsupported And it is not widened to latest or a major boundary +Scenario: Bounded updates retain a SHA-pinned reference + Given an Action or reusable-workflow consumer requests lock-minor-boundary + And permitted bounded update selection is available + And its reference is a full commit SHA + And the producer publishes no minor alias + When a newer compatible patch is selected + Then the reference is updated to that patch's full commit SHA + And the selected major and minor remain unchanged + And no minor alias is retained + Scenario: A native bounded range does not require an alias Given a consumer requests lock-minor-boundary And its target supports a native minor-bounded range From 9f92fa1ad8f8f4d56e79f52a40acee09a3bdbad4 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sat, 31 Oct 2026 16:14:52 +0100 Subject: [PATCH 09/10] Allow bounded immutable updates in native publishing targets --- .../design-publishing-targets.md | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/docs/Capabilities/release-management/design-publishing-targets.md b/src/docs/Capabilities/release-management/design-publishing-targets.md index 58c3e786..9c94a25e 100644 --- a/src/docs/Capabilities/release-management/design-publishing-targets.md +++ b/src/docs/Capabilities/release-management/design-publishing-targets.md @@ -25,7 +25,7 @@ Every target documents seven dimensions: | **Immutability** | Which reference cannot change and what a repeated publication does. | | **Withdrawal** | The strongest supported hide, unlist, yank, or delete operation and whether existing consumers retain access. | | **Alias families** | Whether `latest`, major, or minor moving references can be represented and reconciled. | -| **Version constraints** | Whether consumers can express native ranges or need a producer-controlled alias. | +| **Version constraints** | Whether native ranges or permitted bounded update selection express the bound, or a permitted producer-controlled alias is required. | | **Release record** | Where the durable, linkable destination evidence is stored. | A target MUST answer all seven before it is enabled. It MUST also define: @@ -119,10 +119,14 @@ They are separate from exact version tags and can move only through Consumers must explicitly accept moved owned tags; see [Accept moved release tags](accept-moved-release-tags.md). -Git references do not resolve SemVer range expressions. A major or minor -boundary therefore requires the corresponding producer alias. External -consumers use an exact commit SHA or another immutable fingerprint rather than a -moving tag. +Git reference fields do not resolve SemVer range expressions. Permitted bounded +update selection can choose an immutable commit within the requested major or +minor boundary without a producer alias. The corresponding permitted alias is +required only when no other permitted resolver supplies the bound. If no +permitted resolver or alias can express it, resolution fails as unsupported. +The consumer's artifact-specific pinning standard still governs the retained +reference. External consumers use an exact commit SHA or another immutable +fingerprint rather than a moving tag. ### GitHub release record @@ -264,8 +268,12 @@ disappeared. Optional tags can implement the `latest`, major, and minor alias families. Reconciliation updates each enabled tag to the digest of the greatest eligible matching release. Container references do not evaluate SemVer ranges, so -consumers use a controlled producer alias inside the allowed trust boundary or -pin a digest. +permitted bounded update selection resolves the eligible version outside that +field and can retain its digest without a moving alias. A corresponding +controlled alias is required only when no other permitted resolver supplies +the requested bound. That alias must satisfy the consumer's trust boundary and +artifact-specific pinning standard; an unsupported bound fails rather than +widening silently. ### Container registry release record @@ -279,7 +287,8 @@ links that digest to source, notes, verification, and lifecycle state. versions to native coordinates and flags. 3. Define the immutable identity and read-back check used by idempotent retry. 4. Define the strongest supported withdrawal behavior and its limitations. -5. State which, if any, alias families and native constraints consumers can use. +5. State which native constraints, permitted bounded update selection, or + permitted alias families consumers can use. 6. Define publication, withdrawal, and reconciliation evidence. 7. Add the adapter to the required destination set so durable completion and phase-aware recovery include it. From 995dbab9a1115c768249f467e37ebd6b8686d7ac Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 1 Nov 2026 14:03:12 +0100 Subject: [PATCH 10/10] Use release.settings.yml in lifecycle guidance --- src/docs/Capabilities/release-management/design.md | 4 ++-- src/docs/Capabilities/release-management/spec.md | 2 +- src/docs/Capabilities/vscode-extension-framework/design.md | 4 ++-- src/docs/Ways-of-Working/Automation-Labels.md | 2 +- src/docs/Ways-of-Working/PR-Format.md | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index 93704dd1..e98d3859 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -31,7 +31,7 @@ Documentation alone does not make a lifecycle control or setting available. The effective pipeline establishes whether the target route produces a versioned, immutable output consumed by version. Managed routes participate whether they use a shared workflow or a native producer pipeline, and whether -`.github/release.config.yml` exists. Unmanaged routes omit release metadata and +`.github/release.settings.yml` exists. Unmanaged routes omit release metadata and every `release:*` label; a Pages deployment alone is not a versioned release. ## Release authority and interfaces {#branching-model} @@ -569,7 +569,7 @@ that belongs to earlier unresolved work. Repositories keep the existing MSX configuration file: ```text -.github/release.config.yml +.github/release.settings.yml ``` ### Configuration surface diff --git a/src/docs/Capabilities/release-management/spec.md b/src/docs/Capabilities/release-management/spec.md index fd7fdb88..fe2352d6 100644 --- a/src/docs/Capabilities/release-management/spec.md +++ b/src/docs/Capabilities/release-management/spec.md @@ -67,7 +67,7 @@ Out of scope: The effective target route determines applicability, including native producer pipelines that publish versioned, immutable outputs without a named shared workflow. A route without versioned release behavior carries no release metadata -or `release:*` labels. Absence of `.github/release.config.yml` does not opt a +or `release:*` labels. Absence of `.github/release.settings.yml` does not opt a managed route out. ## Requirements diff --git a/src/docs/Capabilities/vscode-extension-framework/design.md b/src/docs/Capabilities/vscode-extension-framework/design.md index ab8e2261..b1f9a7e0 100644 --- a/src/docs/Capabilities/vscode-extension-framework/design.md +++ b/src/docs/Capabilities/vscode-extension-framework/design.md @@ -204,7 +204,7 @@ Every external Action is pinned to a commit SHA; organization- or initiative-own | Explicit bump / prerelease / skip | owned pull-request label | | Default bump and overrides | shared `DefaultBump: patch`, repository settings, and supported caller inputs | | Pre-merge decision validation | version check required by the branch ruleset or protection | -| Release branches + path filter | `.github/release.config.yml` ([Release Management](../release-management/design.md)) | +| Release branches + path filter | `.github/release.settings.yml` ([Release Management](../release-management/design.md)) | | Marketplace publish tokens | a GitHub environment's secrets | | Extension manifest (`engines.vscode`, `contributes`, activation) | `package.json` | @@ -218,7 +218,7 @@ The template repository lays down the whole shape, mirroring `contributes`, `activationEvents`, and `main` pointing at the bundle. - the bundler config, `tsconfig.json`, and `.vscodeignore`. - `install/` — the hosted one-liner install scripts. -- `.github/` — the caller workflow, `vscode-extension.yml`, `release.config.yml`, +- `.github/` — the caller workflow, `vscode-extension.yml`, `release.settings.yml`, and `dependabot.yml`. ## Where this connects diff --git a/src/docs/Ways-of-Working/Automation-Labels.md b/src/docs/Ways-of-Working/Automation-Labels.md index fd3b4439..64f4b633 100644 --- a/src/docs/Ways-of-Working/Automation-Labels.md +++ b/src/docs/Ways-of-Working/Automation-Labels.md @@ -60,7 +60,7 @@ This set applies only when the pull request's target route invokes Release Management, including through a native producer pipeline. An unmanaged route does not apply or report any `release:*` label, including `release:skip`. The optional -`.github/release.config.yml` file refines an invocation; its absence alone does +`.github/release.settings.yml` file refines an invocation; its absence alone does not determine whether the route invokes the capability. These labels are read by diff --git a/src/docs/Ways-of-Working/PR-Format.md b/src/docs/Ways-of-Working/PR-Format.md index ffb444bd..96774dd3 100644 --- a/src/docs/Ways-of-Working/PR-Format.md +++ b/src/docs/Ways-of-Working/PR-Format.md @@ -88,7 +88,7 @@ target route. Inspect the effective pipeline and its inputs, including native producer pipelines that publish versioned artifacts without calling a named shared workflow. The [applicability contract](../Capabilities/release-management/design.md#applicability) is about the route's release behavior, not one implementation. The optional -`.github/release.config.yml` file refines the route's settings; its absence alone +`.github/release.settings.yml` file refines the route's settings; its absence alone does not prove that release management is absent. Verify the immutable producer revision's supported settings and owned-label @@ -324,7 +324,7 @@ from the actual base. When the target route does not invoke Release Management, omit this block and all `release:*` labels. Do not add `release:skip` merely because the repository -has no `.github/release.config.yml`. +has no `.github/release.settings.yml`. ### Assemble the body