Skip to content

Commit ec236d4

Browse files
ci(shard-timings): give the write-back step every variable it expands, and rehearse it on pull_request (#19933)
Fixes #18341 Clause-②: no ## What this changes One file: `.github/workflows/shard-timings-refresh.yml`. 1. **The write-back step now exports every variable its script expands.** Its `env:` gave `GH_TOKEN`, `RUN_ID`, `HEAD_SHA`; the commit message also expands `RUN_COUNT` and `RUNS` under `set -euo pipefail`. Both are added from the same `steps.generate.outputs` the compose step already reads. The commit message is unchanged: `$RUN_COUNT` and `$RUNS` stay in it (they are the dataset's provenance). 2. **Structural defense: the write and its `pull_request` rehearsal are now ONE step with ONE `env:` and ONE script.** The old pair was gated `github.event_name != 'pull_request'` / `== 'pull_request'`, so no PR ever ran the script that writes. Now the step runs on every event (`if: steps.compare.outputs.changed == 'true'`). On a PR run the branch, the `git add` and the commit (whose message expands every provenance variable) run for real on the runner. Every act that leaves the runner goes through one shell function, `outward`, driven by `DRY_RUN: ${{ github.event_name == 'pull_request' }}`. That covers `git push`, `gh pr create`, `gh pr view`, the label POST and its read-back. On a dry run `outward` prints the fully expanded command and returns a stand-in value. The shell expands arguments before `outward` is entered, so `set -u` judges them on both legs. A key missing from `env:` now reds the PR run that dropped it. 3. **The switch cannot be turned the wrong way.** The script refuses any `DRY_RUN` other than `true`/`false`. It also refuses `false` when `GITHUB_EVENT_NAME` is `pull_request`, and an absent `DRY_RUN` is itself an unbound variable. `GH_TOKEN` is read by `gh`, not by the shell, so a dry run would never notice it missing. The script names it once as `${GH_TOKEN:?…}`, so both legs judge it too. 4. The old "Dry run — the pull request this would have opened" step is folded into the same script (same summary text, one sentence updated). The header's `pull_request` paragraph and the compose step's comment now describe the new shape. ⛔ Not touched: `MAX_SHARD_OVER_MEAN`, `MAX_MEASURED_OVER_PREDICTED`, `timeout-minutes`, the shard matrix, `FILE_SHARDED_PACKAGES`, or any threshold. The diff has zero lines naming any of them. ## Measured: both directions (acceptance item 2) Harness: each leg lifts the step's `run:` script out of the YAML (parsed with `yaml`). It evaluates the step's OWN `env:` block into the environment, using the values the failing scheduled run carried (`RUN_ID=34808103618`, `RUN_COUNT=1`, `HEAD_SHA=a90a9f2679…`) and a fake token. It adds only the runner defaults (`GITHUB_REPOSITORY`, `GITHUB_EVENT_NAME`, `RUNNER_TEMP`, `GITHUB_STEP_SUMMARY`, `GITHUB_OUTPUT`, `HOME`, `PATH`, `CI`) under `env -i`, and runs the script with `bash -e`, the shell the job log shows for these steps. The scratch repo matches the runner's checkout: a depth-1 clone of `main` with `core.hooksPath=.githooks`, which the runner's `pnpm install` registers (job log line: `git integration registered (merge.os-regen.name, merge.os-regen.driver, core.hooksPath)`). So the repo's real `pre-commit` and `pre-push` hooks run. PATH shims sit in front of `gh` (records the call, answers a canned value) and `git push` (records the call, forwards only when `origin` is a local bare repo). Nothing left the machine. Base script = blob `fe5a62ef1c` (`origin/main` `fdeeea0cc9`). Fixed script = blob `2b997d121b` (this PR's head `d4ba97991e`). | leg | script | event | env change | exit | reading | |---|---|---|---|---|---| | L1 | base | schedule | none (the shipped omission) | **1** | `line 9: RUN_COUNT: unbound variable`: byte-for-byte the CI failure of run 34810389734. 0 pushes, 0 gh calls | | L7 | base, the old dry-run step | pull_request | none | **0** | control: the old rehearsal is green over the same defect | | L2 | fixed | schedule | complete | **0** | commit made with the full provenance body. Real `pre-push` ran (`✓ check:commit-card-trailers: 1 commit message(s) … carry no card relation`). Branch reached the local origin. 5 recorded calls: `git push`, `gh pr create`, `gh pr view`, label POST, label read-back | | L3 | fixed | schedule | drop `RUNS` | **1** | `RUNS: unbound variable`, no commit, 0 pushes | | L4 | fixed | pull_request | complete | **0** | commit made locally. **0** recorded calls, no branch on origin. Every outward act printed as `DRY RUN, not executed: …`. Summary carries the dry-run section | | L5 | fixed | pull_request | drop `RUN_COUNT` | **1** | `RUN_COUNT: unbound variable`: **the PR leg now catches the defect class** | | L8 | fixed | pull_request | drop `GH_TOKEN` | **1** | `GH_TOKEN: is not set; gh would run unauthenticated.` | | L6 | fixed | pull_request | force `DRY_RUN=false` | **1** | `::error::DRY_RUN is 'false' on a pull_request run …`, 0 calls | | L6b | fixed | schedule | drop `DRY_RUN` | **1** | `DRY_RUN: unbound variable` | | L6c | fixed | schedule | `DRY_RUN=yes` | **1** | `::error::DRY_RUN must be 'true' or 'false', got 'yes'.` | The exit codes were read from each run directly, never through a pipe. The fix commits came first, and every leg ran against those committed blobs. ## Audit of the whole file (acceptance item 3) Method: every `run:` block parsed out of the YAML. A scanner that skips single-quoted text and `${{ }}` lists each shell expansion (`$X`, `${X}`, arithmetic names) and each `process.env.X` read by an inline `node -e`. Each name is classified as: step `env:`, assigned in the script, `$GITHUB_ENV` from an earlier step, or a runner default. The file has no workflow-level or job-level `env:` and no `defaults:`. Positive control: over the base file the scanner reports exactly two UNRESOLVED names, `RUN_COUNT` and `RUNS` in the write step. Over this PR's head it reports zero. | step | `set -u` | step `env:` | expanded names not assigned in the script | verdict | |---|---|---|---|---| | Get pnpm store directory | no | none | `GITHUB_ENV` (runner) | ok | | Install dependencies | no | none | none | ok | | Self-test the generator and the run selector | no | none | none (`failed` is local) | ok | | List the workspace | no | none | `RUNNER_TEMP` (runner) | ok | | Choose a green, uncensored, un-replayed run | no | `GITHUB_TOKEN` | `RUNNER_TEMP`, `GITHUB_OUTPUT`, `GITHUB_STEP_SUMMARY` (runner); `GITHUB_TOKEN` read by the child script | ok | | Regenerate the dataset… | **yes** | `GITHUB_TOKEN` | `GITHUB_TOKEN` (step), `RUNNER_TEMP`, `GITHUB_REPOSITORY`, `GITHUB_OUTPUT` (runner); `RUN_ID`, `RUN_COUNT` etc. are LOCAL here | ok | | Compare against the committed dataset | no | none | `RUNNER_TEMP`, `GITHUB_OUTPUT`, `GITHUB_STEP_SUMMARY` | ok | | Predicted bins, before and after | no | none | `RUNNER_TEMP`, `GITHUB_OUTPUT` | ok | | Compose the pull request body | **yes** | `RUN_ID`, `RUNS`, `RUN_COUNT`, `HEAD_SHA`, `PARTITIONER_EXIT`, `USED_PAT` | all six (step; `PARTITIONER_EXIT` also defaulted `:-0`), `GITHUB_REPOSITORY`, `RUNNER_TEMP`; node reads `RUNNER_TEMP`, `RUN_ID` | ok | | Push the refresh branch… (base) | **yes** | `GH_TOKEN`, `RUN_ID`, `HEAD_SHA` | **`RUN_COUNT`, `RUNS`: UNRESOLVED** | the defect | | Push the refresh branch… (this PR) | **yes** | `DRY_RUN`, `GH_TOKEN`, `RUN_ID`, `RUNS`, `RUN_COUNT`, `HEAD_SHA` | all step keys, plus `GITHUB_EVENT_NAME`, `GITHUB_REPOSITORY`, `RUNNER_TEMP`, `GITHUB_STEP_SUMMARY` (runner) | ok | | Say what happened when nothing changed | no | none | `GITHUB_STEP_SUMMARY`; its other values are `${{ }}` expressions, substituted before bash | ok | No second instance of the defect class exists in this file. After this PR no step's execution depends on the event: `DRY_RUN` is the file's only `github.event_name` test. The remaining legs split on data, not on the event (`changed` true/false, the selector's exit 3), and the selector's own `--self-test` already drives its exit-3 leg. ## Static read of what runs after the commit (never executed on GitHub; ⛔ not asserted to pass) - **Credential in use:** on run 34810389734 the compose step's env printed `USED_PAT: false`, so `GH_TOKEN` and the checkout credential were the Actions `github.token`, with job `permissions` `contents: write`, `pull-requests: write`, `actions: read`. - **`git push origin claude/shard-timings-refresh-RUN_ID`:** it needs `contents: write` (declared). `GET /repos/…/rules/branches/claude/shard-timings-refresh-1` answers `[]`, and the one repository ruleset (`main`) targets `~DEFAULT_BRANCH` only. The repo's `pre-push` hook runs on the runner and passed in leg L2 on a depth-1 clone. NOT MEASURED: classic branch-protection patterns (no read path from this seat). - **`gh pr create` with the Actions token:** this needs the repository setting that lets GitHub Actions create pull requests. The seat cannot read it (`GET /repos/…/actions/permissions/workflow` answers 403 through the agent proxy). Circumstantial evidence: #17076 (`chore: version packages`, open) was authored by `github-actions[bot]` on 2026-09-09, and `release.yml` says changesets/action opens it with the default token. NOT MEASURED for this workflow. - **Label POST on `issues/N/labels` with `pull-requests: write` and no `issues:` scope:** in-repo precedent is `pr-automation.yml`, whose label-writing jobs declare exactly `contents: read` plus `pull-requests: write`. The label exists (`GET /labels/skip-changeset` answers 200), so no create is implied. - Nothing found that would fail. The first live execution is still the post-merge dispatch below. ## Owed after merge: acceptance item 4 Not triggered here, by design. After merge, dispatch the lane on `main` and read the PR it opens: ``` gh workflow run shard-timings-refresh.yml --repo objectstack-ai/objectstack --ref main ``` (REST equivalent: `POST /repos/objectstack-ai/objectstack/actions/workflows/shard-timings-refresh.yml/dispatches` with body `{"ref":"main"}`.) `workflow_dispatch` evaluates `DRY_RUN` to `false`, so that run writes. ## Changeset None. The diff is `.github/` only and publishes nothing from any package, so it takes route 2 of the `Check Changeset` gate, the `skip-changeset` label. An empty-frontmatter changeset is rejected by that gate. This PR does not apply labels; that is the seat's. ## Gates `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` at `d4ba97991e` derived 40 commands, all run from this worktree. All 40 exited 0 with their own verdict lines. `pnpm check:pm-dispatch-gates` ran detached, as its header prescribes: `✓ dispatch-gates self-test: 1905 cases pass.` in 722.1s. `--ran` reconciliation: `40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED (a DERIVED zero — all 40 recorded an exit code and none of them is 3)`. Also run: the five roster families the derivation flags as living under `.github/workflows` (`check-platform-checklist-watchdog` plus its self-test, `check-ci-filter-parity` plus its self-test, `ci/scheduled-full-run --self-test`, `pr-labels --self-test`), all exit 0. No `actionlint` or other workflow linter exists in the repo's tooling or on this container. NOT MEASURED: the type-check lanes and the six workflow-valued families the derivation lists as CI-only. ## Acceptance notes - The defense is only as strong as the PR run is visible. This lane's `pull_request` run is not in the merge queue's required set, so its red is advisory. Making it required is the maintainer's call, and this PR does not do it. - The rehearsal covers the write script whenever the PR run's regeneration differs from the committed file. `measuredAt` is the run's date, so that is every PR run except one on the same UTC day as a landed refresh with identical inputs. - A re-run after a partial success would meet the already-pushed `claude/shard-timings-refresh-RUN_ID` branch and be refused as non-fast-forward. This is not observed, only read. ## 维护者速读(草稿) - **改了什么**:定时刷新分片时长数据集的工作流里,「推分支、开 PR」那一步补上了漏掉的两个变量;并且把它和 PR 上的演练合成同一步、同一套变量,只在对外动作(push、开 PR、打标签)前加了一个开关。 - **为什么改**:这一步从没在合并前跑过,第一次真跑就是 9 月 14 日的定时任务,算完数据后死在提交那一行,数据集因此一直没刷新。现在任何 PR 只要改到这条工作流,就会把这一步(含提交)真跑一遍,漏变量当场变红。 - **风险与代价(含回滚)**:PR 上多跑一次本地提交,不推送、不开 PR、不打标签;开关写错会直接报错而不是误推。回滚即还原这一个文件。 - **席位意见**: - **你要做的**:合并本 PR(工作流改动需人工合);合并后手动触发一次 `workflow_dispatch`,确认它真开出刷新 PR。 --- _Generated by [Claude Code](https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent fdeeea0 commit ec236d4

1 file changed

Lines changed: 112 additions & 39 deletions

File tree

‎.github/workflows/shard-timings-refresh.yml‎

Lines changed: 112 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,14 @@ on:
139139
# until the next sweep.
140140
#
141141
# On a `pull_request` run everything executes — selection, download,
142-
# regeneration, the coverage check, the byte comparison and the partitioner's
143-
# verdict — so the transport and the flags are proven on a real runner rather
144-
# than argued about. The WRITE is what is skipped: no branch is pushed, no PR
145-
# is opened, no label is written, and the body that would have been posted is
146-
# rendered to the run's step summary instead.
142+
# regeneration, the coverage check, the byte comparison, the partitioner's
143+
# verdict, and the write step's own script with the write step's own `env:`,
144+
# up to and including the local commit — so the transport, the flags and the
145+
# write step's variables are proven on a real runner rather than argued
146+
# about. Only the acts that leave the runner are switched off, behind the one
147+
# `DRY_RUN` switch in that step: no branch is pushed, no PR is opened, no
148+
# label is written, and the body that would have been posted is rendered to
149+
# the run's step summary instead.
147150
pull_request:
148151
paths:
149152
- '.github/workflows/shard-timings-refresh.yml'
@@ -517,8 +520,9 @@ jobs:
517520
518521
# Composition is separated from the WRITE on purpose: a `pull_request` run
519522
# of this lane must exercise the body-building — the shard durations, the
520-
# bins, the conditional blocks — without pushing anything. Both the write
521-
# step and the dry-run step below consume this file.
523+
# bins, the conditional blocks — without pushing anything. The write step
524+
# below consumes this file on every event: as the PR body when it writes,
525+
# and as the step summary on a `pull_request` dry run.
522526
- name: Compose the pull request body
523527
if: steps.compare.outputs.changed == 'true'
524528
env:
@@ -631,16 +635,85 @@ jobs:
631635
} > "$RUNNER_TEMP/pr-body.md"
632636
echo "Composed a $(wc -l < "$RUNNER_TEMP/pr-body.md")-line pull request body."
633637
634-
# The WRITE. Skipped on a `pull_request` run of this lane: a PR that only
635-
# edits this workflow must never push a bot branch or open a second PR.
636-
- name: Push the refresh branch and open the pull request
637-
if: steps.compare.outputs.changed == 'true' && github.event_name != 'pull_request'
638+
# The WRITE — and, on a `pull_request` run of this lane, its rehearsal.
639+
#
640+
# ONE STEP, ONE `env:`, ONE SCRIPT, ON EVERY EVENT (#18341). The write and
641+
# its dry run used to be two steps behind mutually exclusive `if:`s
642+
# (`github.event_name != 'pull_request'` and `== 'pull_request'`), so no
643+
# pull request ever executed the script that writes. Its first execution
644+
# was scheduled run 34810389734: the dataset was computed, and the step
645+
# then died at `git commit` with `RUN_COUNT: unbound variable`, because
646+
# this step's `env:` exported three of the five variables its script
647+
# expands. Under `set -u` a key missing from `env:` blows up only on the
648+
# leg that runs, and the rehearsal ran the other leg.
649+
#
650+
# So a `pull_request` run now executes THIS script with THIS `env:`. The
651+
# branch, the `git add` and the commit — whose message expands every
652+
# provenance variable — happen for real on the runner, with the repo's own
653+
# commit hook, so a variable missing from the block below reds the pull
654+
# request that dropped it. Only the acts that leave the runner are
655+
# switched, and all of them are switched in ONE place: `outward`, which on
656+
# a dry run prints the command instead of running it. The shell expands a
657+
# command's arguments before `outward` is entered, so `set -u` judges every
658+
# argument on both legs alike.
659+
#
660+
# ⛔ Never call `git push`, `gh` or any other network act outside
661+
# `outward`, and never split this step back into an event-gated pair:
662+
# either one reopens a leg that no pull request can exercise.
663+
- name: Push the refresh branch and open the pull request (dry run on pull_request)
664+
if: steps.compare.outputs.changed == 'true'
638665
env:
666+
# The switch: 'true' on a `pull_request` run and only there. The script
667+
# refuses any other spelling, and refuses 'false' on a `pull_request`
668+
# run, so no edit to this line can make a pull request push.
669+
DRY_RUN: ${{ github.event_name == 'pull_request' }}
639670
GH_TOKEN: ${{ secrets.RELEASE_PUSH_TOKEN || github.token }}
671+
# Every variable the script expands that the runner does not provide.
672+
# The commit message is the dataset's provenance and names all four:
673+
# ⛔ never drop one from the message to get a green run.
640674
RUN_ID: ${{ steps.generate.outputs.run_id }}
675+
RUNS: ${{ steps.generate.outputs.runs }}
676+
RUN_COUNT: ${{ steps.generate.outputs.run_count }}
641677
HEAD_SHA: ${{ steps.generate.outputs.head_sha }}
642678
run: |
643679
set -euo pipefail
680+
681+
case "$DRY_RUN" in
682+
true) DRY_TAG='(dry run, not executed) ' ;;
683+
false) DRY_TAG='' ;;
684+
*)
685+
echo "::error::DRY_RUN must be 'true' or 'false', got '$DRY_RUN'. Nothing was pushed."
686+
exit 1
687+
;;
688+
esac
689+
if [ "$GITHUB_EVENT_NAME" = 'pull_request' ] && [ "$DRY_RUN" != 'true' ]; then
690+
echo "::error::DRY_RUN is '$DRY_RUN' on a pull_request run. A pull_request run of this lane never pushes a branch, opens a PR or writes a label. Nothing was pushed."
691+
exit 1
692+
fi
693+
# `gh` reads GH_TOKEN from the environment, not from an argument, so no
694+
# expansion below would notice it missing and a dry run never starts
695+
# `gh`. Named here, it is judged on both legs like every other key.
696+
: "${GH_TOKEN:?is not set; gh would run unauthenticated. Nothing was pushed.}"
697+
698+
# outward [--stand-in TEXT] COMMAND...
699+
# The one dry-run switch. Live, it runs COMMAND. Dry, it prints COMMAND
700+
# to the log instead, and prints TEXT on stdout where the live call's
701+
# output would have been, so every line after it runs on a value of
702+
# the same shape.
703+
outward() {
704+
local stand_in=''
705+
if [ "$1" = '--stand-in' ]; then
706+
stand_in="$2"
707+
shift 2
708+
fi
709+
if [ "$DRY_RUN" = 'true' ]; then
710+
{ printf 'DRY RUN, not executed:'; printf ' %q' "$@"; printf '\n'; } >&2
711+
if [ -n "$stand_in" ]; then printf '%s\n' "$stand_in"; fi
712+
return 0
713+
fi
714+
"$@"
715+
}
716+
644717
BRANCH="claude/shard-timings-refresh-$RUN_ID"
645718
git config user.name 'github-actions[bot]'
646719
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
@@ -651,57 +724,57 @@ jobs:
651724
git commit \
652725
-m "chore(ci): refresh the Test Core shard-timings dataset" \
653726
-m "Regenerated by .github/workflows/shard-timings-refresh.yml from the test-core-run-summary artifacts of $RUN_COUNT accumulated run(s) ($RUNS), newest $RUN_ID at $HEAD_SHA. Generated, never hand-edited."
654-
git push origin "$BRANCH"
727+
outward git push origin "$BRANCH"
655728
656-
PR_URL=$(gh pr create --base main --head "$BRANCH" \
729+
PR_URL=$(outward --stand-in "https://github.com/$GITHUB_REPOSITORY/pull/0" \
730+
gh pr create --base main --head "$BRANCH" \
657731
--title "chore(ci): refresh the Test Core shard-timings dataset" \
658732
--body-file "$RUNNER_TEMP/pr-body.md")
659-
echo "Opened $PR_URL" | tee -a "$GITHUB_STEP_SUMMARY"
733+
echo "${DRY_TAG}Opened $PR_URL" | tee -a "$GITHUB_STEP_SUMMARY"
660734
661735
# ADDITIVE label write only. A whole-set PUT replaces the PR's labels
662736
# and destroys any that land in between — measured on this repo, one
663737
# second wide (see pr-automation.yml's header). POST names only what it
664738
# adds, so no interleaving can lose another writer's label.
665-
PR_NUMBER=$(gh pr view "$PR_URL" --json number --jq .number)
666-
gh api --method POST "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" \
739+
PR_NUMBER=$(outward --stand-in 0 gh pr view "$PR_URL" --json number --jq .number)
740+
outward gh api --method POST "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" \
667741
-f "labels[]=skip-changeset" > /dev/null
668742
669743
# Read back, because an additive write is necessary and not sufficient:
670744
# a concurrent whole-set PUT from another workflow can still strip the
671745
# label after a successful POST. `skip-changeset` is this PR's exemption
672746
# from the changeset gate — it publishes nothing — so losing it turns
673747
# the gate red on a PR that legitimately has no changeset.
674-
if gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" --jq '.[].name' \
748+
if outward --stand-in skip-changeset gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" --jq '.[].name' \
675749
| grep -qxF 'skip-changeset'; then
676-
echo "skip-changeset confirmed on PR #$PR_NUMBER."
750+
echo "${DRY_TAG}skip-changeset confirmed on PR #$PR_NUMBER."
677751
else
678752
echo "::warning::skip-changeset did not survive the write on PR #$PR_NUMBER (a concurrent whole-set label PUT strips it). Re-applying once."
679-
gh api --method POST "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" \
753+
outward gh api --method POST "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" \
680754
-f "labels[]=skip-changeset" > /dev/null
681-
gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" --jq '.[].name' \
755+
outward gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/labels" --jq '.[].name' \
682756
| grep -qxF 'skip-changeset' \
683757
|| echo "::error::skip-changeset is still absent from PR #$PR_NUMBER; the changeset gate will demand a changeset this PR legitimately has none of. Apply the label by hand."
684758
fi
685759
686-
# The dry-run half of the `pull_request` posture. Everything above ran for
687-
# real; this renders the body that WOULD have been posted, so a reviewer of
688-
# a change to this lane sees the actual output rather than the diff of the
689-
# code that produces it.
690-
- name: Dry run — the pull request this would have opened
691-
if: steps.compare.outputs.changed == 'true' && github.event_name == 'pull_request'
692-
run: |
693-
{
694-
echo "### Shard timings: dry run (no branch pushed, no PR opened, no label written)"
695-
echo
696-
echo "This is a \`pull_request\` run of the refresh lane itself. The run selection, the"
697-
echo "artifact download, the regeneration, the coverage check and the partitioner's verdict"
698-
echo "all executed for real; only the write was skipped. The body below is what a scheduled"
699-
echo "run would have posted."
700-
echo
701-
echo "---"
702-
echo
703-
cat "$RUNNER_TEMP/pr-body.md"
704-
} >> "$GITHUB_STEP_SUMMARY"
760+
# The dry-run half of the `pull_request` posture: render the body that
761+
# WOULD have been posted, so a reviewer of a change to this lane sees the
762+
# actual output rather than the diff of the code that produces it.
763+
if [ "$DRY_RUN" = 'true' ]; then
764+
{
765+
echo "### Shard timings: dry run (no branch pushed, no PR opened, no label written)"
766+
echo
767+
echo "This is a \`pull_request\` run of the refresh lane itself. The run selection, the"
768+
echo "artifact download, the regeneration, the coverage check, the partitioner's verdict"
769+
echo "and the write step's own script, up to and including its local commit, all"
770+
echo "executed for real; only the push, the PR and the label write were skipped. The body"
771+
echo "below is what a scheduled run would have posted."
772+
echo
773+
echo "---"
774+
echo
775+
cat "$RUNNER_TEMP/pr-body.md"
776+
} >> "$GITHUB_STEP_SUMMARY"
777+
fi
705778
706779
- name: Say what happened when nothing changed
707780
if: steps.compare.outputs.changed == 'false'

0 commit comments

Comments
 (0)