#350 made the CI-trigger scheduler (ci-trigger.yml) dispatch ci.yml with the built-in GITHUB_TOKEN, on the claim that workflow_dispatch is anti-recursion-exempt so no PAT is needed. In practice a GITHUB_TOKEN-triggered run requires manual approval — it sits in action_required and never runs un-attended, while a dispatch by an authorized user runs immediately. So auto-updated PRs' CI never ran (this stalled #285). The original #349 design was right: a PAT dispatch runs as the authorized token owner, so there is no approval gate.
Fix — separation of concerns
ci-trigger.yml (triggering): the "Trigger CI…" step's GH_TOKEN is now ${{ secrets.AUTOUPDATE_TOKEN || github.token }} (was ${{ github.token }}). AUTOUPDATE_TOKEN (the PAT) is required for the scheduler — #350 wrongly declared it unused. The || github.token fallback keeps this fail-open if the secret is absent, but that GITHUB_TOKEN path only actually starts CI if repo settings don't gate GITHUB_TOKEN-triggered runs.
autoupdate.yml (updates): unchanged — the branch update stays on GITHUB_TOKEN so it does NOT retrigger CI (retriggering here is what kills the cascade). Clarified its comment so the still-required AUTOUPDATE_TOKEN secret isn't deleted.
So: updates = GITHUB_TOKEN, triggering = PAT.
Corrected the now-wrong "no PAT needed / workflow_dispatch is anti-recursion-exempt" comments in ci-trigger.yml and the traffic_control.py docstrings.
Validation
yaml.safe_load parses ci-trigger.yml, autoupdate.yml, and ci.yml clean.
python -m unittest discover -s .github/scripts — 59 tests pass (the change is workflow-env only; script logic unchanged).
Closes #351
## The bug
#350 made the CI-trigger scheduler (`ci-trigger.yml`) dispatch `ci.yml` with the built-in **GITHUB_TOKEN**, on the claim that `workflow_dispatch` is anti-recursion-exempt so no PAT is needed. In practice a **GITHUB_TOKEN-triggered run requires manual approval** — it sits in `action_required` and never runs un-attended, while a dispatch by an authorized user runs immediately. So auto-updated PRs' CI never ran (this stalled #285). The original #349 design was right: a **PAT** dispatch runs as the authorized token owner, so there is no approval gate.
## Fix — separation of concerns
- **`ci-trigger.yml` (triggering):** the "Trigger CI…" step's `GH_TOKEN` is now `${{ secrets.AUTOUPDATE_TOKEN || github.token }}` (was `${{ github.token }}`). **`AUTOUPDATE_TOKEN` (the PAT) is required** for the scheduler — #350 wrongly declared it unused. The `|| github.token` fallback keeps this fail-open if the secret is absent, but that GITHUB_TOKEN path only actually starts CI if repo settings don't gate GITHUB_TOKEN-triggered runs.
- **`autoupdate.yml` (updates):** unchanged — the branch update stays on **GITHUB_TOKEN** so it does NOT retrigger CI (retriggering here is what kills the cascade). Clarified its comment so the still-required `AUTOUPDATE_TOKEN` secret isn't deleted.
- So: **updates = GITHUB_TOKEN, triggering = PAT.**
- Corrected the now-wrong "no PAT needed / `workflow_dispatch` is anti-recursion-exempt" comments in `ci-trigger.yml` and the `traffic_control.py` docstrings.
## Validation
- `yaml.safe_load` parses `ci-trigger.yml`, `autoupdate.yml`, and `ci.yml` clean.
- `python -m unittest discover -s .github/scripts` — 59 tests pass (the change is workflow-env only; script logic unchanged).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #351
The bug
#350 made the CI-trigger scheduler (
ci-trigger.yml) dispatchci.ymlwith the built-in GITHUB_TOKEN, on the claim thatworkflow_dispatchis anti-recursion-exempt so no PAT is needed. In practice a GITHUB_TOKEN-triggered run requires manual approval — it sits inaction_requiredand never runs un-attended, while a dispatch by an authorized user runs immediately. So auto-updated PRs' CI never ran (this stalled #285). The original #349 design was right: a PAT dispatch runs as the authorized token owner, so there is no approval gate.Fix — separation of concerns
ci-trigger.yml(triggering): the "Trigger CI…" step'sGH_TOKENis now${{ secrets.AUTOUPDATE_TOKEN || github.token }}(was${{ github.token }}).AUTOUPDATE_TOKEN(the PAT) is required for the scheduler — #350 wrongly declared it unused. The|| github.tokenfallback keeps this fail-open if the secret is absent, but that GITHUB_TOKEN path only actually starts CI if repo settings don't gate GITHUB_TOKEN-triggered runs.autoupdate.yml(updates): unchanged — the branch update stays on GITHUB_TOKEN so it does NOT retrigger CI (retriggering here is what kills the cascade). Clarified its comment so the still-requiredAUTOUPDATE_TOKENsecret isn't deleted.workflow_dispatchis anti-recursion-exempt" comments inci-trigger.ymland thetraffic_control.pydocstrings.Validation
yaml.safe_loadparsesci-trigger.yml,autoupdate.yml, andci.ymlclean.python -m unittest discover -s .github/scripts— 59 tests pass (the change is workflow-env only; script logic unchanged).🤖 Generated with Claude Code