Files
Vojtech NovakandClaude Opus 5.5 ad36e49993 [agent-cli] CI: an LLP-only PR runs only the format check and the Linux unit job (#334)
## Summary

A PR that changes only LLP documents ran the whole agent-cli CI: six
Linux and Windows e2e shards, the macOS e2e job, the Windows unit job,
the agent evals, and four billed EAS Simulator sessions. No test in
those jobs reads `llp/`.

## How

The stack gate (`scripts/stack-gate.ts`) already decides, for GitHub and
EAS, whether a PR runs CI. It now returns a scope instead of a boolean:

- `none`: an open PR above holds this PR's head commit. Nothing runs
(unchanged).
- `llp`: the PR is based on the default branch, its head is the event's
commit, and every changed path, including the old path of a rename, is
under `packages/@expo/agent-cli/llp/`. Only `tier0-linux` (its
`oldName-test` scans `llp/`) and `oxfmt` run.
- `all`: anything else. Errors, pushes, manual runs and schedules also
give `all`. A stack layer above the default branch also gets `all`:
GitHub lists its files against the layer below, so an LLP-only top layer
would hide the code of a lower layer that it covers.

The script maps the scope to two outputs in one table: `run` (false only
on `none`, the old meaning) and `full` (true only on `all`), and prints
`full` on stdout. `tier0-linux` and `oxfmt` keep `run == 'true'`.
`tier0-e2e`, `tier0-e2e-macos`, `tier0-windows` and `tier1-agent-eval`
check `full != 'false'`, so an empty output runs them; a test fails on
any `outputs.full ==`. On EAS the gate step keeps its fail-open form and
names the output for what it carries: `set-output full "$(bun
scripts/stack-gate.ts || echo true)"`; the four cloud jobs check `full
== 'true'`. No status check is required by the ruleset, so a skipped job
does not block a merge.

## Verification

- `bun test scripts`: 43 pass. `stack-gate.test.ts` covers the file
rule, a rename from `src/` into `llp/`, an LLP-only stack layer, a head
that is not the event commit (or no event commit), "covered wins over
LLP-only", the exact reason of every scope, pagination, a GitHub error,
the condition form, the scope-to-output table, and the real script
against a local fake GitHub for an LLP-only PR (stdout `false`,
`run=true`, `full=false`). Breaking the page loop, dropping
`previous_filename`, writing one `full ==` condition, or printing `run`
on stdout each makes a case fail. The stack-layer case fails without the
base check.
- The four workflow files parse. `oxfmt --check` passes on the changed
files.
- Not checked: the skip on GitHub and on EAS for a real LLP-only PR.
This PR changes code, so every job runs here.

## Watch

`stack-gate.yml` gains a `full` output; `run` keeps its meaning, so
`format.yml` is unchanged. The EAS gate runs without `GITHUB_TOKEN`, so
the extra files request is unauthenticated; a rate-limit 403 gives
`all`.

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

Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-11-13 19:26:38 +01:00
..