Downstream Release Propagation — Design#
The notification runs in the producer when a release is cut. It resolves the release coordinates, builds a self-contained prompt per dependent, and delegates the change to a cloud agent in the dependent via the Agent Tasks API. The brief travels entirely in the prompt. The agent first creates or reuses the dependent's Task or Bug delivery issue, then opens the pull request with that delivery leaf as its one closing reference.
flowchart TD
rel["Producer release published"] --> notify["Notify job (in producer)"]
notify --> resolve["Resolve version + immutable ref (SHA / digest) + notes"]
resolve --> fan{"For each dependent"}
fan --> delegate["Create agent task in dependent<br/>self-contained prompt with full context"]
delegate --> issue["Create or reuse Task / Bug delivery issue"]
issue --> pr["Agent opens closing PR: bump + related fixes + impact"]
pr --> review["Human review + merge"]
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.
| 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
releases), and a workflow_dispatch taking the release tag, for backfill.
Release coordinate resolution#
| Coordinate | Meaning |
|---|---|
version |
Human-readable version — travels only as a tag / trailing comment |
| immutable ref | The commit SHA (pinned-reference) or image digest (published-artifact) that dependents pin to |
release_notes |
The producer's release body, embedded verbatim in the prompt |
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
release notes verbatim; and
related-change context — new or renamed config keys, new environment
variables or secrets, required infrastructure changes, migrations, changed
defaults, or breaking changes. It is assembled in code and is the single source
of truth for the change.
Delegation#
Two delegation modes can carry the request into the dependent. Both create or reuse a real Task or Bug delivery leaf before a pull request exists, so the delivery path satisfies the Definition of Ready.
| Task-first | Issue-first | |
|---|---|---|
| The request is | an agent task created after its delivery leaf exists | an issue in the dependent, which the agent picks up |
| The agent produces | a pull request closing the delivery leaf | a pull request closing that issue |
| Idempotency key | the delivery issue — one per producer version per dependent | the issue itself — one issue per producer version per dependent |
| Visible before the agent starts | the delivery issue and task state | the issue |
| Suits | immediate execution after the delivery leaf is ready | propagation that needs triage, discussion, or scheduling before work starts |
Issue-first is the default: it creates or reuses one Task or Bug in the dependent per producer version, with independently verifiable acceptance criteria and an executable local plan. The issue is the delivery leaf before the agent starts, then the agent opens the pull request that closes exactly that issue. Idempotency is by existence: the issue is the durable record that this version was propagated, so a repeat run finds and reuses it.
Task-first is available only when the agent task is created after the same
Task or Bug is created or reused. The task carries the issue number and instruction
to close it, then is polled until it reaches queued, in_progress, or
completed (a fast task may go straight to completed). It fails only if the
task cannot be created or lands in failed, timed_out, or cancelled. An agent
task is execution state, not a delivery record; it never authorizes a standalone
delivery pull request.
Either way the model is chosen per producer, not per release, so a dependent receives propagation in one consistent shape.
Fan-out is a matrix of dependents (pinned-reference shape) or a single
configured notify_repo (published-artifact shape), with fail-fast: false so
one dependent's failure does not stop the rest.
Agent instructions#
The agent is given the same instructions under either delegation model:
- Apply the bump. Every matching reference, bringing any mutable-tag pins into SHA-pinned compliance.
- Read the release notes for related work. The notes are the producer's own account of what changed; the agent treats new or renamed configuration keys, new environment variables or secrets, changed defaults, and migrations as part of the update, not as someone else's problem.
- Apply the related changes it can make safely. A change that is mechanical and verifiable belongs in this pull request.
- Call out larger or riskier work under a follow-up section rather than forcing it into the bump. Scope that needs a decision is surfaced, not guessed at.
- Summarise impact in the PR body: what moved, what it requires of the dependent, and what was deliberately left out.
- Open the pull request — closing exactly the Task or Bug delivery leaf created or reused for this producer version.
Permissions and credentials#
GITHUB_TOKEN is unsuitable for three independent reasons: it cannot act across
repositories, it is not the user-to-server token the Agent Tasks API requires,
and a release it publishes cannot trigger a release: workflow. So the job:
- Declares least-privilege
permissions:(contents: readsuffices). - Uses
PROPAGATION_TOKEN— a user PAT carrying the Agent tasks permission, an org secret scoped to only the dependents that need it. Because the agent commits and opens the PR within its task session, the token does not itself push or open PRs. - Passes the secret explicitly by name when the notification is a reusable
workflow — never
secrets: inherit, per the GitHub Actions coding standard.
Failure behaviour#
| Condition | Behaviour |
|---|---|
| Delegation not created (missing permission / capability off) | Step fails with the error; re-run via workflow_dispatch. |
| This version already propagated to this dependent | Step succeeds, reporting the existing delivery issue and pull request if one exists; no duplicate is created. |
| Task lands in a failed / timed-out / cancelled state | Step fails with the reported state. |
| One dependent's leg fails | Fails independently (fail-fast: false); others proceed. |
| Prerelease published | Propagation is skipped. |
Where this connects#
- Spec — the requirements this design delivers.
- Release Management — produces the release and note this consumes.
- GitHub Actions — SHA pinning, least-privilege permissions, explicit secret passing.
- Security — the supply-chain rationale for immutable references.
- PR Format — the delivery-leaf closure contract used by the agent.