Skip to content

ci: split benchmarks switchboard release flow - #140

Merged
borgesius merged 1 commit into
mainfrom
codex/benchmarks-switchboard-release-flow
Jun 19, 2026
Merged

ci: split benchmarks switchboard release flow#140
borgesius merged 1 commit into
mainfrom
codex/benchmarks-switchboard-release-flow

Conversation

@borgesius

@borgesius borgesius commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • make the existing runner/API CI reusable by Switchboard
  • add a separate reusable web CI adapter with local OpenAPI schema generation for codegen
  • replace push-to-main runner/API release with runner-release.yml repository_dispatch
  • add web-release.yml for Vercel web production promotion and the production-web marker branch
  • fix two existing web lint warnings so the new web adapter can run with --max-warnings 0
  • declare the web packageManager and set up pnpm before node cache restore on fresh GitHub runners
  • keep the production-runner idempotency fetch authenticated so no-op releases can skip correctly
  • remove shared runner CI concurrency so direct PR CI and the Switchboard-called adapter do not cancel each other during rollout

Validation

  • actionlint
  • web: generated OpenAPI schema locally, then pnpm codegen, pnpm lint, pnpm test (32 passed), pnpm build
  • web package setup: pnpm install --frozen-lockfile
  • runner/API: uv sync --frozen --dev, uv run ruff check ., uv run ruff format --check ., uv run mypy --strict src, uv run pytest -q --disable-socket --allow-unix-socket --allow-hosts=127.0.0.1,::1 (582 passed, 1 skipped)

Rollout note

Merge before the ci-cd-switchboard config PR that starts dispatching switchboard_benchmarks_web_release and switchboard_benchmarks_runner_release. Until that config is on Switchboard main, the new gate conservatively falls back to running both local adapters if planning cannot run; once switchboard#150 lands, the normal selected-check path takes over.

Greptile Summary

This PR splits the monolithic push-to-main release pipeline into two independently triggered release workflows (runner-release.yml and web-release.yml), each driven by repository_dispatch from a Switchboard config, and introduces a new switchboard.yml orchestrator that selectively runs only the relevant CI adapters (ci.yml or web-ci.yml) based on changed files. Two frontend lint warnings are also fixed to satisfy --max-warnings 0.

  • switchboard.yml plans which CI adapters to invoke per PR using changed-file selectors, falls back conservatively to running both if Switchboard cannot plan, and enforces a hard gate job that fails the PR if any selected adapter fails.
  • runner-release.yml adds idempotency (skip if production-runner already points to the target SHA), Docker image builds, infra dispatch + run-watching, and a marker fast-forward — replacing the old release.yml.
  • web-release.yml adds Vercel production promotion with an identical idempotency gate via a production-web marker branch, and web-ci.yml adds local OpenAPI schema generation for type-safe codegen in CI.

Confidence Score: 5/5

Safe to merge — all workflow logic is well-guarded, fallback paths are explicit, and no existing release or CI gate is removed without a replacement.

The new workflows are carefully structured: release idempotency is gated on marker-branch comparisons, Switchboard failures fall back to running the full suite, and the gate job correctly enforces selected-adapter results. The only new issue found is a benign race window between the background HTTP server start and codegen in web-ci.yml — unlikely to fire in practice and non-blocking to merge.

.github/workflows/runner-release.yml — the context job idempotency skip path is worth verifying once merged with a live dispatch to confirm the skip logic behaves as expected.

Important Files Changed

Filename Overview
.github/workflows/ci.yml Made reusable via workflow_call/workflow_dispatch with a ref input; removed concurrency group (now managed by switchboard.yml caller); added pull_request guard on methodology marker check
.github/workflows/release.yml Deleted — replaced by runner-release.yml (repository_dispatch triggered) and web-release.yml
.github/workflows/runner-release.yml New release workflow triggered by repository_dispatch from Switchboard; adds idempotency skip via production-runner marker, infra dispatch with run-watching, and marker fast-forward
.github/workflows/switchboard.yml New orchestrator workflow — plans which CI adapters to run based on changed files, falls back to running both if planning fails, and enforces a gate job that fails on any selected adapter failure
.github/workflows/web-ci.yml New reusable web CI workflow — sets up pnpm before Node.js cache restore, generates OpenAPI schema locally via a background HTTP server, then runs codegen/lint/test/build
.github/workflows/web-release.yml New web production release workflow triggered by repository_dispatch; uses app token for authenticated checkout, skips if production-web already matches, runs codegen + vercel build/promote, and fast-forwards production-web marker
web/components/charts/d3/HeatmapPlot.tsx Wraps handleSort in useCallback with correct deps and adds it to the useMemo dependency array, fixing a lint warning
web/components/dashboard/KeyMetrics.tsx Replaces array-index key with metric.label for stable React list keys, fixing a lint warning
web/package.json Adds packageManager field (pnpm@10.33.0) so pnpm/action-setup can auto-detect the version without an explicit packageManager input

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant GH as GitHub Event
    participant SW as switchboard.yml
    participant RCI as ci.yml
    participant WCI as web-ci.yml
    participant SG as switchboard_gate
    participant RR as runner-release.yml
    participant WR as web-release.yml
    participant INFRA as benchmark-infra
    participant VERCEL as Vercel

    GH->>SW: pull_request / merge_group
    SW->>SW: Resolve changed files
    SW->>SW: Plan Switchboard checks
    SW->>SW: Resolve selected adapters
    alt "run_runner_ci == true"
        SW->>RCI: workflow_call(ref)
        RCI->>RCI: uv sync / ruff / mypy / pytest
    end
    alt "run_web_ci == true"
        SW->>WCI: workflow_call(ref)
        WCI->>WCI: pnpm codegen / lint / test / build
    end
    SW->>SG: check adapter results

    GH->>RR: repository_dispatch
    RR->>RR: context (resolve ref / skip check)
    RR->>RR: build_and_push (Docker to AR)
    RR->>INFRA: dispatch image-bump
    INFRA-->>RR: watch run until complete
    RR->>RR: fast-forward production-runner

    GH->>WR: repository_dispatch
    WR->>WR: context (resolve ref / skip check)
    WR->>WR: pnpm codegen / vercel build
    WR->>VERCEL: deploy --prebuilt --prod
    VERCEL-->>WR: deployment_url
    WR->>VERCEL: promote deployment
    WR->>WR: fast-forward production-web
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant GH as GitHub Event
    participant SW as switchboard.yml
    participant RCI as ci.yml
    participant WCI as web-ci.yml
    participant SG as switchboard_gate
    participant RR as runner-release.yml
    participant WR as web-release.yml
    participant INFRA as benchmark-infra
    participant VERCEL as Vercel

    GH->>SW: pull_request / merge_group
    SW->>SW: Resolve changed files
    SW->>SW: Plan Switchboard checks
    SW->>SW: Resolve selected adapters
    alt "run_runner_ci == true"
        SW->>RCI: workflow_call(ref)
        RCI->>RCI: uv sync / ruff / mypy / pytest
    end
    alt "run_web_ci == true"
        SW->>WCI: workflow_call(ref)
        WCI->>WCI: pnpm codegen / lint / test / build
    end
    SW->>SG: check adapter results

    GH->>RR: repository_dispatch
    RR->>RR: context (resolve ref / skip check)
    RR->>RR: build_and_push (Docker to AR)
    RR->>INFRA: dispatch image-bump
    INFRA-->>RR: watch run until complete
    RR->>RR: fast-forward production-runner

    GH->>WR: repository_dispatch
    WR->>WR: context (resolve ref / skip check)
    WR->>WR: pnpm codegen / vercel build
    WR->>VERCEL: deploy --prebuilt --prod
    VERCEL-->>WR: deployment_url
    WR->>VERCEL: promote deployment
    WR->>WR: fast-forward production-web
Loading

Reviews (2): Last reviewed commit: "ci: split benchmarks switchboard release..." | Re-trigger Greptile

@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
benchmarks Ready Ready Preview, Comment Jun 18, 2026 10:45pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@borgesius, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 18 minutes and 58 seconds. Learn how PR review limits work.

To continue reviewing without waiting, enable usage-based billing in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 27599050-1652-4549-9354-8ef1e001fe6c

📥 Commits

Reviewing files that changed from the base of the PR and between 53470c7 and cdc250a.

📒 Files selected for processing (9)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .github/workflows/runner-release.yml
  • .github/workflows/switchboard.yml
  • .github/workflows/web-ci.yml
  • .github/workflows/web-release.yml
  • web/components/charts/d3/HeatmapPlot.tsx
  • web/components/dashboard/KeyMetrics.tsx
  • web/package.json
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/benchmarks-switchboard-release-flow

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment on lines +52 to +71
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{ steps.input.outputs.deploy_ref }}
fetch-depth: 0
persist-credentials: false

- name: Resolve image tags
id: context
run: |
set -euo pipefail
deploy_sha="$(git rev-parse HEAD)"
runner_image="us-east1-docker.pkg.dev/coval-benchmarks-prod/runner/coval-bench-runner:${deploy_sha}"
api_image="us-east1-docker.pkg.dev/coval-benchmarks-prod/runner/coval-bench-api:${deploy_sha}"

git fetch origin production-runner:refs/remotes/origin/production-runner 2>/dev/null || true
skip=false
if git rev-parse --verify origin/production-runner >/dev/null 2>&1 && [ "$deploy_sha" = "$(git rev-parse origin/production-runner)" ]; then
skip=true
fi

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.

P2 Skip idempotency check never fires

The context job checks out with persist-credentials: false, then immediately runs git fetch origin production-runner ... 2>/dev/null || true. On a private repository the fetch needs git credentials — which persist-credentials: false deliberately removes — so it silently fails every time. skip therefore stays false on every run and the early-exit optimization is permanently bypassed.

Compare web-release.yml lines 70-88: the equivalent job there uses token: ${{ steps.app_token.outputs.token }} (without persist-credentials: false), so its skip check works as intended. The runner-release context job needs the same treatment — either generate an app token before checkout, or drop persist-credentials: false here.

Comment thread .github/workflows/ci.yml
Comment on lines 150 to 155
name: Methodology marker check
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.event_name == 'pull_request'
# Advisory only: never let this job block a PR, even on an unexpected error.
continue-on-error: true

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.

P2 Methodology marker check silently skips in Switchboard PR flow

The new if: github.event_name == 'pull_request' guard is appropriate to prevent this advisory job from running in release pipelines, but it also prevents it from running when ci.yml is invoked from switchboard.yml via workflow_call. In that context github.event_name is "workflow_call", not "pull_request", so the check is always skipped for every PR that goes through Switchboard. The check is continue-on-error: true so this isn't blocking, but the behavioral change may be unintentional — the check ran on all PRs before this PR.

@borgesius

Copy link
Copy Markdown
Contributor Author

Addressed the reviewbot idempotency finding in the latest push: the runner-release context checkout now keeps credentials so the production-runner fetch can work on the private repo and no-op releases can skip correctly. Also fixed the fresh-runner pnpm setup issue by declaring packageManager and setting up pnpm before node cache restore.

@borgesius
borgesius force-pushed the codex/benchmarks-switchboard-release-flow branch from ebb0eea to cdc250a Compare June 18, 2026 22:45
@borgesius

Copy link
Copy Markdown
Contributor Author

One more rollout fix after the latest CI pass: removed the shared concurrency block from the reusable runner/API CI workflow, because the direct PR CI and Switchboard-called adapter were canceling each other during the transition. Same rollout-race shape as the benchmark-infra Terraform plan fix.

@borgesius
borgesius merged commit 4f46991 into main Jun 19, 2026
12 checks passed
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