Skip to content

ci(ci-scripts): post pr size as a pinned comment - #219

Merged
haydenshively merged 8 commits into
mainfrom
ci/pr-size-comment
Sep 15, 2026
Merged

haydenshively merged 8 commits into
mainfrom
ci/pr-size-comment

Conversation

@haydenshively

@haydenshively haydenshively commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

pr-describe made the agent measure the diff by hand — a git diff --numstat + awk pipeline plus tokei — and paste the result into the PR body under ## Size. That number was wrong the moment another commit landed, and nothing corrected it. CI now owns the measurement and keeps one pinned comment per PR, recomputed on every push.

Changes

  • packages/ci-scripts/src/pr-size/summary.ts holds the pure logic (bucketing, tokei-totals validation, table rendering); orchestrate/comment.ts reads the PR files API and upserts a marker-tagged comment. Reuses the package's existing githubApi/paginate/readPayload helpers rather than adding a dependency.
  • .github/workflows/pr-size.yml — two jobs. Comment holds pull-requests: write, checks out main, and never touches PR code: GitHub's PR files API serves the per-file additions/deletions the table needs, so no checkout of the diff is required at all. Measure checks out PR head for tokei but holds no write token, and hands over three integers through a job output.
  • .claude/commands/pr-describe.md — Step 1.2 and the ## Size section deleted; the agent no longer measures. Also repairs the unbalanced code fences in the Step 3 template, which were pre-existing.
  • Tests, knip.json entry, README, docs/INDEX.md.

Notes for review

The port is verified, not asserted. Run over a 229-file range spanning all four buckets, the new renderer produces a table byte-identical to the old awk. Against live PR #218, the rendered totals match GitHub's own additions/deletions/changed_files exactly.

tokei is built from source, pinned to v15.0.0. It has shipped no prebuilt binary since v12.1.2 in 2021, so pinning one only gets further out of date. ubuntu-latest already carries a Rust toolchain, and the cold build measured 45s in CI on this PR; only the resulting binary is cached, so restore is near instant and a stale entry just rebuilds. Verified that v12.1.2, v14.0.0 and v15.0.0 return identical code/comment/blank totals on the same inputs. The workflow parses tokei's plain-text Total row rather than --output json, which is stable across all three versions.

Two deliberate divergences from the old pipeline, both named in comments: a rename's content delta is attributed to the new path, and a binary file counts as one changed file at +0/−0 where the old awk dropped it from the file count entirely.

Cosmetic means cosmetic. Both jobs carry continue-on-error, so a failed build or merge-base leaves the PR green and the comment still posts, saying the code/prose split is unavailable.

Comment fails on this PR, by design. It runs main's ci-scripts, which has no pr-size-comment script until this merges. The workflow run still reports success. It passes from the next PR onward; the writer path was verified end to end by running the orchestrator against this PR directly (created, then updated in place, exactly one comment).

Deferred

BOTS-138pull_request runs the workflow as the PR defines it, so a branch can edit the job holding the write token. That grants a contributor nothing they lack here (pushing a branch already means repo write) and a fork's token is read-only, but it is not the boundary pull_request_target would give. pr-release-label-sync.yml has the identical exposure, so it is a repo-wide call rather than one to make in this PR. This workflow's header now states the exposure instead of claiming a boundary it does not have.

Test Plan

  • On this PR, confirm the size comment's numbers match git diff --numstat origin/main...HEAD
  • After merge, confirm the next PR gets the comment from CI and that it is edited in place on a second push

🤖 Generated with Claude Code

haydenshively and others added 4 commits September 14, 2026 21:41
`pr-describe` tallied the diff by hand with awk and tokei, then pasted the table
into the PR body, where it went stale on the next push. A two-job workflow now
recomputes it on every push and keeps one pinned comment.

`Comment` holds the write token and never checks out PR code: GitHub's PR files
API serves the per-file additions/deletions the table needs. `Measure` checks
the PR out for tokei but holds no write token, and hands over three integers
through a job output.

Verified against the old pipeline over a 229-file range across all four buckets:
byte-identical table.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- `continue-on-error` on both jobs, so a failed download or merge-base cannot
  redden a PR over a cosmetic comment
- `!cancelled()` instead of `always()`, so a run superseded by
  `cancel-in-progress` cannot post the new head's file counts beside the old
  head's tokei totals
- handle `edited`, guarded on a base change, so retargeting a stacked PR
  recomputes instead of leaving the former base's table pinned
- `xargs ... tokei --`: a root file named `--output` was read as an option and
  silently yielded an all-zero measurement (reproduced, then fixed)
- stop overclaiming in comments: `pull_request` runs the workflow as the PR
  defines it, and binaries count at +0/−0 where the old awk dropped them

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Concurrency resolves at workflow-run level, before any job `if:`. A title or
body edit therefore entered the group, cancelled a recompute still in flight,
then skipped both of its own jobs — leaving the comment stale or absent.
`cancel-in-progress` now carries the same condition as the job guard.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The guard that ran only on a base change could not be made race free. A run
that will go on to skip still enters the concurrency group first and displaces
a pending real one, because GitHub resolves concurrency at workflow-run level
and replaces a queued run regardless of `cancel-in-progress`.

Dropping the guard deletes both duplicated job conditions and the conditional
`cancel-in-progress`, and costs about a minute of CI on a title or body edit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@haydenshively haydenshively self-assigned this Sep 15, 2026
@haydenshively

haydenshively commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator Author

Size

Area Files + Net
src 3 +211 −1 +210
test 2 +155 −0 +155
docs 3 +23 −65 -42
ci 2 +156 −1 +155
total 10 +545 −67 +478

Changed files at head: 451 code, 344 comments, 157 blanks. tokei counts Markdown prose as comments, so a docs PR honestly reports near-zero code.

haydenshively and others added 3 commits September 14, 2026 22:17
Running the orchestrator against PR #219 under a PAT posted a second comment
instead of editing the first: the author filter looked for `type === 'Bot'` and
a user token is not one. CI always runs as `github-actions[bot]`, so this never
fires in production — but it is the same duplicate-on-every-push failure the
filter was supposed to prevent, just triggered by a different identity.

The marker is enough. Dropping the author check removes the only way the lookup
can miss, at the cost of a contrived case where someone prefixes their own
comment with the marker and has it overwritten.

Also records the bootstrap property found on #219: `Comment` runs main's
ci-scripts, so the job fails with "no script" on the PR that adds it, while
`continue-on-error` keeps the PR green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tokei has shipped no prebuilt binary since v12.1.2 in 2021, so pinning one only
gets further out of date. ubuntu-latest already carries a Rust toolchain, and
`cargo install tokei --locked` costs about a minute on a runner — measured at
18s wall / 83s CPU locally. Only the binary is cached, so restore is near
instant and a stale entry just rebuilds.

Now on v15.0.0. Verified v12.1.2, v14.0.0 and v15.0.0 return identical code,
comment and blank totals on the same inputs, and that `--` and empty input
still behave.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A cache entry is immutable at its key, so the previous comment's claim that a
corrupt one "simply rebuilds" was wrong: it would have cost the code/prose
split on every push until someone noticed and bumped the key. The restored
binary is now probed and rebuilt on failure.

Also moves the smoke check ahead of the save, so a bad build is never cached,
and spells out `success()` in both conditions — an explicit `if:` drops the
implicit one, which would otherwise let a failed build be saved.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@haydenshively
haydenshively marked this pull request as ready for review September 15, 2026 04:13
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-15T04:22:34.863377Z be18d09 Draft marked ready
🔒 Security Review Completed 2026-09-15T04:20:54.660435Z be18d09 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

Comment thread .github/workflows/pr-size.yml
Comment thread .github/workflows/pr-size.yml

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: be18d093ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/pr-size.yml Outdated
Comment thread .github/workflows/pr-size.yml Outdated
Comment thread .github/workflows/pr-size.yml
`set -e` was inherited from the runner's default shell (`bash -e {0}`) rather
than stated. Verified both ways: under `bash -e` a failed merge-base exits 128
before the echo, under plain bash it publishes zeroes that `Comment` cannot
tell from a real empty diff. Spelled out so the property is local.

Also drops one-time rollout history from the header, per the repo rule that
comments state a guarantee or a hazard and leave provenance to git.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@dev-carapulse dev-carapulse Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving the CI-only scope at ae86126. I found no new blocking issue in the reviewed diff and surrounding helpers.

Validation performed with Node 24.14.1 / pnpm 11.1.1:

  • pnpm --filter @repo/ci-scripts exec vitest run: 94 tests passed, including the 31 PR-size tests.
  • pnpm --filter @repo/ci-scripts run typecheck: passed.
  • Exercised the actual comment orchestrator with intercepted HTTP responses: creation, paginated lookup/update, malformed measurement fallback, missing PR payload, and API-error handling passed. These were offline checks, not live comment-write tests.
  • Reconciled the current PR files API against the local three-dot diff, then checked that the existing size-comment table matches the current renderer.
  • Read the workflow, default-branch setup path, existing review replies, and the upstream v15.0.0 Total-row renderer.

CI at review time: Lint, Typecheck, Dead-Code, and Measure succeeded; the full Test job is still running. Comment failed at Post size comment with exit code 1. The checked default-branch package does not yet define pr-size-comment, consistent with the documented bootstrap limitation; this review does not treat the writer as CI-verified.

Acknowledged deferred scope: BOTS-138 (workflow trust boundary) and BOTS-139 (base-only updates can leave the comment stale), both read in Linear and left as follow-ups rather than expanding this PR. The private-repository fork-policy probe returned HTTP 422 because this repository is public; it supplied no additional policy evidence.

After merge, complete the stated real-CI create/update-in-place smoke check on a subsequent PR, and let the full Test job finish before merging. No repository changes or merge performed.

@haydenshively
haydenshively merged commit 50cc7d1 into main Sep 15, 2026
4 of 6 checks passed
@haydenshively
haydenshively deleted the ci/pr-size-comment branch September 15, 2026 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant