Files
PaperClipAI/scripts
b226336762 ci: skip full CI for release-notes-only pull requests (#16207)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Each beta release ends with a pull request that adds one release
notes file under `releases/`
> - PR CI runs the full build, test, and e2e matrix for that pull
request
> - No build, test, or e2e lane reads `releases/v*.md` or
`releases/beta/v*.md`
> - The full matrix takes about 30 minutes, and lost runners or flaky
e2e specs can make it run again
> - This pull request lets the existing CI scope gate skip the heavy
lanes when a pull request changes only release notes
> - The benefit is that release notes pull requests get a green result
in minutes, and code pull requests keep full CI

## Linked Issues or Issue Description

**Issue type**

CI efficiency enhancement.

**Where is the issue?**

The `Select stacked PR CI scope` step in
`.github/workflows/ci-routing.yml`. This step sets the `full_ci` output
for PR CI.

**What's wrong?**

The step sets `full_ci=false` only for middle pull requests in a stack.
A pull request that changes only one release notes markdown file runs
the full matrix. For example, #16053 changed one file in
`releases/beta/`. Its CI ran two times: on the first run, 8 shards lost
their runners, and on the second run, one Playwright spec flaked and
needed a rerun.

**Suggested fix**

Read the pull request diff from the GitHub compare API in the scope
step. When every changed path is release notes, set `full_ci=false`. The
callers already support this value. I found no open pull request or
issue for this change.

## What Changed

- `ci-routing.yml`: the scope step (renamed to `Select PR CI scope`)
also sets `full_ci=false` when every path in the diff matches
`releases/v*.md` or `releases/beta/v*.md`.
- The step reads the diff from `compare/<event base SHA>...<event head
SHA>`. The SHAs come from the event, so a later push cannot change the
decision for this run.
- For a renamed file, the step checks the old path and the new path.
- The step keeps full CI when the event is not `pull_request`, a SHA is
malformed, the API call fails, the diff is empty, or the file list has
300 entries. The compare API can truncate a list at 300 entries.
- The step does not change the stacked pull request rules. It checks the
paths only when the stack rules select full CI.
- `ci-routing.test.mjs`: the GitHub stub now returns `files` for compare
calls. 17 new cases cover release notes paths, mixed diffs, renames,
non-markdown files, nested folders, empty and truncated lists, API
failure, non-PR events, malformed SHAs, and stack interaction.
- `e2e-shard.test.mjs`: the test now uses the new step name.
- `doc/DEVELOPING.md`: added a short description of the CI scope rules.

## Verification

- `node --test .github/scripts/tests/ci-routing.test.mjs
scripts/__tests__/e2e-shard.test.mjs`: 73 pass, 0 fail.
- `node --test '.github/scripts/tests/*.test.mjs'`: all pass.
- I ran the jq filter on real compare API responses. #16053 (one file in
`releases/beta/`) returns `true`. #16082 (10 files) returns `false`.
- After merge: open a pull request that changes only a
`releases/beta/v*.md` file. The `Select trusted runner` job shows the
notice `release notes only; full_ci=false`. The heavy lanes show as
skipped. The `policy`, `verify`, and `e2e` checks pass.

Note: `pr.yml` calls `pr-trusted.yml@master`, and that workflow calls
`ci-routing.yml@master`. This pull request does not change its own CI
run. The change applies after merge.

## Risks

- Low risk. The skip uses the existing `full_ci=false` path. The
`verify` and `e2e` aggregate checks already accept that value, and the
`policy` job always runs.
- A future job that reads release notes files would not run for
notes-only pull requests. Today, only the release workflows read these
files, and those workflows do not run on pull requests.
- The step now uses `GH_TOKEN` to call one more read-only API endpoint.
The workflow still does not check out or run pull request code, and its
permissions do not change.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic. Agentic coding with
tool use (shell, file edits, GitHub CLI).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:16:34 -07:00
..