Skip to content

refactor!: rename the guarded maintenance system to autorelease - #49

Merged
loadinglucian merged 6 commits into
mainfrom
feat/autorelease-rename
Aug 2, 2026
Merged

refactor!: rename the guarded maintenance system to autorelease#49
loadinglucian merged 6 commits into
mainfrom
feat/autorelease-rename

Conversation

@loadinglucian

@loadinglucian loadinglucian commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Renames the "guarded maintenance" system to autorelease across every
directory, workflow, script, schema, control, and prose reference, and moves the
system documentation out of README.md into a dedicated AUTORELEASE.md.

No behaviour changes. Every rename is a git mv, so history follows the files.

Why

"Guarded" said nothing a reader could act on, and "maintenance" was ambiguous —
it read like routine upkeep when the system's actual job is producing releases
without a human in the loop.

What is deliberately not renamed

release_transition, LEGAL_RELEASE_TRANSITIONS, and releaseIntent name the
release object, not the system that produces it, so they stay as they are.

scripts/release-maintenance becomes scripts/publish-release rather than
autorelease-publish, to keep the verb-first convention every other script in
that directory already uses.

Two tripwires fired, both correctly

  • .github/autorelease-pins.json pins the digest of autorelease-e2e.yml, and
    that workflow verifies its own pin at runtime. The pin is regenerated in this
    PR.
  • verify.py A20 asserted the README carried the Mermaid flows, verifier
    command, and owner variable. Those moved, so A20 now checks AUTORELEASE.md
    for them and additionally asserts each README links to it.

One behaviour change, deliberate

Review surfaced a template-injection weakness that predates this branch, and it
is fixed here rather than deferred.

Both dispatch workflows expanded ${{ inputs.* }} directly into run: script
text. GitHub substitutes those before the shell parses them, so shell quoting
cannot contain a hostile value. Worse, exact_base_sha selected
actions/checkout.ref in autorelease-implement.yml, and
investigation_run_id reached gh run download in autorelease-publish.yml,
both before the regex checks that came later in the file.

Each workflow now opens with a preflight job that shape-checks every input and
republishes it as a job output. Every other job takes needs: preflight and
reads needs.preflight.outputs.*, so no raw inputs expression is expanded
anywhere else. The merge job carries if: always(), which runs a job even
when a dependency failed, so its condition gained an explicit
needs.preflight.result == 'success'.

autorelease-e2e.yml had the same pattern in its verifier call and is swept
too, which is why .github/autorelease-pins.json changes again. Its optional
live_version is shaped in preflight for the one suite that uses it and
republished blank for the others, so the file has a single validation point.

Verification

  • ./scripts/test.sh — passes in both repos
  • verify-autorelease-system — 21/21 checks pass at these exact commits
  • markdownlint — clean

The completed new_patch:8.5.9 event record and
autorelease-state/last-evidence.json contain no renamed text, so their digests
stay valid and the watcher keeps its comparison baseline. Nothing is in flight.

Merge order — mise-php first

mise-php reads this repo's operator control by path, live from main.
Its PR teaches it to accept both the old and new filename, so it must merge
before this PR. Merging this one first would 404 its consumer.

Both merges should land in the quiet window between the daily crons
(php-bin 05:17 UTC, mise-php 05:43 UTC).

GitHub-side migration (required, outside the repo)

Run in this order:

  1. Before merging, add the new variables alongside the old ones:
    AUTORELEASE_OWNER (both repos) and AUTORELEASE_ADMIN_CANARY (php-bin).
    Set AUTORELEASE_OWNER to the exact login in CODEOWNERS, since
    protected-controls.yml now resolves its reviewer from that variable alone
    and an empty or mismatched value makes the gate unsatisfiable.
  2. Merge the mise-php PR, then this one.
  3. Rename the existing maintenance label to autorelease via the API.
    Do this before step 4: renaming preserves the label on the issues already
    carrying it, and configure-github-autorelease would otherwise create a
    fresh autorelease label and make the rename collide with an existing name.
  4. Run scripts/configure-github-autorelease. It creates the
    php-autorelease-publish environment with its protection rules, sets
    AUTORELEASE_OWNER, and reconciles the colour and description of the
    autorelease label renamed in step 3.
  5. Create php-autorelease-canary and re-add its secrets by hand — the
    script configures environments but cannot carry secret values across.
  6. Delete the old environments and variables once a dispatch has confirmed the
    new ones work.
  7. Re-run scripts/snapshot-github-admin-state to refresh docs/admin-state/,
    which currently records the pre-rename names.
  8. Dispatch autorelease-e2e.yml with suite=production-parity to confirm.
  9. Open the follow-up in mise-php removing its dual-path fallback.

Summary by CodeRabbit

  • New Features

    • Introduced automated PHP autorelease workflows covering investigation, validation, publishing, monitoring, and failure recovery.
    • Added preflight checks and protected release controls to improve release safety and consistency.
    • Added support for serving and validating staged release artifacts.
  • Documentation

    • Added comprehensive autorelease operations, verification, configuration, and recovery guidance.
    • Updated project documentation to describe the new autorelease process.
  • Bug Fixes

    • Preserved compatibility with existing maintenance-related notifications during the transition.

Rename every "guarded maintenance" identifier to "autorelease" across
directories, workflows, scripts, schemas, controls, and prose, and move the
system documentation out of README.md into a dedicated AUTORELEASE.md.

Release transaction vocabulary is deliberately untouched: release_transition,
LEGAL_RELEASE_TRANSITIONS, and releaseIntent name the release object, not the
system that produces it. scripts/release-maintenance becomes
scripts/publish-release to keep the verb-first convention used by every other
script in the directory.

protected-paths.json, CODEOWNERS, and the retained event and evidence records
move in lockstep. autorelease-state/last-evidence.json and the completed
new_patch:8.5.9 event record contain no renamed text, so their digests remain
valid and the watcher keeps its comparison baseline.

BREAKING CHANGE: these GitHub-side names live outside the repository and must
be migrated in the same window as this merge, otherwise the publish workflow
loses access to its secrets:

  environment  php-maintenance-release       -> php-autorelease-publish
  environment  php-maintenance-agent-canary  -> php-autorelease-canary
  variable     MAINTENANCE_OWNER             -> AUTORELEASE_OWNER
  variable     MAINTENANCE_ADMIN_CANARY      -> AUTORELEASE_ADMIN_CANARY
  label        maintenance                   -> autorelease

Workflow filenames change, so any saved dispatch links must be updated:
maintenance-watch.yml -> autorelease-watch.yml, maintenance-release.yml ->
autorelease-publish.yml, maintenance-implementation.yml ->
autorelease-implement.yml, maintenance-e2e.yml -> autorelease-e2e.yml.
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eb82f621-62ba-4bdc-99f3-59516712fad2

📥 Commits

Reviewing files that changed from the base of the PR and between 8f653bc and 3f2f45f.

📒 Files selected for processing (3)
  • .github/autorelease-pins.json
  • .github/workflows/autorelease-e2e.yml
  • .github/workflows/autorelease-publish.yml
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/autorelease-pins.json
  • .github/workflows/autorelease-publish.yml

📝 Walkthrough

Walkthrough

The change migrates PHP release automation from maintenance terminology and paths to autorelease equivalents. It adds autorelease controls, workflows, state, policy, documentation, event records, artifact serving, validation, and tests.

Changes

Autorelease system migration

Layer / File(s) Summary
Autorelease contracts and repository state
.github/codex/autorelease/*, .github/autorelease-*.json, autorelease-*/, AUTORELEASE.md, README.md, docs/*, schemas/*
Adds autorelease instructions, policy invariants, protected paths, evidence state, event records, documentation, schema identifiers, and repository settings.
Autorelease controls and command tools
autorelease/*, scripts/*, tests/test_autorelease.py
Updates control imports, validation paths, labels, notifications, scripts, verification outputs, tests, and the local HTTP artifact server.
Evidence watcher and protected controls
.github/workflows/autorelease-watch.yml, .github/workflows/protected-controls.yml, .github/workflows/ci.yml
Updates evidence capture, plan admission, notifications, readiness events, branch checks, attestations, protected paths, and workflow validation.
Autorelease implementation flow
.github/workflows/autorelease-implement.yml
Validates dispatch inputs and uses autorelease contracts and artifacts for patch sealing, validation, bounded repair, pull request creation, readiness events, and check recording.
Publishing transaction and canary validation
.github/workflows/autorelease-publish.yml, .github/workflows/autorelease-e2e.yml
Validates publishing inputs and updates event progression, release verification, notifications, environments, integrity pins, and canary artifacts.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Watcher as autorelease-watch.yml
  participant Controls as autorelease.control
  participant Implementer as autorelease-implement.yml
  participant Publisher as autorelease-publish.yml
  Watcher->>Controls: Capture evidence and admit autorelease plan
  Controls-->>Watcher: Validated plan and evidence
  Watcher->>Implementer: Dispatch implementation workflow
  Implementer->>Controls: Seal, validate, or repair patch
  Implementer->>Publisher: Create readiness event
  Publisher->>Controls: Validate event and publish release
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the primary change: renaming the guarded maintenance system to autorelease.
Description check ✅ Passed The description clearly explains the rename, behavior change, verification results, migration order, and required GitHub-side actions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/autorelease-rename

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/autorelease-implement.yml (1)

39-100: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Add upfront format validation for workflow_dispatch run-ID inputs before they reach shell scripts.

Both workflows consume the investigation_run_id input via raw ${{ }} template expansion inside run: scripts before any format check occurs. autorelease-publish.yml already demonstrates the correct pattern for its other inputs (VERSION, EXACT_COMMIT, ACTION_KEY): assign to env:, then validate with a regex before use. Apply the same pattern consistently to investigation_run_id in both files, and to exact_base_sha/phase in autorelease-implement.yml.

  • .github/workflows/autorelease-implement.yml#L39-L100: Before Line 39, add an env: block plus a regex check for investigation_run_id (^[1-9][0-9]*$), exact_base_sha (^[0-9a-f]{40}$), and an explicit allow-list check for phase, then reference the validated env: variables (not raw ${{ inputs.* }}) at Lines 39, 44, 45, 48, 91, and the later occurrences in the validate/repair/validate-repair jobs.
  • .github/workflows/autorelease-publish.yml#L52-L58: Add investigation_run_id to the existing regex-validation step at Lines 67-69 (alongside VERSION/EXACT_COMMIT/ACTION_KEY) before it is first used at Line 57.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/autorelease-implement.yml around lines 39 - 100, Validate
workflow_dispatch inputs before shell use: in
.github/workflows/autorelease-implement.yml#L39-L100, add env-backed values and
validate investigation_run_id and exact_base_sha with their required regexes,
phase with an explicit allow-list, then use those env values throughout the
referenced steps and later validate/repair jobs instead of raw inputs. In
.github/workflows/autorelease-publish.yml#L52-L58, add investigation_run_id to
the existing regex-validation step before its first use.
🧹 Nitpick comments (1)
tests/test_autorelease.py (1)

347-355: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the changed notification-label producer directly.

This test supplies labels: ["autorelease"] to apply_github manually. It does not exercise notification_decision, which supplies the changed label in Line 951 of autorelease/control.py. Add a direct assertion for the producer output.

Proposed test addition
        first = notification_decision(event, None)
+       self.assertEqual(["autorelease"], first["labels"])
        replay = notification_decision(event, {"fingerprint": first["fingerprint"]})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_autorelease.py` around lines 347 - 355, Extend the test to call
the changed notification_decision producer directly and assert that its returned
decision includes the expected notification label. Keep the existing
apply_github test coverage intact, but derive or validate the labels through
notification_decision rather than only supplying ["autorelease"] manually.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/autorelease-implement.yml:
- Around line 39-79: Add a preflight validation job before checkout that
validates investigation_run_id as a positive decimal integer and exact_base_sha
as exactly 40 lowercase hexadecimal characters, then exposes only validated
values for downstream jobs. Update checkout and all run scripts to consume these
values through env-backed shell variables rather than direct interpolation, and
pass phase through env with an explicit implementation/repair allowlist before
using it in the Prepare offline phase contract step.

In `@autorelease-events/new_patch-8.5.9.json`:
- Line 1: Update the README’s PHP 8.5 latest-release status link from 8.5.8 to
8.5.9, preserving the existing link format and surrounding content.

In `@autorelease/control.py`:
- Line 951: Update the deduplicated-notification path around
notification_decision so retained issues reconcile labels even when the decision
is action: "none". Ensure autorelease is added and obsolete maintenance is
removed independently of notification delivery, or reset the notification state
before applying this migration.

In `@autorelease/protected-paths.json`:
- Around line 12-26: Update the protected-path list in
autorelease/protected-paths.json to include scripts/serve-autorelease-artifact
and scripts/verify-autorelease-system, preserving the existing entries and
ensuring path_is_protected() recognizes both control scripts.

In `@scripts/notify-autorelease`:
- Line 33: Update the notification lookup and parsing logic around the
autorelease marker construction to search for both autorelease-action-key and
maintenance-action-key markers when notification state is unavailable, parse
both fingerprint formats, and merge matching results by issue number before
creating issues. Preserve deduplication for existing maintenance issues while
retaining current autorelease behavior.

In `@scripts/serve-autorelease-artifact`:
- Around line 20-21: Update payload() and its caller to build asset URLs with
the server’s bound port from server.server_address[1] rather than args.port,
preserving correct URLs when --port 0 selects an ephemeral port.

---

Outside diff comments:
In @.github/workflows/autorelease-implement.yml:
- Around line 39-100: Validate workflow_dispatch inputs before shell use: in
.github/workflows/autorelease-implement.yml#L39-L100, add env-backed values and
validate investigation_run_id and exact_base_sha with their required regexes,
phase with an explicit allow-list, then use those env values throughout the
referenced steps and later validate/repair jobs instead of raw inputs. In
.github/workflows/autorelease-publish.yml#L52-L58, add investigation_run_id to
the existing regex-validation step before its first use.

---

Nitpick comments:
In `@tests/test_autorelease.py`:
- Around line 347-355: Extend the test to call the changed notification_decision
producer directly and assert that its returned decision includes the expected
notification label. Keep the existing apply_github test coverage intact, but
derive or validate the labels through notification_decision rather than only
supplying ["autorelease"] manually.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b3c02ce1-b837-4c0d-a6cd-1351aa0f7544

📥 Commits

Reviewing files that changed from the base of the PR and between 594a01f and a9eb814.

📒 Files selected for processing (48)
  • .github/CODEOWNERS
  • .github/autorelease-operator.json
  • .github/autorelease-pins.json
  • .github/codex/autorelease/implementation.md
  • .github/codex/autorelease/investigation.md
  • .github/codex/autorelease/repair.md
  • .github/codex/autorelease/shared.md
  • .github/workflows/autorelease-e2e.yml
  • .github/workflows/autorelease-implement.yml
  • .github/workflows/autorelease-publish.yml
  • .github/workflows/autorelease-watch.yml
  • .github/workflows/ci.yml
  • .github/workflows/protected-controls.yml
  • .gitignore
  • AUTORELEASE.md
  • README.md
  • autorelease-events/.gitkeep
  • autorelease-events/new_patch-8.5.9.json
  • autorelease-state/.gitkeep
  • autorelease-state/last-evidence.json
  • autorelease/__init__.py
  • autorelease/control.py
  • autorelease/policy-invariants.json
  • autorelease/protected-paths.json
  • autorelease/verify.py
  • docs/admin-state/php-bin-after.json
  • docs/autorelease-admin-evidence.json
  • docs/repository-settings.md
  • maintenance/__init__.py
  • maintenance/protected-paths.json
  • schemas/autorelease-event.schema.json
  • schemas/autorelease-plan.schema.json
  • scripts/admit-autorelease-plan
  • scripts/autorelease-event
  • scripts/capture-autorelease-evidence
  • scripts/configure-github-autorelease
  • scripts/notify-autorelease
  • scripts/prepare-agent-task
  • scripts/publish-release
  • scripts/seal-autorelease-patch
  • scripts/serve-autorelease-artifact
  • scripts/test.sh
  • scripts/validate-autorelease-archive
  • scripts/validate-structured-output-schemas
  • scripts/verify-autorelease-system
  • scripts/verify-merge-admission
  • scripts/watch-autorelease-evidence
  • tests/test_autorelease.py
💤 Files with no reviewable changes (2)
  • maintenance/protected-paths.json
  • maintenance/init.py

Comment thread .github/workflows/autorelease-implement.yml Outdated
Comment thread autorelease/control.py
Comment thread autorelease/protected-paths.json
Comment thread scripts/notify-autorelease Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/autorelease-implement.yml (1)

39-100: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Add upfront format validation for workflow_dispatch run-ID inputs before they reach shell scripts.

Both workflows consume the investigation_run_id input via raw ${{ }} template expansion inside run: scripts before any format check occurs. autorelease-publish.yml already demonstrates the correct pattern for its other inputs (VERSION, EXACT_COMMIT, ACTION_KEY): assign to env:, then validate with a regex before use. Apply the same pattern consistently to investigation_run_id in both files, and to exact_base_sha/phase in autorelease-implement.yml.

  • .github/workflows/autorelease-implement.yml#L39-L100: Before Line 39, add an env: block plus a regex check for investigation_run_id (^[1-9][0-9]*$), exact_base_sha (^[0-9a-f]{40}$), and an explicit allow-list check for phase, then reference the validated env: variables (not raw ${{ inputs.* }}) at Lines 39, 44, 45, 48, 91, and the later occurrences in the validate/repair/validate-repair jobs.
  • .github/workflows/autorelease-publish.yml#L52-L58: Add investigation_run_id to the existing regex-validation step at Lines 67-69 (alongside VERSION/EXACT_COMMIT/ACTION_KEY) before it is first used at Line 57.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/autorelease-implement.yml around lines 39 - 100, Validate
workflow_dispatch inputs before shell use: in
.github/workflows/autorelease-implement.yml#L39-L100, add env-backed values and
validate investigation_run_id and exact_base_sha with their required regexes,
phase with an explicit allow-list, then use those env values throughout the
referenced steps and later validate/repair jobs instead of raw inputs. In
.github/workflows/autorelease-publish.yml#L52-L58, add investigation_run_id to
the existing regex-validation step before its first use.
🧹 Nitpick comments (1)
tests/test_autorelease.py (1)

347-355: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the changed notification-label producer directly.

This test supplies labels: ["autorelease"] to apply_github manually. It does not exercise notification_decision, which supplies the changed label in Line 951 of autorelease/control.py. Add a direct assertion for the producer output.

Proposed test addition
        first = notification_decision(event, None)
+       self.assertEqual(["autorelease"], first["labels"])
        replay = notification_decision(event, {"fingerprint": first["fingerprint"]})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_autorelease.py` around lines 347 - 355, Extend the test to call
the changed notification_decision producer directly and assert that its returned
decision includes the expected notification label. Keep the existing
apply_github test coverage intact, but derive or validate the labels through
notification_decision rather than only supplying ["autorelease"] manually.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/autorelease-implement.yml:
- Around line 39-79: Add a preflight validation job before checkout that
validates investigation_run_id as a positive decimal integer and exact_base_sha
as exactly 40 lowercase hexadecimal characters, then exposes only validated
values for downstream jobs. Update checkout and all run scripts to consume these
values through env-backed shell variables rather than direct interpolation, and
pass phase through env with an explicit implementation/repair allowlist before
using it in the Prepare offline phase contract step.

In `@autorelease-events/new_patch-8.5.9.json`:
- Line 1: Update the README’s PHP 8.5 latest-release status link from 8.5.8 to
8.5.9, preserving the existing link format and surrounding content.

In `@autorelease/control.py`:
- Line 951: Update the deduplicated-notification path around
notification_decision so retained issues reconcile labels even when the decision
is action: "none". Ensure autorelease is added and obsolete maintenance is
removed independently of notification delivery, or reset the notification state
before applying this migration.

In `@autorelease/protected-paths.json`:
- Around line 12-26: Update the protected-path list in
autorelease/protected-paths.json to include scripts/serve-autorelease-artifact
and scripts/verify-autorelease-system, preserving the existing entries and
ensuring path_is_protected() recognizes both control scripts.

In `@scripts/notify-autorelease`:
- Line 33: Update the notification lookup and parsing logic around the
autorelease marker construction to search for both autorelease-action-key and
maintenance-action-key markers when notification state is unavailable, parse
both fingerprint formats, and merge matching results by issue number before
creating issues. Preserve deduplication for existing maintenance issues while
retaining current autorelease behavior.

In `@scripts/serve-autorelease-artifact`:
- Around line 20-21: Update payload() and its caller to build asset URLs with
the server’s bound port from server.server_address[1] rather than args.port,
preserving correct URLs when --port 0 selects an ephemeral port.

---

Outside diff comments:
In @.github/workflows/autorelease-implement.yml:
- Around line 39-100: Validate workflow_dispatch inputs before shell use: in
.github/workflows/autorelease-implement.yml#L39-L100, add env-backed values and
validate investigation_run_id and exact_base_sha with their required regexes,
phase with an explicit allow-list, then use those env values throughout the
referenced steps and later validate/repair jobs instead of raw inputs. In
.github/workflows/autorelease-publish.yml#L52-L58, add investigation_run_id to
the existing regex-validation step before its first use.

---

Nitpick comments:
In `@tests/test_autorelease.py`:
- Around line 347-355: Extend the test to call the changed notification_decision
producer directly and assert that its returned decision includes the expected
notification label. Keep the existing apply_github test coverage intact, but
derive or validate the labels through notification_decision rather than only
supplying ["autorelease"] manually.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b3c02ce1-b837-4c0d-a6cd-1351aa0f7544

📥 Commits

Reviewing files that changed from the base of the PR and between 594a01f and a9eb814.

📒 Files selected for processing (48)
  • .github/CODEOWNERS
  • .github/autorelease-operator.json
  • .github/autorelease-pins.json
  • .github/codex/autorelease/implementation.md
  • .github/codex/autorelease/investigation.md
  • .github/codex/autorelease/repair.md
  • .github/codex/autorelease/shared.md
  • .github/workflows/autorelease-e2e.yml
  • .github/workflows/autorelease-implement.yml
  • .github/workflows/autorelease-publish.yml
  • .github/workflows/autorelease-watch.yml
  • .github/workflows/ci.yml
  • .github/workflows/protected-controls.yml
  • .gitignore
  • AUTORELEASE.md
  • README.md
  • autorelease-events/.gitkeep
  • autorelease-events/new_patch-8.5.9.json
  • autorelease-state/.gitkeep
  • autorelease-state/last-evidence.json
  • autorelease/__init__.py
  • autorelease/control.py
  • autorelease/policy-invariants.json
  • autorelease/protected-paths.json
  • autorelease/verify.py
  • docs/admin-state/php-bin-after.json
  • docs/autorelease-admin-evidence.json
  • docs/repository-settings.md
  • maintenance/__init__.py
  • maintenance/protected-paths.json
  • schemas/autorelease-event.schema.json
  • schemas/autorelease-plan.schema.json
  • scripts/admit-autorelease-plan
  • scripts/autorelease-event
  • scripts/capture-autorelease-evidence
  • scripts/configure-github-autorelease
  • scripts/notify-autorelease
  • scripts/prepare-agent-task
  • scripts/publish-release
  • scripts/seal-autorelease-patch
  • scripts/serve-autorelease-artifact
  • scripts/test.sh
  • scripts/validate-autorelease-archive
  • scripts/validate-structured-output-schemas
  • scripts/verify-autorelease-system
  • scripts/verify-merge-admission
  • scripts/watch-autorelease-evidence
  • tests/test_autorelease.py
💤 Files with no reviewable changes (2)
  • maintenance/protected-paths.json
  • maintenance/init.py
🛑 Comments failed to post (2)
autorelease-events/new_patch-8.5.9.json (1)

1-1: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the public status for the completed 8.5.9 event.

This record is marked complete and records a published 8.5.9 release on July 31, 2026. README.md still lists 8.5.8 as the latest PHP 8.5 release. Update the status link to 8.5.9.

Proposed README update
- [8.5.8](https://github.com/bigpixelrocket/php-bin/releases/tag/8.5.8).
+ [8.5.9](https://github.com/bigpixelrocket/php-bin/releases/tag/8.5.9).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@autorelease-events/new_patch-8.5.9.json` at line 1, Update the README’s PHP
8.5 latest-release status link from 8.5.8 to 8.5.9, preserving the existing link
format and surrounding content.
scripts/serve-autorelease-artifact (1)

20-21: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python - <<'PY'
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

class Handler(BaseHTTPRequestHandler):
    def log_message(self, *_args):
        pass

server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
try:
    assert server.server_address[1] != 0
finally:
    server.server_close()
PY

rg -n 'args\.port|server\.server_address|ThreadingHTTPServer' scripts/serve-autorelease-artifact

Repository: Bigpixelrocket/php-bin

Length of output: 357


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,110p' scripts/serve-autorelease-artifact

Repository: Bigpixelrocket/php-bin

Length of output: 2608


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- references to the server script and --port ---'
rg -n --hidden -g '! .git' 'serve-autorelease-artifact|--port[ =]|PORT|127\.0\.0\.1' . | head -200

printf '%s\n' '--- bound-port behavior and URL construction ---'
python3 - <<'PY'
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

class Handler(BaseHTTPRequestHandler):
    def log_message(self, *_args):
        pass

server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
try:
    bound_port = server.server_address[1]
    assert bound_port != 0
    advertised_with_args_port = f"http://127.0.0.1:{0}/assets"
    advertised_with_bound_port = f"http://127.0.0.1:{bound_port}/assets"
    print(f"bound_port={bound_port}")
    print(f"args.port URL={advertised_with_args_port}")
    print(f"bound-port URL={advertised_with_bound_port}")
finally:
    server.server_close()
PY

Repository: Bigpixelrocket/php-bin

Length of output: 1343


Use the bound port in API URLs.

When --port 0 is used, ThreadingHTTPServer selects an ephemeral port. payload() still uses args.port, so the returned URLs use port 0 and fail. Pass server.server_address[1] to payload(), or reject port 0.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/serve-autorelease-artifact` around lines 20 - 21, Update payload()
and its caller to build asset URLs with the server’s bound port from
server.server_address[1] rather than args.port, preserving correct URLs when
--port 0 selects an ephemeral port.

Issues opened before the autorelease rename carry maintenance-action-key and
maintenance-fingerprint markers. notify-autorelease searched only the new
prefix, so a recurring action key would have created a duplicate issue and the
"issue already exists" guard would no longer have fired for those issues. Both
prefixes are now searched and merged by issue number.

scripts/serve-autorelease-artifact and scripts/verify-autorelease-system were
absent from protected-paths.json before the rename as well. Adding them only
narrows what an offline agent may edit, so the omission is closed here rather
than left in place while the file is already being rewritten.

Also points the README at 8.5.9, which the completed event record shows as
published.
@loadinglucian

Copy link
Copy Markdown
Contributor Author

Review round 1 summary

Every finding was checked against the code before deciding, including the two CodeRabbit could not post inline. Pushed as ff62a8e.

Fixed

Finding What changed
scripts/notify-autorelease deduplication Real regression from the rename. find_issue and the fingerprint scan now read both the autorelease- and maintenance- marker prefixes, merged by issue number. All 14 pre-rename issues carry the old marker, and no caller passes a --state path that exists in a fresh checkout, so this search was the only cross run deduplication there is. New test covers it.
autorelease/protected-paths.json scripts/serve-autorelease-artifact and scripts/verify-autorelease-system added. Pre-existing gap, not a rename regression, but adding paths only narrows what an offline agent may edit and leaving the verifier editable was the worse side to err on.
README.md release status Now points at 8.5.9, which the completed event record and the published release both confirm.
tests/test_autorelease.py Asserts notification_decision returns ["autorelease"] directly, rather than only through a hand supplied apply_github fixture.

Fixed outside the code

The label reconciliation comment on control.py:951 did not need a code change, because renaming a GitHub label preserves it on every issue carrying it. It did expose an ordering bug in the migration runbook in this PR description: configure-github-autorelease created a fresh autorelease label before the rename step ran, so the rename would have collided and left old issues stale. The runbook now renames first. Good find by an indirect route.

Declined, with reasons

autorelease-implement.yml workflow input validation. Valid observation, but byte for byte identical to maintenance-implementation.yml on main. Deliberately out of scope: this is a pure rename that already needs exact head owner approval, and mixing a security change in makes it harder to review and revert. The workflow is workflow_dispatch only, so reaching it already requires write access. Tracked as a follow up with the matching sites in mise-php.

scripts/serve-autorelease-artifact ephemeral port. The code path is unreachable as written. The only caller resolves a concrete free port in the shell first and passes it, so --port 0 never happens. Pre-existing either way. Same follow up.

Verification

./scripts/test.sh passes in both repos, verify-autorelease-system passes 21 of 21 at these commits, markdownlint is clean.

Merge order is unchanged: mise-php first, then this one.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_autorelease.py (1)

341-359: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Test both notification marker variants.

The mock returns an issue only for maintenance-action-key. It returns an empty result for the new autorelease marker. Therefore, a regression that removes the autorelease-marker lookup can still pass this test. Keep the legacy case and add a separate autorelease-marker fixture and assertion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_autorelease.py` around lines 341 - 359, Update
test_notification_search_finds_pre_rename_marker_issues to cover both marker
lookup variants: retain the existing legacy maintenance-action-key
fixture/assertion, and add a separate autorelease-marker fixture with mock
behavior and an assertion that find_issue returns it when searching the
autorelease marker.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_autorelease.py`:
- Around line 341-359: Update
test_notification_search_finds_pre_rename_marker_issues to cover both marker
lookup variants: retain the existing legacy maintenance-action-key
fixture/assertion, and add a separate autorelease-marker fixture with mock
behavior and an assertion that find_issue returns it when searching the
autorelease marker.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 58c5e773-15a6-4261-8105-8b79b92f9cfd

📥 Commits

Reviewing files that changed from the base of the PR and between a9eb814 and ff62a8e.

📒 Files selected for processing (4)
  • README.md
  • autorelease/protected-paths.json
  • scripts/notify-autorelease
  • tests/test_autorelease.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • autorelease/protected-paths.json
  • README.md

The legacy fixture alone still passed when the autorelease prefix was removed
from MARKER_PREFIXES. Each prefix now gets its own subtest and fixture, so
dropping either lookup fails the test.
@loadinglucian

Copy link
Copy Markdown
Contributor Author

You are right, and I checked it rather than assuming. Fixed in 7ad9adf.

The old test only had a maintenance-action-key fixture, so the mock returned [] for the autorelease search and the assertion passed either way. I proved the gap by temporarily reducing MARKER_PREFIXES to ("maintenance",) and re-running: the test still passed. It should not have.

Each prefix now gets its own subtest and its own fixture, with the mock keyed to that prefix. Re-running the same mutation now fails, and restoring the tuple passes, so the test actually discriminates. Good catch on a test I had just written.

GitHub substitutes ${{ }} into run script text before the shell parses it, so
shell quoting cannot contain a hostile value. Both dispatch workflows now
validate their inputs in a preflight job and publish them as outputs, and every
downstream job reads those outputs through an env map instead of expanding a
raw inputs expression.

The preflight job also runs ahead of every actions/checkout, so exact_base_sha
and exact_commit are shape-checked before they can select a ref. The e2e
verifier call gains the same env binding and SHA assertion.
Comment thread .github/workflows/autorelease-publish.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/autorelease-publish.yml (1)

405-408: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Require preflight success for the always() job.

Add needs.preflight.result == 'success' to this condition. This keeps the validation gate explicit if later changes alter the release job condition or dependencies.

Based on learnings, any job using if: always() must also require needs.preflight.result == 'success'.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/autorelease-publish.yml around lines 405 - 408, Update the
notify-failure job’s if condition to also require needs.preflight.result ==
'success' alongside the existing release failure check, while preserving
always() and the current actionable failure notification behavior.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/autorelease-e2e.yml:
- Around line 78-87: Add a separate preflight job that validates both SHA
dispatch inputs before any checkout or shell usage, and exposes the validated
values as job outputs. Make production-parity depend on this preflight job, and
replace its raw input references with the preflight outputs for both checkout
refs and verify-autorelease-system arguments.

In @.github/workflows/autorelease-publish.yml:
- Around line 324-325: Update the jq invocation that builds
notification-event.json to pass the release VERSION value into jq and
interpolate it in the summary instead of leaving the literal "$VERSION" text.
Preserve the existing severity and finalResult assignments and the release
verification wording.

---

Nitpick comments:
In @.github/workflows/autorelease-publish.yml:
- Around line 405-408: Update the notify-failure job’s if condition to also
require needs.preflight.result == 'success' alongside the existing release
failure check, while preserving always() and the current actionable failure
notification behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 06510067-51d8-4f6b-95cc-93f587a9371c

📥 Commits

Reviewing files that changed from the base of the PR and between 7ad9adf and 8f653bc.

📒 Files selected for processing (4)
  • .github/autorelease-pins.json
  • .github/workflows/autorelease-e2e.yml
  • .github/workflows/autorelease-implement.yml
  • .github/workflows/autorelease-publish.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/autorelease-pins.json

Comment thread .github/workflows/autorelease-e2e.yml
Comment thread .github/workflows/autorelease-publish.yml Outdated
…nputs

The publish summary built its jq program in single quotes, so moving the version
off a ${{ }} expansion left jq resolving an undefined $VERSION variable instead
of the released version. It is passed with --arg, matching the two jq calls
directly above it.

autorelease-e2e.yml gains the same preflight job as the other two dispatch
workflows, so all four suites check out validated SHAs. notify-failure asserts
the preflight result alongside always().

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0a7ea3d. Configure here.

Comment thread .github/workflows/autorelease-e2e.yml
live_version was the last free-form dispatch input still shaped inside the job
that consumed it. Preflight now shapes it for the live-canary suite and
republishes it blank for the others, so the file has one validation point and a
malformed version fails before a macOS runner is provisioned.
@loadinglucian

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Not chasing you, the automatic pass got dropped. The commit status on this head reads "Review rate limited" and has not moved since the push landed, so the latest commits have not been looked at yet. Requesting one now that the window should have cleared.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

@loadinglucian I will review the latest commits on pull request #49.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@loadinglucian
loadinglucian merged commit 88a7186 into main Aug 2, 2026
5 of 6 checks passed
@loadinglucian
loadinglucian deleted the feat/autorelease-rename branch August 2, 2026 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant