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
26 changes: 13 additions & 13 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@
/.github/codex-action-contract.json @loadinglucian
/.github/workflows/ @loadinglucian
/.github/CODEOWNERS @loadinglucian
/.github/maintenance-operator.json @loadinglucian
/.github/maintenance-pins.json @loadinglucian
/.github/autorelease-operator.json @loadinglucian
/.github/autorelease-pins.json @loadinglucian
/.codex/ @loadinglucian
/maintenance/ @loadinglucian
/autorelease/ @loadinglucian
/schemas/ @loadinglucian
/scripts/admit-maintenance-plan @loadinglucian
/scripts/capture-maintenance-evidence @loadinglucian
/scripts/configure-github-maintenance @loadinglucian
/scripts/maintenance-event @loadinglucian
/scripts/notify-maintenance @loadinglucian
/scripts/admit-autorelease-plan @loadinglucian
/scripts/capture-autorelease-evidence @loadinglucian
/scripts/configure-github-autorelease @loadinglucian
/scripts/autorelease-event @loadinglucian
/scripts/notify-autorelease @loadinglucian
/scripts/prepare-agent-task @loadinglucian
/scripts/seal-maintenance-patch @loadinglucian
/scripts/seal-autorelease-patch @loadinglucian
/scripts/snapshot-github-admin-state @loadinglucian
/scripts/validate-maintenance-archive @loadinglucian
/scripts/validate-autorelease-archive @loadinglucian
/scripts/validate-codex-action-inputs @loadinglucian
/scripts/validate-structured-output-schemas @loadinglucian
/scripts/verify-merge-admission @loadinglucian
/scripts/release-maintenance @loadinglucian
/scripts/watch-maintenance-evidence @loadinglucian
/maintenance/policy-invariants.json @loadinglucian
/scripts/publish-release @loadinglucian
/scripts/watch-autorelease-evidence @loadinglucian
/autorelease/policy-invariants.json @loadinglucian
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
"openai/codex-action": "52fe01ec70a42f454c9d2ebd47598f9fd6893d56"
},
"workflows": {
".github/workflows/maintenance-e2e.yml": "sha256:a495b86fb9c2b7477adc4e88b35db303a11193ab77096dee45865a8b2dd18f96"
".github/workflows/autorelease-e2e.yml": "sha256:677ad87c8c58bdb61e6fc8e54782b70a89533ac4916827414a7d639985949c6b"
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Investigation phase

Observable goal: classify exactly one action key from retained evidence and
produce a schema-valid, evidence-bound maintenance plan without modifying a
produce a schema-valid, evidence-bound autorelease plan without modifying a
repository or causing a GitHub mutation.

For every material release or lifecycle claim, cite one captured body by
Expand All @@ -14,18 +14,18 @@ captured evidence.
Plan evidence `captureId` values may name only a capture in the evidence
manifest or the two deterministic runtime inputs `evidence_manifest` and
`watch_decision`. Those runtime IDs resolve only to
`maintenance-run/evidence/evidence-manifest.json` and
`maintenance-run/watch-decision.json`; no other runtime or repository file is
`autorelease-run/evidence/evidence-manifest.json` and
`autorelease-run/watch-decision.json`; no other runtime or repository file is
admissible as plan evidence.

The required runtime inputs are generated before this phase and are available
at these exact paths:

- `maintenance-run/evidence/evidence-manifest.json`
- `autorelease-run/evidence/evidence-manifest.json`
- the captured bodies named by each manifest entry, resolved relative to
`maintenance-run/evidence/`
- `maintenance-run/preconditions.json`
- `maintenance-run/watch-decision.json`
`autorelease-run/evidence/`
- `autorelease-run/preconditions.json`
- `autorelease-run/watch-decision.json`

These runtime files are intentionally gitignored, so discovery commands that
respect `.gitignore` (including `rg --files`) may omit them. Read the exact paths
Expand All @@ -43,7 +43,7 @@ advisory checks. Declare them in the plan, but do not run them in this read-only
phase or treat their not-yet-run status as unresolved; writable deterministic
jobs execute them before merge.

If changed evidence has no maintenance consequence, use action `no_change` and
If changed evidence has no autorelease consequence, use action `no_change` and
the key `no_change:<first 16 hexadecimal characters of the evidence manifest
digest>` so the reviewed snapshot remains uniquely auditable.

Expand All @@ -53,7 +53,7 @@ action, include a `php_release_feed` JSON-pointer evidence item whose resolved
value is the exact `releaseIntent.version`; otherwise classify the tag-only
change as `no_change` until the official feed publishes that version.

The plan `actionKey` identifies the classified maintenance action, not the
The plan `actionKey` identifies the classified autorelease action, not the
phase-scoped action key in the event contract. It must use one of the reviewed
forms enforced by the output schema: `no_change`, `new_patch`, `new_branch`,
`branch_eol`, `recipe_rebuild`, `repair`, `source_unhealthy`, `health_failed`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Guarded PHP maintenance agent instructions
# Autorelease agent instructions

The overarching goal is one production maintenance system across
The overarching goal is one production autorelease system across
`bigpixelrocket/php-bin` and `bigpixelrocket/mise-php` that detects upstream
PHP release or lifecycle changes, prepares bounded repository work, coordinates
both repositories, and permits deterministic controls to publish immutable,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Maintenance end to end
name: Autorelease end to end

on:
workflow_dispatch:
Expand Down Expand Up @@ -26,11 +26,49 @@ permissions:
contents: read

concurrency:
group: maintenance-e2e-${{ inputs.suite }}
group: autorelease-e2e-${{ inputs.suite }}
cancel-in-progress: false

jobs:
# Dispatch inputs select the refs every suite checks out. They are shaped once
# here, ahead of every other job, and republished as outputs so no raw inputs
# expression reaches a checkout or a run script.
preflight:
name: Validate dispatch inputs
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
php_bin_sha: ${{ steps.validated.outputs.php_bin_sha }}
mise_php_sha: ${{ steps.validated.outputs.mise_php_sha }}
live_version: ${{ steps.validated.outputs.live_version }}
steps:
- name: Enforce exact input shapes
id: validated
env:
PHP_BIN_SHA: ${{ inputs.php_bin_sha }}
MISE_PHP_SHA: ${{ inputs.mise_php_sha }}
SUITE: ${{ inputs.suite }}
LIVE_VERSION: ${{ inputs.live_version }}
run: |
[[ "$PHP_BIN_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$MISE_PHP_SHA" =~ ^[0-9a-f]{40}$ ]]
# live_version is optional and only meaningful for live-canary, so it is
# shaped for that suite and republished empty for every other one. The
# blanking matters: an unshaped value reaching $GITHUB_OUTPUT could set
# arbitrary outputs.
if [[ "$SUITE" == "live-canary" ]]; then
[[ "$LIVE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[1-9][0-9]*)?$ ]]
else
LIVE_VERSION=
fi
{
echo "php_bin_sha=$PHP_BIN_SHA"
echo "mise_php_sha=$MISE_PHP_SHA"
echo "live_version=$LIVE_VERSION"
} >> "$GITHUB_OUTPUT"

production-parity:
needs: preflight
if: inputs.suite == 'production-parity'
runs-on: macos-26
timeout-minutes: 45
Expand All @@ -44,22 +82,22 @@ jobs:
working-directory: control
run: |
# This reviewed pin detects workflow edits that omit the corresponding pin update.
expected="$(jq -r '.workflows[".github/workflows/maintenance-e2e.yml"]' .github/maintenance-pins.json)"
actual="sha256:$(shasum -a 256 .github/workflows/maintenance-e2e.yml | awk '{print $1}')"
expected="$(jq -r '.workflows[".github/workflows/autorelease-e2e.yml"]' .github/autorelease-pins.json)"
actual="sha256:$(shasum -a 256 .github/workflows/autorelease-e2e.yml | awk '{print $1}')"
test "$actual" = "$expected"
- name: Checkout exact php-bin commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: bigpixelrocket/php-bin
ref: ${{ inputs.php_bin_sha }}
ref: ${{ needs.preflight.outputs.php_bin_sha }}
path: php-bin
fetch-depth: 0
persist-credentials: false
- name: Checkout exact mise-php commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: bigpixelrocket/mise-php
ref: ${{ inputs.mise_php_sha }}
ref: ${{ needs.preflight.outputs.mise_php_sha }}
path: mise-php
fetch-depth: 0
persist-credentials: false
Expand All @@ -75,37 +113,41 @@ jobs:
test -z "${GH_TOKEN:-}"
test -z "${GITHUB_TOKEN:-}"
- name: Run stable cross-repository verifier
env:
PHP_BIN_SHA: ${{ needs.preflight.outputs.php_bin_sha }}
MISE_PHP_SHA: ${{ needs.preflight.outputs.mise_php_sha }}
run: |
./php-bin/scripts/verify-maintenance-system \
./php-bin/scripts/verify-autorelease-system \
--mise-repo ./mise-php \
--php-bin-sha "${{ inputs.php_bin_sha }}" \
--mise-php-sha "${{ inputs.mise_php_sha }}" \
--php-bin-sha "$PHP_BIN_SHA" \
--mise-php-sha "$MISE_PHP_SHA" \
Comment thread
coderabbitai[bot] marked this conversation as resolved.
--output ./verification-results
- name: Retain production-parity report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: maintenance-production-parity-${{ github.run_id }}
name: autorelease-production-parity-${{ github.run_id }}
path: verification-results/
if-no-files-found: error
retention-days: 90
include-hidden-files: true

agent-canary:
needs: preflight
if: inputs.suite == 'agent-canary'
runs-on: ubuntu-latest
timeout-minutes: 15
environment: php-maintenance-agent-canary
environment: php-autorelease-canary
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ inputs.php_bin_sha }}
ref: ${{ needs.preflight.outputs.php_bin_sha }}
persist-credentials: false
- name: Bind the credentialed canary to reviewed main
env:
EXPECTED_SHA: ${{ inputs.php_bin_sha }}
EXPECTED_SHA: ${{ needs.preflight.outputs.php_bin_sha }}
run: |
test "$GITHUB_REF" = "refs/heads/main"
test "$GITHUB_SHA" = "$EXPECTED_SHA"
Expand Down Expand Up @@ -152,12 +194,13 @@ jobs:
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: maintenance-agent-canary-${{ github.run_id }}
name: autorelease-agent-canary-${{ github.run_id }}
path: canary/
if-no-files-found: error
retention-days: 90

notification-canary:
needs: preflight
if: inputs.suite == 'notification-canary'
runs-on: ubuntu-latest
timeout-minutes: 10
Expand All @@ -167,7 +210,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ inputs.php_bin_sha }}
ref: ${{ needs.preflight.outputs.php_bin_sha }}
persist-credentials: false
- name: Create, replay, transition, and close one namespaced issue
env:
Expand All @@ -178,44 +221,44 @@ jobs:
jq -n --arg actionKey "$action_key" \
'{actionKey:$actionKey,state:"detected",severity:"info",summary:"Harmless notification delivery canary."}' \
> canary/event.json
./scripts/notify-maintenance --event canary/event.json --state canary/state.json --output canary/next.json \
--backend github --repo "${{ github.repository }}" --owner "${{ vars.MAINTENANCE_OWNER }}"
./scripts/notify-autorelease --event canary/event.json --state canary/state.json --output canary/next.json \
--backend github --repo "${{ github.repository }}" --owner "${{ vars.AUTORELEASE_OWNER }}"
mv canary/next.json canary/state.json
./scripts/notify-maintenance --event canary/event.json --state canary/state.json --output canary/replay.json \
--backend github --repo "${{ github.repository }}" --owner "${{ vars.MAINTENANCE_OWNER }}"
./scripts/notify-autorelease --event canary/event.json --state canary/state.json --output canary/replay.json \
--backend github --repo "${{ github.repository }}" --owner "${{ vars.AUTORELEASE_OWNER }}"
test "$(jq -r .lastAction canary/replay.json)" = "none"
jq '.state="php_bin_ready"' canary/event.json > canary/transition.json
./scripts/notify-maintenance --event canary/transition.json --state canary/state.json --output canary/next.json \
--backend github --repo "${{ github.repository }}" --owner "${{ vars.MAINTENANCE_OWNER }}"
./scripts/notify-autorelease --event canary/transition.json --state canary/state.json --output canary/next.json \
--backend github --repo "${{ github.repository }}" --owner "${{ vars.AUTORELEASE_OWNER }}"
mv canary/next.json canary/state.json
jq '.state="complete" | .finalResult="passed"' canary/event.json > canary/complete.json
./scripts/notify-maintenance --event canary/complete.json --state canary/state.json --output canary/closed.json \
--backend github --repo "${{ github.repository }}" --owner "${{ vars.MAINTENANCE_OWNER }}"
./scripts/notify-autorelease --event canary/complete.json --state canary/state.json --output canary/closed.json \
--backend github --repo "${{ github.repository }}" --owner "${{ vars.AUTORELEASE_OWNER }}"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: always()
with:
name: maintenance-notification-canary-${{ github.run_id }}
name: autorelease-notification-canary-${{ github.run_id }}
path: canary/
if-no-files-found: error
retention-days: 90

live-canary:
needs: preflight
if: inputs.suite == 'live-canary'
runs-on: macos-26
timeout-minutes: 20
environment: php-maintenance-release
environment: php-autorelease-publish
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: bigpixelrocket/mise-php
ref: ${{ inputs.mise_php_sha }}
ref: ${{ needs.preflight.outputs.mise_php_sha }}
Comment thread
cursor[bot] marked this conversation as resolved.
persist-credentials: false
- uses: jdx/mise-action@9e7f7633ff6f6d6048a9418a68d48f288f50eb14 # v4
- name: Verify exact and branch-shorthand public installs
env:
LIVE_VERSION: ${{ inputs.live_version }}
LIVE_VERSION: ${{ needs.preflight.outputs.live_version }}
run: |
[[ "$LIVE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[1-9][0-9]*)?$ ]]
branch="$LIVE_VERSION"
branch="${branch%%-*}"
branch="${branch%.*}"
Expand Down
Loading
Loading