← all branches

feat/ci-speed

needs attentionviewing older commit
f7dbbf7 · fullpre-PRreviewed 2026-08-07 02:01 UTC0H · 5M · 7L · 4I
The branch
Purpose
Cut PR gate latency — the dominant cost was 287s of Vercel build polling inside a job that runs 21s of actual tests
Goal
Reduce warm-path E2E gate time from ~6 min to ~1.5 min by triggering on deployment_status (Vercel READY) instead of pull_request (races the build); add Turbo Remote Cache to cut typecheck/lint from ~215s cold to ~seconds on cache hit
Sub-goals
  • SG-1: Switch e2e.yml trigger to deployment_status with correct gate logic (PR resolution, supersession, branch-name filter)
  • SG-2: Add TURBO_TOKEN + TURBO_TEAM to pr-checks.yml validate job for Vercel remote cache
  • SG-3: Update e2e-testing.md to document the new trigger mechanics and required-check posture
  • SG-4: Add CI/CD diagnosis report documenting measured bottlenecks and recommended sequence
The changes (whole branch)
What
e2e.yml trigger changed from pull_request to deployment_status; gate step rewritten to resolve PR/branch from SHA via GitHub API; concurrency group keyed on SHA; pr-checks.yml validate job gets TURBO_TOKEN/TURBO_TEAM env; e2e-testing.md updated; docs/ci-cd-diagnosis.html added
Why
81% of the E2E job (287s of 354s) was curl-polling for Vercel to finish building. Starting from a READY deployment eliminates that wait. Turbo Remote Cache eliminates redundant typecheck/lint recomputation across CI runs.
Areas
.github/workflows/e2e.yml+11155.github/workflows/pr-checks.yml+120.claude/rules/e2e-testing.md+2919docs/ci-cd-diagnosis.html+1270
Blast
4 files, +279/−74 lines; CI/CD infrastructure only — no domain code, no migrations, no API surface changes
ci-infrastructure github-actions no-domain-impact
github-ci· GitHub API unavailable in this runner context (401); no CI signal fetchedcoderabbit· No .coderabbit.yaml in repo

Findings · 16

correctness3

medium

Gate 'branch' output missing when PLATFORM_PREVIEW_URL override + non-matching branch name

.github/workflows/e2e.yml

When PLATFORM_PREVIEW_URL is set as a repo var but HEAD_REF does not match feat|fix|hotfix|feature, the gate emits run=true but never emits branch=$HEAD_REF. The 'Resolve preview URLs' step then does SLUG=$(echo "${{ steps.gate.outputs.branch }}") with an empty value, producing a malformed alias URL like https://batu-codebase-platform-git--batu-energy.vercel.app (double dash). The E2E smoke would target a non-existent host. Fix: also emit `echo "branch=$HEAD_REF" >> "$GITHUB_OUTPUT"` in that else-with-override branch.

low

Duplicate lines in workflow comment block

.github/workflows/e2e.yml

The diff shows the lines '- The branch's Supabase preview DB is seeded by preview-provision.yml, so the' and 'seeded user (default diego@batuenergy.com / BatuPreview2024!) can log in.' each appearing twice in the comment header — a copy-paste merge artifact. Does not affect runtime but clutters the canonical source.

low

Cross-push supersession relies on GitHub API currency

.github/workflows/e2e.yml

For rapid successive pushes (different SHAs), the concurrency group (keyed on SHA) does NOT cancel — the gate's HEAD_SHA != SHA check is the only guard. If the GitHub commits API is stale (edge case), an older SHA's run could slip through and test a superseded commit. Low probability but worth noting alongside the concurrency comment.

security3

medium

VERCEL_TOKEN reused as TURBO_TOKEN — overprivileged cache credential

.github/workflows/pr-checks.yml

TURBO_TOKEN is set to ${{ secrets.VERCEL_TOKEN }}, which carries deploy, env-var sync, and project promotion privileges across all Vercel projects. A Turbo cache token only needs remote-cache read/write scope. Using the deploy token means a cache-poisoning incident or a token leak from a build log also exposes full Vercel deploy access. Preferred path: generate a scoped token via Vercel dashboard → team settings → Remote Cache, store as TURBO_TOKEN secret, and reference that. The comment documents the intentional reuse but 'avoids a new secret' is a weak justification for carrying deploy authority into the validate job.

low

Verify Vercel is NOT configured to build fork PRs

.github/workflows/e2e.yml

deployment_status fires for any deployment attached to the repo. If Vercel is configured to build fork PRs, a fork actor could cause a deployment_status success event and the workflow would check out and execute that SHA's workflow code. Confirm batu-codebase-platform does not build fork PRs in the Vercel project settings.

info

Branch name written to GITHUB_OUTPUT without value quoting

.github/workflows/e2e.yml

echo "branch=$HEAD_REF" >> "$GITHUB_OUTPUT" does not quote the value side. A branch name containing a newline or GITHUB_OUTPUT delimiter could corrupt the output file. GitHub rejects most pathological names, so this is very low likelihood, but using the heredoc form (echo "branch<<EOF\n$HEAD_REF\nEOF") is the hardened pattern.

conventions2

low

loops.md still says 'e2e testing' is a required check

.claude/rules/loops.md

loops.md Safety model § point 2 references 'the `e2e testing` required check'. The diff updates e2e-testing.md to document that the check is currently NOT required, but loops.md was not updated. The two rule files are now inconsistent. A reader of loops.md will believe enforcement is in place when it is not.

info

migration-lint absent from summary.needs (pre-existing)

.github/workflows/pr-checks.yml

The summary job's needs list omits migration-lint, so a failing migration-lint run does not block All Checks Passed. Pre-existing issue not introduced by this PR; will need fixing when MON-48 promotes migration-lint to blocking.

tests4

medium

deployment_status trigger is inert on this branch — the new code path ships unvalidated

.github/workflows/e2e.yml

GitHub only fires deployment_status for the workflow file on the default branch (main). The branch copy of e2e.yml is completely inert. This means the gate step logic (jq filter, SHA comparison, branch-name regex, output wiring) cannot be exercised on this PR itself. The functional bug in finding #1 is an example of exactly what this blind spot hides. The workflow header correctly documents this limitation, but it means the change ships with zero live CI runs validating the new code path. Manual testing via dispatch or a post-merge monitoring window is recommended.

medium

Non-preview branches produce no check run — latent re-enablement hazard

.github/workflows/e2e.yml

Under pull_request, docs/chore branches got a skip→pass run that satisfied a required-check gate. Under deployment_status they produce NO run. The workflow header and e2e-testing.md document this correctly and note the check is NOT currently required. The risk: if a future contributor re-enables 'e2e testing' as required without first reading the caveat and adding a pull_request pass-through, every docs/chore PR blocks forever. Adding a commented-out pass-through skeleton would make the safe re-enablement path structurally obvious.

low

180s alias-flip deadline may be too tight for Vercel propagation lag

.github/workflows/e2e.yml

The deployment_status event fires when the build finishes, but Vercel's branch alias update is a separate async step. Under load, alias propagation can lag by minutes. The old 600s budget absorbed this; 180s may not. If the alias flip takes >180s the readiness check fails and E2E aborts, producing a flaky gate. Monitoring actual alias-flip latency on a few post-merge runs before accepting this as the new budget is advisable.

info

Gate skip reports as green 'e2e testing' check

.github/workflows/e2e.yml

When the gate skips (no PR, superseded, non-preview), the job exits 0 and GitHub shows a green 'e2e testing' check. This could be misread as 'tests ran and passed'. Intentional design given the check is not currently required, but worth noting.

improvement4

medium

Gate picks first open PR arbitrarily when a SHA has multiple open PRs to main

.github/workflows/e2e.yml

The jq expression `[.[] | select(.state=="open" and .base.ref=="main")][0] // empty` silently picks the first result when a commit SHA appears on more than one open PR targeting main (cherry-pick branches, rebase collisions). Sort order is not a documented API guarantee. A safer policy: if `length > 1`, emit a notice and skip (or pick by `.updated_at` descending). Silent first-pick makes the behavior nondeterministic and hard to debug.

low

docs/ci-cd-diagnosis.html is a transient diagnostic committed to source

docs/ci-cd-diagnosis.html

The file is a point-in-time measurement snapshot (timings, waterfall, findings). It goes stale the moment the pipeline improves and will require a follow-up cleanup commit. Diagnostic artifacts belong in a PR description, GitHub wiki, or gist — not in docs/ alongside forward-looking strategy docs.

low

Slug derivation may drift from preview-provision.yml transform

.github/workflows/e2e.yml

The slug is derived with `sed 's/[/]/-/g' | tr '[:upper:]' '[:lower:]'`. If preview-provision.yml uses a slightly different transform for edge-case branch names, the constructed alias URL will 404 and manifest as a misleading readiness timeout rather than a clear URL mismatch error. A shared composite action or a canonical slug script referenced by both workflows would eliminate this latent drift.

low

wait-on 5-minute timeout for web is too generous post-trigger-change

.github/workflows/e2e.yml

Under deployment_status the platform deployment is already READY. The web project deploys in parallel and typically finishes first. The 300 000 ms (5 min) wait-on is a residual of the old pull_request timing where web might still be building. A 90–120s timeout would fail faster on a genuine web failure and reduce the job's worst-case tail.

History · 3 commits

  1. 167f02aneeds attentionincremental1H · 2M · 2L2026-08-12 17:47
  2. ca9f915needs attentionfull1H · 4M · 4L2026-08-11 19:27
  3. f7dbbf7needs attentionfull0H · 5M · 7L2026-08-07 02:01current