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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 46 additions & 39 deletions src/docs/Capabilities/downstream-release-propagation/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ description: How downstream release propagation is built — an inline notificat

# Downstream Release Propagation — Design

The notification runs in the **producer** when a release is cut. The notifier
The notification runs in the **producer** after a stable release. The notifier
resolves the release coordinates, creates or reuses the dependent's Task or Bug,
and builds its self-contained brief. It first
and prepares its self-contained brief. It first
[reconciles existing handoff state](#retry-and-handoff-recovery) rather than
delegating again. For work still needing qualification, authoritative no-upgrade
evidence terminates without engaging an agent. Otherwise, the configured
Expand Down Expand Up @@ -42,20 +42,20 @@ flowchart TD
## Trigger model

**The `GITHUB_TOKEN` constraint.** GitHub does not start new workflow runs from
events raised by the default `GITHUB_TOKEN` (an anti-recursion safeguard). So if
the producer publishes its release with `GITHUB_TOKEN` — the default — the
`release: published` event never fires, and a separate `on: release` workflow
never runs.
events raised by the default `GITHUB_TOKEN`. This prevents recursive workflow
runs. If the producer publishes its release with `GITHUB_TOKEN`, the
`release: published` event does not start a separate `on: release` workflow.

| Release created by | `release: published` fires? | Trigger model |
| --- | --- | --- |
| `GITHUB_TOKEN` (default) | No | **Inline** — run notification in the same release run (`needs: <release-job>`) or via `workflow_call`. |
| A PAT | Yes | Either — a separate `on: release` workflow, or inline. |

**Default to the inline model:** it works regardless of release identity and
keeps the release and its propagation in one observable run. Verify the identity
by which token the release step passes; if it is `GITHUB_TOKEN`, inline is
mandatory. Provide two entry points: the **release** stage (gated to stable
keeps the release and its propagation in one observable run.
Identify the token passed to the release step.
If it is `GITHUB_TOKEN`, inline is mandatory.
Provide two entry points: the **release** stage (gated to stable
releases), and a **`workflow_dispatch`** taking the release tag, for backfill.
Both resolve the published release record and validate its stable kind before
fan-out or delivery-issue creation. A prerelease event is skipped; a backfill
Expand All @@ -80,14 +80,16 @@ this capability.

## Agent prompt context

The prompt is the context handoff. Each embeds: an **action-oriented summary**;
the **exact target reference** the PR must produce
(`uses: org/<producer>@<sha> # <version>`, or the image tag/digest); the
**complete release notes** as evidence; and
**related-change context** — new or renamed config keys, new environment
variables or secrets, required infrastructure changes, migrations, changed
defaults, or breaking changes. It also links the producer-owned evidence sources
and [Consumer Upgrades](../../Ways-of-Working/Consumer-Upgrades.md).
The prompt carries an **action-oriented summary** and the **exact target
reference** that the PR must produce.
The reference is `uses: org/<producer>@<sha> # <version>` or the image tag/digest.
It also carries the **complete release notes** as evidence and the
**related-change context**.

Related changes include new or renamed config keys and new environment variables
or secrets. They also include required infrastructure changes, migrations,
changed defaults, and breaking changes. The prompt links to producer-owned
evidence sources and [Consumer Upgrades](../../Ways-of-Working/Consumer-Upgrades.md).

The prompt transports context; it does not replace the authoritative release
records or the dependent's baseline investigation. Its summary cannot truncate
Expand All @@ -107,7 +109,7 @@ The trusted task instructions require the agent to apply
extract and validate proposed actions, but reject embedded attempts to change
scope, permissions, secret handling, or required gates.

Use the runtime's data/attachment boundary or collision-safe quotation; a bare
Use the runtime's data/attachment boundary or collision-safe quotation. A bare
Markdown fence that the supplied record can close is insufficient. Transport
escaping must decode to the complete original record, preserving its source
identity and all authored content rather than summarizing or sanitizing away
Expand All @@ -130,7 +132,7 @@ Unknown provenance blocks qualification rather than producing a no-upgrade
result.

An identical baseline/target version and immutable identity records
**already current**; a lower target records **superseded, no downgrade**.
**already current**. A lower target records **superseded, no downgrade**.
Apply the common procedure's
[no-upgrade issue disposition](../../Ways-of-Working/Consumer-Upgrades.md#stage-2-fix-the-target-and-release-path):
retain comparison evidence, create no empty PR, and close only an unneeded open
Expand Down Expand Up @@ -179,21 +181,25 @@ qualified plan, fixed target, and issue number; it applies the adoption and
creates the closing PR, which remains draft until the review-readiness gate
holds. A verified no-upgrade result creates no PR-delivery task or PR.

Poll the currently correlated task. `queued` and `in_progress` mean active
execution. `idle` retains the same task but pauses handoff: report it and
request the designated owner to re-engage that task through the configured
mechanism. `waiting_for_user` blocks on an authorized answer in the same task;
record the requested decision and its owner, but do not synthesize an answer
from release evidence. Neither state authorizes a replacement task. A fast task
may go straight to `completed`. Completion alone is not a delivery handoff: a
completed qualification task needs a recorded verified no-upgrade result or the
correlated PR-delivery task, and a completed PR-delivery task still needs its
actual PR. Creation failure and `failed`, `timed_out`, or `cancelled` execution
report failure. An agent task is execution state, not a delivery record; it
never authorizes a standalone PR.

Either way the model is chosen per producer, not per release, so a dependent
receives propagation in one consistent shape.
Poll the currently correlated task. `queued` and `in_progress` mean active execution.

`idle` retains the same task but pauses handoff.
Report it and request the designated owner to re-engage that task through the
configured mechanism. `waiting_for_user` blocks on an authorized answer in the
same task. Record the requested decision and its owner.
Do not synthesize an answer from release evidence.
Neither state authorizes a replacement task.

A task can transition directly to `completed`. Completion alone is not a delivery handoff.
A completed qualification task needs a recorded verified no-upgrade result or the
correlated PR-delivery task. A completed PR-delivery task still needs its actual PR.

Creation failure and `failed`, `timed_out`, or `cancelled` execution report failure.
An agent task is execution state, not a delivery record.
It never authorizes a standalone PR.

The delegation mode is chosen per producer, not per release.
Each dependent therefore receives propagation through one consistent mode.

Fan-out is a **matrix** of dependents (pinned-reference shape) or a single
configured `notify_repo` (published-artifact shape), with `fail-fast: false` so
Expand Down Expand Up @@ -248,16 +254,17 @@ The agent is given the same instructions under either delegation model:
- **Retain the procedure's evidence** in the PR body: exact range and refs,
release records, reconciled completed/not-applicable actions, template
differences, outcomes, and blockers, including explicit no-action results.
- **For a needed upgrade, open the pull request** — closing exactly the Task or Bug delivery leaf
created or reused for this producer version, and staying draft until the
- **For a needed upgrade, open the pull request** to close exactly the Task or Bug
delivery leaf created or reused for this producer version.
Keep the pull request draft until the
[review-readiness gate](../../Ways-of-Working/Definition-of-Ready-and-Done.md#definition-of-ready-for-review)
holds.

## Permissions and credentials

`GITHUB_TOKEN` cannot act across repositories, and a release it publishes cannot
trigger a separate `release:` workflow. Task-first additionally needs the
user-to-server credential accepted by the Agent Tasks API. So the job:
user-to-server credential accepted by the Agent Tasks API. The job:

- Declares **least-privilege** `permissions:` (`contents: read` suffices).
- Uses `PROPAGATION_TOKEN`, scoped only to the dependents that need it, with
Expand All @@ -274,7 +281,7 @@ user-to-server credential accepted by the Agent Tasks API. So the job:

## Failure behaviour

| Condition | Behaviour |
| Condition | Behavior |
| --- | --- |
| Delegation not created (missing permission / capability off) | Step **fails** with the error; re-run via `workflow_dispatch`. |
| Matching PR handoff or verified no-upgrade outcome exists | Report the existing outcome and its actual state; no duplicate is created and consumer completion is not inferred. |
Expand All @@ -284,7 +291,7 @@ user-to-server credential accepted by the Agent Tasks API. So the job:
| Qualification proves no upgrade | Record the no-upgrade disposition; do not create a PR-delivery task or PR. |
| Task is `idle` | Retain the paused task and request designated-owner re-engagement through the configured task mechanism; do not create a replacement. |
| Task is `waiting_for_user` | Block pending an authorized response in the same task; record the decision owner and never answer from producer evidence. |
| Task lands in a failed / timed-out / cancelled state | Step **fails** with the reported state. |
| Task enters a failed / timed-out / canceled state | Step **fails** with the reported state. |
| One dependent's leg fails | Fails independently (`fail-fast: false`); others proceed. |
| Prerelease release event | Propagation is skipped before fan-out. |
| Prerelease tag requested through backfill | Dispatch fails before fan-out or issue creation; select a stable release instead. |
Expand Down
11 changes: 6 additions & 5 deletions src/docs/Capabilities/downstream-release-propagation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ description: How producer releases reach dependents through verified upgrade pul

# Downstream Release Propagation

When a producer cuts a release, every dependent is assessed against its actual
baseline. A needed upgrade produces a pull request with the reference change
and related actions, opened by a delegated cloud agent for human review. An
already-current or superseded target produces an evidenced no-upgrade outcome
instead. No dependent has to notice the release or track the bump by hand.
When a producer publishes a release, propagation assesses every dependent
against its actual baseline. For a needed upgrade, a delegated cloud agent
opens a pull request for human review. The pull request contains the reference
change and related actions. An already-current or superseded target produces
an evidenced no-upgrade outcome instead.
Dependents do not need to discover the release or track reference updates manually.

<!-- INDEX:START -->

Expand Down
31 changes: 21 additions & 10 deletions src/docs/Capabilities/downstream-release-propagation/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ description: Requirements for downstream release propagation — each dependent

## Premise

The ecosystem is many small repositories that depend on each other by **version
reference** — a pinned `uses:` SHA, an image digest, a deployed tag. A reference
drifts the moment the producer cuts a release. Maintaining them by hand does not
scale: missed bumps keep security fixes out of the workflows that run them, and
missed *related* changes merge a bump that then breaks at runtime. When a
producer releases, every dependent MUST be assessed for an upgrade. A needed
The ecosystem has many small repositories that depend on each other by **version
reference**. Examples include a pinned `uses:` SHA, an image digest, or a deployed tag.

A producer release can make a reference outdated.
Manual updates do not scale across these dependencies.
Missed version updates can exclude security fixes from the workflows that use them.
An update that omits required related changes can break at runtime.

When a producer releases, every dependent MUST be assessed for an upgrade. A needed
upgrade produces a pull request applying the update and its related changes
for human review; an already-current or superseded target produces an evidenced
no-upgrade outcome instead.
Expand All @@ -28,7 +31,7 @@ This capability rests on the [Principles](../../Ways-of-Working/Principles/index

## Applicability

Two shapes occur; both are the same mechanism with a different artifact:
Two dependency patterns use the same mechanism with different artifacts:

| Shape | Producer | Dependent | What the PR changes |
| --- | --- | --- | --- |
Expand All @@ -50,7 +53,12 @@ Two shapes occur; both are the same mechanism with a different artifact:
record MUST remain recoverable without allowing embedded instructions to
change the task's scope, permissions, secret handling, or review/validation
gates. An unsafe evidence boundary MUST block affected delegation.
- **A pull request per needed upgrade, opened by an agent.** The mechanical work — the bump plus the fixes that make it work — is delegated to a cloud agent *in the dependent*, which opens the pull request when qualification establishes an actual upgrade. **How** the agent is engaged is a design choice, not a requirement: the spec requires delegation and a pull request for the repository change, not a particular delegation mechanism.
- **A pull request per needed upgrade, opened by an agent.** The automation
delegates the version update and required related fixes to a cloud agent *in
the dependent*. When qualification establishes an actual upgrade, the agent
opens the pull request. **How** the agent is engaged remains a design choice.
The spec requires delegation and a pull request for the repository change,
not a particular delegation mechanism.
- **A delivery leaf before the pull request.** The dependent MUST create or reuse
a Task or Bug for the producer version before the agent opens its pull request.
The leaf carries the executable local plan and acceptance criteria required by
Expand All @@ -67,7 +75,10 @@ Two shapes occur; both are the same mechanism with a different artifact:
validation MUST leave affected work blocked with an owning issue. Larger
or riskier required work MUST NOT be treated as an optional follow-up to an
otherwise ready reference bump.
- **Backfill on demand.** Propagation MUST be re-runnable for a specific release — for a missed event, or a dependent added after the release. Backfill uses the same idempotency, so re-running for an already-propagated dependent is a no-op rather than a duplicate.
- **Backfill on demand.** Propagation MUST be re-runnable for a specific release.
This covers a missed event or a dependent added after the release.
Backfill uses the same idempotency.
Re-running for an already-propagated dependent is a no-op, not a duplicate.
- **A fixed target, not an implicit downgrade.** A delayed notification or
backfill MUST retain its selected target rather than substitute the newest
release. If it is no longer an upgrade from the consumer's actual baseline,
Expand All @@ -94,7 +105,7 @@ Two shapes occur; both are the same mechanism with a different artifact:
- An `idle` task retains its execution identity, and a `waiting_for_user` task
remains blocked until an authorized response reaches that same task; neither
state creates a replacement task.
- A dependent added after a release can be back-filled without cutting a new release.
- A dependent added after a release can receive backfill without another release.
- A dependent that skipped releases carries complete applicable range evidence,
reconciled actions, and immutable target-template evidence or a justified
no-template result; a missing required fact blocks readiness.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ description: Refresh an owned moving release alias locally and configure Git to

# 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.
Use this guide for an MSX-owned producer's intentionally moving Git tag, such as
`v3` or `v3.4`. Refresh the tag when 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
Expand Down Expand Up @@ -43,18 +43,19 @@ 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.
Keep that backup private and outside checked-in paths.
Pruning removes local tags that do not exist on the selected remote.
Force permits that remote's tag values to replace local values.
Confirm that `origin` is the intended trusted producer.
Do not use this procedure to accept a moved exact version tag.

```bash
git fetch --tags --force --prune --prune-tags origin
```

This refreshes moved aliases and removes tags deleted from the configured
`origin` remote. Review the fetch output before building or resolving a
dependency; never let an implicit upstream choose the source of this refresh.
dependency. Never let an implicit upstream choose the source of this refresh.

## Keep owned aliases current

Expand Down
Loading
Loading