Skip to content
This repository was archived by the owner on Oct 26, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 83 additions & 17 deletions .github/workflows/test-shard-timings-refresh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,40 @@
# edit, not this workflow's.
# ⛔ It never opens a pull request for a byte-identical file.
#
# ## The cost it carries, stated
# ## Whose identity opens the pull request, and why (objectui#13349)
#
# The pull request is opened with this run's `GITHUB_TOKEN`, and GitHub starts
# no workflow run for an event that token raised -- the release pull request's
# limitation, which objectui#5397's ruling chose to keep rather than add a
# personal access token. So the refresh pull request arrives with no CI; the
# seat or person who lands it pushes to its branch once (a merge of `main` is
# enough), and that push runs the full suite on the new split. The branch is
# this workflow's own and is overwritten by each refresh, the same posture
# `changeset-release.yml` takes with its version branch.
# GitHub starts no workflow run for an event raised by this run's
# `GITHUB_TOKEN`. Until objectui#13349 the refresh pushed and opened with that
# token, so every refresh pull request arrived with no CI and sat until a seat
# or person pushed to its branch: #13028 waited from 2026-10-19 to 2026-10-23
# while the shards ran 1.3-1.8x apart on a dataset missing 764 files.
#
# So the two acts that leave the runner -- the push and the pull request -- are
# done as the fleet App (`objectstack-fleet[bot]`), whose events DO start
# workflows: `actions/create-github-app-token` mints a token on this runner
# from the organization variable `OS_FLEET_APP_ID` and the organization secret
# `OS_FLEET_PRIVATE_KEY`, the same pair and action objectstack's
# `fleet-write.yml` mints with. The token is narrowed to this one repository
# and to the three grants below, exists only in the steps that use it, and is
# revoked by the action's post step. The job's own `GITHUB_TOKEN` keeps only
# the reads the selection and the downloads need.
#
# ⛔ Never a personal access token: objectui#5397's ruling keeps one out of
# this repository's automation, and the fleet App is an installation, not
# a person. The App-token route here is objectui#13349's ruling (Sales,
# 2026-10-23), which reads #5397's rejection as scoped to the release
# pull request, where an in-workflow validation was the alternative; here
# the pull request's own full-suite run IS the validation.
# ⛔ No fallback to `GITHUB_TOKEN`. A missing credential is a red run that
# names it, never a quiet return to a pull request nobody's CI reads.
#
# The branch, `ci/test-shard-timings-refresh`, is this workflow's own and is
# overwritten by each refresh, the same posture `changeset-release.yml` takes
# with its version branch. A force-push moves it from last week's base to
# today's `main`, across whatever workflow files landed in between, and GitHub
# refuses an App token that moves a ref across a workflow-file change unless it
# carries `workflows: write` -- the reason for that third grant; this workflow
# writes no workflow file.
#
# ## Which runs it reads
#
Expand All @@ -71,7 +95,12 @@
#
# A pull request that edits this workflow or the scripts it runs executes it
# all -- the selection, the downloads, the regeneration -- and stops before
# the two acts that leave the runner: the push and the pull request.
# the two acts that leave the runner: the push and the pull request. It mints
# no fleet token either, so a pull request's run never reads the App secret.
#
# The same three steps run only from `main`: a manual dispatch on any other
# branch regenerates and prints, and pushes nothing, so the refresh branch is
# only ever built from `main`'s tree.

name: Test Shard Timings Refresh

Expand Down Expand Up @@ -103,14 +132,19 @@ jobs:
name: Regenerate the per-file test timings
runs-on: ubuntu-latest
timeout-minutes: 15
# The push and the pull request go out on the fleet App token minted
# below, so this run's own token only reads.
permissions:
contents: write # push this workflow's own branch
pull-requests: write # open the refresh pull request
contents: read # the checkout
actions: read # list runs, read their jobs, download their timing artifacts

steps:
# No persisted credential: the one push goes out on the fleet token
# (`gh auth setup-git` below), never on this run's `GITHUB_TOKEN`.
- name: Checkout code
uses: actions/checkout@v7
with:
persist-credentials: false

# The selector and the generator are node builtins only: no pnpm, no
# install.
Expand Down Expand Up @@ -158,18 +192,50 @@ jobs:
git diff --stat -- scripts/test-shard-timings.json
cat "$RUNNER_TEMP/summary.md" >> "$GITHUB_STEP_SUMMARY"

# Read as a boolean, never printed: a red run that names the missing
# credential beats `create-github-app-token`'s own error, which does not.
- name: Check the fleet App credential is visible to this repository
id: credential
if: steps.select.outputs.status == '0' && github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
env:
HAS_APP_ID: ${{ vars.OS_FLEET_APP_ID != '' }}
HAS_PRIVATE_KEY: ${{ secrets.OS_FLEET_PRIVATE_KEY != '' }}
run: |
if [ "$HAS_APP_ID" != 'true' ] || [ "$HAS_PRIVATE_KEY" != 'true' ]; then
echo "::error title=Test shard timings::The fleet App credential is not visible to this repository (OS_FLEET_APP_ID set: $HAS_APP_ID; OS_FLEET_PRIVATE_KEY set: $HAS_PRIVATE_KEY). Both are organization-level; grant this repository access to them. Nothing was pushed (objectui#13349)."
exit 1
fi
# The token's one repository, by name: the action takes names
# without the owner, and an empty list would widen it to every
# repository the installation covers.
echo "repository=${GITHUB_REPOSITORY#*/}" >> "$GITHUB_OUTPUT"

- name: Mint the fleet App token, narrowed to this repository
id: fleet
if: steps.select.outputs.status == '0' && github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.OS_FLEET_APP_ID }}
private-key: ${{ secrets.OS_FLEET_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ steps.credential.outputs.repository }}
permission-contents: write # push this workflow's own branch
permission-pull-requests: write # open or update the refresh pull request
permission-workflows: write # the force-push crosses workflow files main changed (header)

- name: Open or update the refresh pull request
if: steps.select.outputs.status == '0' && github.event_name != 'pull_request'
if: steps.select.outputs.status == '0' && github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_TOKEN: ${{ steps.fleet.outputs.token }}
BRANCH: ci/test-shard-timings-refresh
run: |
if git diff --quiet -- scripts/test-shard-timings.json; then
echo "The regenerated dataset is byte-identical to the committed one: no pull request."
exit 0
fi
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
gh auth setup-git
git config user.name 'objectstack-fleet[bot]'
git config user.email '332303061+objectstack-fleet[bot]@users.noreply.github.com'
git switch -c "$BRANCH"
git add scripts/test-shard-timings.json
git commit -m 'chore(test): refresh the per-file test timings (objectui#12208)'
Expand All @@ -179,7 +245,7 @@ jobs:
echo
cat "$RUNNER_TEMP/summary.md"
echo
echo '**This pull request has no CI of its own yet.** It was opened with the Actions token, and GitHub starts no workflow for an event that token raised. Push to its branch once (a merge of `main` is enough): the dataset is in the root vitest config import closure, so that push runs the full suite on the new split.'
echo 'Pushed and opened as the fleet App (objectui#13349), so this pull request runs its own CI: the dataset is in the root vitest config import closure, so that run is the full suite on the new split.'
} > "$RUNNER_TEMP/body.md"
open=$(gh pr list --repo "$GITHUB_REPOSITORY" --head "$BRANCH" --state open --json number --jq '.[0].number // empty')
if [ -n "$open" ]; then
Expand Down
24 changes: 16 additions & 8 deletions content/docs/guide/ci-cd-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ one has its own section below.
| `merge-queue-head-patrol.yml` | Merge queue head patrol | Every 15 minutes (cron `7,22,37,52 * * * *`); manual | No — it gates no branch and blocks no queue, but it **goes red on a finding**: a merge-queue head with no `merge_group` build is a live repo-wide block |
| `required-check-set-patrol.yml` | Required check set patrol | Daily (cron `23 5 * * *`); manual | No — it gates no branch and blocks no queue, but it **goes red on a finding**: a merge queue whose required set has lost `Type Check` validates nothing that a type error would fail |
| `hook-selftests.yml` | Hook Self-Tests | PR / push touching `.claude/hooks/**` or the workflow | **Yes** |
| `test-shard-timings-refresh.yml` | Regenerate the per-file test timings | Weekly cron `47 6 * * 1`; manual; PR touching the workflow or the two scripts it loads | No — it is path-filtered, so it does not report on most PRs; **blocking when it does run**. Its scheduled run opens a pull request and gates nothing |
| `test-shard-timings-refresh.yml` | Regenerate the per-file test timings | Weekly cron `47 6 * * 1`; manual; PR touching the workflow or the two scripts it loads | No — it is path-filtered, so it does not report on most PRs; **blocking when it does run**. Its scheduled run opens a pull request as the fleet App, so that pull request runs CI, and gates nothing |

The path filters explain most "why did nothing run on my PR?" questions:

Expand Down Expand Up @@ -2993,15 +2993,22 @@ full suite on the new split before it lands.
timings, or after a week of red — the selector exits 3, the job prints a warning naming the reason
and stays green, and nothing is written. A NOT MEASURED that persists is the finding.

**The refresh pull request arrives without CI.** It is opened with the run's `GITHUB_TOKEN`, and
GitHub starts no workflow for an event that token raised — the same limitation the release pull
request carries, which [#5397](https://github.com/objectstack-ai/objectui/issues/5397)'s ruling
kept rather than add a personal access token. Whoever lands it pushes to its branch once (a merge
of `main` is enough). The branch, `ci/test-shard-timings-refresh`, is this workflow's own and is
**The refresh pull request runs its own CI.** GitHub starts no workflow for an event raised by a
run's `GITHUB_TOKEN`, so until [#13349](https://github.com/objectstack-ai/objectui/issues/13349)
every refresh pull request arrived without CI and waited for someone to push to its branch. The
push and the pull request now go out as the fleet App (`objectstack-fleet[bot]`):
`actions/create-github-app-token` mints a token on the runner from the organization variable
`OS_FLEET_APP_ID` and secret `OS_FLEET_PRIVATE_KEY`, narrowed to this repository and to
`contents`, `pull-requests` and `workflows` write (the force-push moves the branch across any
workflow files `main` changed since the last refresh), and revokes it when the job ends. The job's
own token only reads. ⛔ No personal access token ([#5397](https://github.com/objectstack-ai/objectui/issues/5397)),
and ⛔ no fallback to `GITHUB_TOKEN`: when the credential is not visible to this repository the run
goes red and says so. The branch, `ci/test-shard-timings-refresh`, is this workflow's own and is
overwritten by each refresh, as `changeset-release.yml` does with its version branch.

**A pull-request run writes nothing.** It runs the selection, the downloads and the regeneration,
and skips the push and the pull request.
**A pull-request run writes nothing**, and neither does a manual dispatch on any branch but `main`.
It runs the selection, the downloads and the regeneration, and skips the mint, the push and the
pull request.

### Merge Queue Head Patrol (`merge-queue-head-patrol.yml`)

Expand Down Expand Up @@ -3452,6 +3459,7 @@ on:
|-------------------|---------|---------|
| `GITHUB_TOKEN` | All workflows | GitHub API access (automatic) |
| `NPM_TOKEN` | `changeset-release.yml` | npm package publishing |
| `OS_FLEET_APP_ID` (variable), `OS_FLEET_PRIVATE_KEY` (secret) | `test-shard-timings-refresh.yml` | Mint the fleet App token the refresh pushes its branch and opens its pull request with, so that pull request runs CI. Both are **organization**-level. If either is not visible to this repository, the run fails red. |
| `CROSS_REPO_ISSUE_TOKEN` | `cross-repo-issue-closer.yml` | Closing issues in sibling repositories. `GITHUB_TOKEN` cannot do this — it is scoped to the repository running the workflow. When absent the workflow reports instead of closing. |
| `VERCEL_TOKEN` | `docs-deploy.yml` | Vercel API token for the Object Stack team, used by `vercel pull` and `vercel deploy`. It is stored as an **organization** secret. If it is missing, the run fails red. |
| `TURBO_TOKEN` | Build workflows | Turbo remote cache authentication |
Expand Down
Loading