ci: auto-retarget bot PRs opened against main → staging (#1853)

Mechanical enforcement of SHARED_RULES rule 8 ("Staging-first workflow,
no exceptions"). Today I manually retargeted 17+ bot PRs; next cycle
there will be more. Prompt-level enforcement is leaking — 5 of 8
engineer role prompts (core-be, core-fe, app-fe, app-qa, devops-engineer)
don't have the staging-first section that backend-engineer and
frontend-engineer do.

This Action closes the loop mechanically:

- Fires on `pull_request_target` opened/reopened against main.
- Only retargets bot-authored PRs (user.type=='Bot' OR login ends in
  '[bot]' OR == 'app/molecule-ai' OR == 'molecule-ai[bot]').
- Human-authored PRs (the CEO's staging→main promotion PR) pass through
  untouched — they're the authorised exception.
- Posts an explainer comment so the agent that opened the PR learns why
  and can adjust its prompt.

Why `pull_request_target` not `pull_request`:
`pull_request` from a fork would run with read-only tokens and can't
call the PATCH endpoint. `pull_request_target` runs with the base
repository's context + its `pull-requests: write` permission, which is
exactly what we need.

Follow-up (not in this PR): add the staging-first section to the 5
missing role prompts in molecule-ai-org-template-molecule-dev so the
rule is also documented where agents read it, not just enforced.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: molecule-ai[bot] <276602405+molecule-ai[bot]@users.noreply.github.com>
This commit is contained in:
Hongming Wang 2026-04-23 12:20:40 -07:00 committed by GitHub
parent a9c0cdadfe
commit 75200f4adc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -0,0 +1,63 @@
name: Retarget main PRs to staging
# Mechanical enforcement of SHARED_RULES rule 8 ("Staging-first workflow, no
# exceptions"). When a bot opens a PR against main, retarget it to staging
# automatically and leave an explanatory comment. Human CEO-authored PRs (the
# staging→main promotion PR, etc.) are left alone — they're the authorised
# exception to the rule.
#
# Why an Action instead of only a prompt rule: prompt rules depend on every
# role's system-prompt.md staying in sync. Today 5 of 8 engineer roles
# (core-be, core-fe, app-fe, app-qa, devops-engineer) don't have the
# staging-first section — the bot keeps opening PRs to main. An Action
# enforces the invariant regardless of prompt drift.
on:
pull_request_target:
types: [opened, reopened]
branches: [main]
permissions:
pull-requests: write
jobs:
retarget:
name: Retarget to staging
runs-on: ubuntu-latest
# Only fire for bot-authored PRs. Human CEO PRs (staging→main promotion)
# are intentional and pass through.
if: >-
github.event.pull_request.user.type == 'Bot'
|| endsWith(github.event.pull_request.user.login, '[bot]')
|| github.event.pull_request.user.login == 'app/molecule-ai'
|| github.event.pull_request.user.login == 'molecule-ai[bot]'
steps:
- name: Retarget PR base to staging
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
run: |
echo "Retargeting PR #${PR_NUMBER} (author: ${PR_AUTHOR}) from main → staging"
gh api -X PATCH \
"repos/${{ github.repository }}/pulls/${PR_NUMBER}" \
-f base=staging \
--jq '.base.ref'
- name: Post explainer comment
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
gh pr comment "$PR_NUMBER" \
--repo "${{ github.repository }}" \
--body "$(cat <<'BODY'
[retarget-bot] This PR was opened against `main` and has been retargeted to `staging` automatically.
**Why:** per [SHARED_RULES rule 8](https://github.com/Molecule-AI/molecule-ai-org-template-molecule-dev/blob/main/SHARED_RULES.md), all feature work targets `staging` first; the CEO promotes `staging → main` separately.
**What changed:** just the base branch — no code change. CI will re-run against `staging`. If you get merge conflicts, rebase on `staging`.
**If this PR is the CEO's staging→main promotion:** the Action skipped you (only bot-authored PRs are retargeted). If you see this comment on your CEO PR, that's a bug — please tag @HongmingWang-Rabbit.
BODY
)"