Skip to content
Merged
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
15 changes: 8 additions & 7 deletions .agents/skills/maintainer/delivery-lifecycle-maintainer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,22 +127,23 @@ content-equivalent metadata/ref changes, document equivalence and rebind the
receipt with the issuing agent; do not copy mismatched identities into a packet
or replay unrelated product journeys. Recheck exact-source CI for releases.

### 5. Integrate main-first, then recheck
### 5. Integrate through a protected PR, then recheck

For an explicitly authorized local integration:

1. Inspect current target `main`, remote ref/SHA, branch tips, and the dirty
path/index baseline. Record all six (or however many) candidate branch refs
rather than collapsing them into “the branches”.
2. Attempt the smallest direct main-first operation. If it is conflict-free
and no concurrent-write/destructive risk exists, keep the named checkout.
2. Prepare integration on a working branch and open/update its PR targeting
`main`. Never push commits directly to `main` or bypass protection, including
for release preparation or version handoffs.
3. On a real conflict or risk trigger, create a detached isolated worktree and
perform the merge/rebase there. Validate the exact candidate tree, tests,
and receipts before touching the shared ref.
4. Use compare-and-swap semantics against the recorded expected-old target
SHA. If the target or remote moved, stop, record non-fast-forward/drift,
refreeze against the new base, and reverify. Never silently merge onto a
newer target.
4. Merge only with integration authority, current review/verifier evidence,
and passing required PR checks. If the target or remote moved, record drift,
update the PR against the new base, and reverify affected behavior. Record
the actual merged SHA and exact-source CI; do not update the shared ref by hand.
5. Never run `git read-tree` against the shared checkout's live index. A ref
update does not require an index update. If a disposable index view is
needed for comparison, set `GIT_INDEX_FILE` to an explicit temporary path,
Expand Down
7 changes: 4 additions & 3 deletions .agents/skills/maintainer/release-maintainer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@ a package, or another surface authorizes that surface and its prerequisites.
Resolve a bare `publish` from context; do not expand it into a full version release.

1. resolve and lock the single consistent version and source SHA;
2. land reviewed release source on `main` when needed;
2. land reviewed release source on `main` through a PR and required checks when needed;
3. run required exact-source CI, preflight, and package validation once;
4. publish npm, tag, GitHub Release, Desktop, and production-docs surfaces;
5. verify public installation, clean obsolete canary Releases/tags, and advance
the next-version base;
the next-version base through its protected-branch PR;
6. when explicitly authorized, publish and read back the stable Discord announcement.

Do not create a release PR or ask for routine second approval after validation.
Release and next-version PRs are part of this authorization. Never push directly
to `main` or bypass its protection. Do not ask for routine second approval after validation.
Ask only when channel, version, source, or destination is materially ambiguous.

Questions such as “how does release work?” or “is this ready?” are read-only.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ Before completion, record:
- GitHub Release name, prerelease/draft flags, and assets;
- install/update proof appropriate to the changed area;
- obsolete canary cleanup and retained active line;
- next-version main handoff and its CI;
- next-version PR URL, required checks, merged `main` SHA and its CI; report an
unmerged PR as pending integration even when the Release workflow succeeded;
- when announcement delivery is requested, its server, channel, direct message
URL, ping state, follower cross-post state, and rendered readback; otherwise
`Announcement: not requested`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ The standard sequence is:
`npx @rudderhq/cli@latest start --no-open` path and the resulting persistent
`rudder start --no-open` command;
7. remove obsolete canary GitHub Releases/tags at or below the stable base;
8. advance the next patch base directly on `main` with `[skip release]` and
dispatch CI for that immutable handoff SHA.
8. open or reuse the next-patch `[skip release]` PR and dispatch CI for its
immutable handoff SHA; merge through the protected PR flow after checks pass,
then verify the merged `main` CI. A proposed PR is pending integration.

If npm succeeds and a downstream step fails, stop the normal stable path and
use `partial-recovery.md`; do not republish.
Expand Down
23 changes: 19 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
workflow_dispatch:
inputs:
source_sha:
description: "Optional immutable source SHA to verify with the trusted main-branch Test workflow"
description: "Optional immutable source SHA; dispatch on main or a controlled release-maintenance branch"
required: false
type: string

Expand Down Expand Up @@ -60,8 +60,13 @@ jobs:
run: |
set -euo pipefail
[[ "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]]
test "$GITHUB_REF" = "refs/heads/main"
test "$(git rev-parse HEAD)" = "$SOURCE_SHA"
if [ "$GITHUB_REF" = "refs/heads/main" ]; then exit 0; fi
[[ "$GITHUB_REF" =~ ^refs/heads/codex/release-v[0-9]+\.[0-9]+\.[0-9]+$ ]]
test "$GITHUB_SHA" = "$SOURCE_SHA"
git fetch origin +refs/heads/main:refs/remotes/origin/main
git diff --exit-code refs/remotes/origin/main HEAD -- .github/workflows/ci.yml scripts/ci-dispatch-source.mjs
node scripts/ci-dispatch-source.mjs

- name: Resolve comparison source
id: comparison
Expand Down Expand Up @@ -188,8 +193,13 @@ jobs:
run: |
set -euo pipefail
[[ "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]]
test "$GITHUB_REF" = "refs/heads/main"
test "$(git rev-parse HEAD)" = "$SOURCE_SHA"
if [ "$GITHUB_REF" = "refs/heads/main" ]; then exit 0; fi
[[ "$GITHUB_REF" =~ ^refs/heads/codex/release-v[0-9]+\.[0-9]+\.[0-9]+$ ]]
test "$GITHUB_SHA" = "$SOURCE_SHA"
git fetch origin +refs/heads/main:refs/remotes/origin/main
git diff --exit-code refs/remotes/origin/main HEAD -- .github/workflows/ci.yml scripts/ci-dispatch-source.mjs
node scripts/ci-dispatch-source.mjs

- name: Architecture audit tests
run: node --test scripts/architecture-audit.test.mjs scripts/architecture-boundaries.test.mjs
Expand Down Expand Up @@ -530,8 +540,13 @@ jobs:
run: |
set -euo pipefail
[[ "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]]
test "$GITHUB_REF" = "refs/heads/main"
test "$(git rev-parse HEAD)" = "$SOURCE_SHA"
if [ "$GITHUB_REF" = "refs/heads/main" ]; then exit 0; fi
[[ "$GITHUB_REF" =~ ^refs/heads/codex/release-v[0-9]+\.[0-9]+\.[0-9]+$ ]]
test "$GITHUB_SHA" = "$SOURCE_SHA"
git fetch origin +refs/heads/main:refs/remotes/origin/main
git diff --exit-code refs/remotes/origin/main HEAD -- .github/workflows/ci.yml scripts/ci-dispatch-source.mjs
node scripts/ci-dispatch-source.mjs

- uses: actions/setup-node@v6
with:
Expand Down
23 changes: 17 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1784,7 +1784,7 @@ jobs:
run: node scripts/cleanup-obsolete-canaries.mjs --repo "$GITHUB_REPOSITORY" --remote origin --stable-version "${{ needs.preflight.outputs.version }}"

next-release-base:
name: Advance next release base
name: Propose next release base
needs:
- preflight
- publish-stable
Expand All @@ -1794,6 +1794,7 @@ jobs:
permissions:
actions: write
contents: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
Expand All @@ -1804,17 +1805,27 @@ jobs:
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Advance main to the next patch version
- name: Open the next patch version pull request
id: next-release
env:
GH_TOKEN: ${{ github.token }}
run: node scripts/prepare-next-release.mjs --stable-version "${{ needs.preflight.outputs.version }}"
- name: Start Test for the advanced release base
if: steps.next-release.outputs.action == 'updated'
- name: Start Test for the proposed release base
if: steps.next-release.outputs.action == 'proposed'
env:
GH_TOKEN: ${{ github.token }}
run: gh workflow run ci.yml --ref main -f source_sha="${{ steps.next-release.outputs.head_sha }}"
HANDOFF_BRANCH: ${{ steps.next-release.outputs.branch }}
HANDOFF_SHA: ${{ steps.next-release.outputs.head_sha }}
run: gh workflow run ci.yml --ref "$HANDOFF_BRANCH" -f source_sha="$HANDOFF_SHA"
- name: Record the protected-branch handoff
if: steps.next-release.outputs.action == 'proposed'
env:
HANDOFF_PR: ${{ steps.next-release.outputs.pr_url }}
run: |
echo "Next release base PR (merge pending required checks): $HANDOFF_PR" >> "$GITHUB_STEP_SUMMARY"

stable-release-result:
name: Require complete stable release
name: Require published stable surfaces and handoff PR
needs:
- preflight
- publish-stable
Expand Down
19 changes: 12 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,19 +188,23 @@ separate transitions.

- `start`, `continue`, `proceed`, `implement`, `finish`, or approval of a plan
authorizes implementation, verification, and the section 10 Git handoff. The default stopping point
is Review Ready: validated changes committed and pushed on the current branch,
a PR when appropriate, review evidence, and a release-risk summary.
is Review Ready: validated changes committed and pushed on a working branch,
a PR targeting `main`, review evidence, and a release-risk summary.
- An explicit imperative to release a Rudder version, such as `release vX.Y.Z`,
`ship this version`, or `发版`, authorizes the complete standard release
lifecycle when the conversation identifies that version release as the target.
Publishing only named docs, a package, or another surface stays limited to
that surface. A bare `publish` is interpreted from context, not as automatic
authority for every release target. The version lifecycle includes committing
and pushing the reviewed source directly
to `main`, running CI and the release dry-run, publishing npm/GitHub/Desktop/
reviewed source on a working branch and merging its PR after protected-branch
checks pass, running exact-source CI and release validation, publishing npm/GitHub/Desktop/
production-docs surfaces, verifying them, cleaning obsolete canary
Releases/tags, and completing the direct next-version handoff. Do not create a
release PR or ask for another authorization during this lifecycle.
Releases/tags, and completing the next-version handoff through a PR. These PRs
are part of the authorized lifecycle; do not ask for routine second approval.
- `main` is protected for everyone, including administrators and automation.
All changes, including features, fixes, docs, release preparation, and version
bumps, enter through a PR with required checks. Never push commits directly to
`main`, bypass its rules, or disable protection to finish a task or release.
- If the release request omits a version, infer the single consistent target
from the current release context and repository release scripts, lock its
source SHA, and state both in a progress update. Ask only when the channel,
Expand Down Expand Up @@ -372,7 +376,8 @@ A change is done when all are true:
5. The authorized Git handoff is complete, or a concrete external blocker is reported.

- After scoped edits and applicable validation, commit and push the task's changes
to the current remote branch, including instruction/doc fixes. This standing
to a working branch and open/update its PR, including instruction/doc fixes.
If the checkout is on `main`, create a `codex/` branch before committing. This standing
authority does not authorize merging another branch, release, or deployment.
Honor a user request for local-only work or no commit/push.
- Continue using the repository's Conventional Commit format for commit messages (for example `feat:`, `fix:`, `test:`, `chore:`, `pref:`).
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ PRs that follow this path are **much** more likely to be accepted, even when the

## General Rules (both paths)

- Every change enters protected `main` through a pull request, including release
preparation and version bumps. Push a working branch, open a PR, and wait for
the required `Qualification summary` check before merging. Direct pushes,
force pushes, and protection bypasses are prohibited for contributors,
administrators, and automation alike.
- Write clear commit messages
- Keep PR title + description meaningful
- One PR = one logical change (unless it's a small related group)
Expand Down
9 changes: 9 additions & 0 deletions doc/engineering/DEVELOPING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
This guide is the entrypoint for local development.
It keeps the shortest path here and routes deep operational details to focused docs.

## Protected Main Workflow

Create a working branch before making commits (`codex/` for agent work), push
that branch, and open a PR targeting `main`. All changes use this path, including
docs, release preparation, and version bumps. Required qualification checks must
pass before PR merge. Administrators and automation have no direct-push bypass.
See [release automation setup](RELEASE-AUTOMATION-SETUP.md#7-protected-main-release-flow)
for the enforced branch rules and automatic version-handoff PRs.

## Deployment Modes

For mode definitions and intended CLI behavior, see `doc/engineering/DEPLOYMENT-MODES.md`.
Expand Down
8 changes: 5 additions & 3 deletions doc/engineering/PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,11 @@ summary, locale-appropriate headings, and only non-empty categories. CI,
workflow, branch, source-locking, approval, and deployment mechanics belong in
maintainer records rather than the public changelog.
After both the stable and public changelog deploy succeed,
`scripts/prepare-next-release.mjs` idempotently updates current `main` to the
next patch base with one `[skip release]` maintenance commit pushed directly to
`main`, then explicitly dispatches Test for that exact SHA.
`scripts/prepare-next-release.mjs` idempotently proposes the next patch base on
`codex/release-vX.Y.Z` with one `[skip release]` maintenance commit and a PR.
Release explicitly dispatches Test for that exact SHA because `GITHUB_TOKEN`
PR creation does not trigger normal PR checks. Merge through protected `main`
after required checks pass, then verify the merged commit's CI.

## Version formats

Expand Down
54 changes: 36 additions & 18 deletions doc/engineering/RELEASE-AUTOMATION-SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This document covers the GitHub and npm setup required for the current Rudder re
- manual stable promotion from a full locked commit SHA
- npm trusted publishing via GitHub OIDC
- optional Tencent COS Desktop mirroring via GitHub OIDC and Tencent STS
- direct-main release execution with exact-source Test
- protected-PR integration and release execution with exact-source Test

Repo-side files that depend on this setup:

Expand All @@ -17,10 +17,17 @@ Repo-side files that depend on this setup:

The `Release` workflow needs `actions: write` because it inspects exact-source
Test runs and starts Test for the generated post-stable version commit. It needs
`contents: write` to push release tags and the direct version handoff commit to
`main`. A tag or branch push performed with `GITHUB_TOKEN` will not, by itself,
trigger a second workflow run, so the workflow dispatches handoff Test
explicitly.
`contents: write` to push release tags and the version handoff branch, plus
`pull-requests: write` to open its PR. Enable **Allow GitHub Actions to create
and approve pull requests** in repository Actions settings. No release job gets
a bypass for protected `main`. A tag/branch push or PR creation performed with
`GITHUB_TOKEN` does not trigger the usual follow-up workflow, so Release
explicitly dispatches Test **on the handoff branch** with its immutable
`source_sha`, so the required check attaches to the PR head. This controlled
dispatch requires the branch HEAD, a single parent reachable from `main`, and
unchanged CI workflow/guard code. It cannot qualify release publication, which
still requires a successful `main` run. The release operator merges that PR after required checks pass
and verifies CI on the resulting `main` commit.

Note:

Expand Down Expand Up @@ -269,15 +276,27 @@ Reasoning:
- the environment isolates stable credentials and limits use to `main` without
introducing an account switch or reviewer click

## 7. Direct `main` Release Flow
## 7. Protected `main` Release Flow

Stable release work does not require a PR, branch-protection approval, repository
attestation variable, or workflow confirmation phrase. The release agent pushes
the validated source directly to `main`; the workflow then requires that exact
SHA to have a successful `main` Test run before it can publish.
All changes enter `main` through a PR, including release preparation and the
post-stable version bump. Configure an active branch ruleset targeting
`refs/heads/main` with no bypass actors (including administrators and apps):

The generated post-stable `[skip release]` version commit is also pushed
directly to `main`, followed by an explicit CI dispatch for its immutable SHA.
- require a pull request and resolved review conversations;
- require the GitHub Actions `Qualification summary` check with an up-to-date base;
- block branch deletion and non-fast-forward updates.

The single-maintainer repository may require zero approving reviews while still
requiring a PR and checks. This does not waive independent task review gates.
Verify live repository rules rather than treating this document as enforcement.
Never disable protection or add a release bypass to resolve a failing check.

The release agent merges reviewed preparation PRs under the existing release
authority, then requires exact-source `main` Test before publishing. The
generated `[skip release]` version commit is proposed on
`codex/release-vX.Y.Z`; retries reuse its PR without force-pushing. The workflow
reports the PR as pending integration and dispatches Test for its immutable SHA.
Complete the handoff by merging the PR normally and verifying merged `main` CI.

## 7.1. Configure progressive qualification and candidate promotion

Expand Down Expand Up @@ -335,10 +354,8 @@ These files should always trigger code owner review:
- `doc/engineering/RELEASING.md`
- `doc/engineering/PUBLISHING.md`

If you want stronger controls, add a repository ruleset that explicitly blocks direct pushes to:

- `.github/workflows/**`
- `scripts/release*`
The protected `main` ruleset applies to these files as well. CODEOWNERS routing
does not replace the required PR and qualification checks.

## 10. Do Not Store a Claude Token in GitHub Actions

Expand Down Expand Up @@ -418,8 +435,9 @@ After at least one good canary exists:
from the matching `v0.1.0` source and passes public health checks
16. confirm Windows, macOS, and Linux public install smoke all pass; do not
remove a slow Windows smoke because it measures real installation behavior
17. confirm the workflow commits the next patch version directly to `main` and
dispatches Test for that exact commit, or reports that `main` already advanced
17. confirm the workflow opens/reuses the next-patch PR and dispatches Test for
that exact commit, or reports that `main` already advanced; merge its PR
after required checks pass and verify the resulting `main` CI

Start-path check:

Expand Down
Loading