Skip to content

Require hosted CI for generator PRs#4149

Merged
justin808 merged 3 commits into
mainfrom
jg-codex/require-hosted-ci-for-generators
Jun 21, 2026
Merged

Require hosted CI for generator PRs#4149
justin808 merged 3 commits into
mainfrom
jg-codex/require-hosted-ci-for-generators

Conversation

@justin808

@justin808 justin808 commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

Add a lightweight ci-required guard so ordinary pull requests that touch generator-sensitive paths cannot pass the required gate until hosted CI is requested.

Why

PR #4130 changed generator path behavior and had ci-required / required-pr-gate green, but Rspec test for gem / rspec-package-tests was skipped on the PR. The generator shard then failed only after merge to main.

script/ci-changes-detector already knows generator changes need generator/Ruby coverage. This PR makes the fast required gate enforce the missing process step: request hosted CI before merging generator-sensitive PRs.

Implementation

  • Adds script/ci-required-hosted-gate and a shell test harness.
  • Updates .github/workflows/ci-required.yml to:
    • read hosted-CI label/release/merge-queue state through .github/actions/hosted-ci-selectors
    • keep running the existing change detector
    • fail ordinary pull requests when run_generators=true and hosted CI is not requested
  • Documents the policy in AGENTS.md, .github/read-me.md, and internal/contributor-info/ci-optimization.md.

Validation

  • bash script/ci-required-hosted-gate-test.bash - 6 tests passed
  • bash -n script/ci-required-hosted-gate script/ci-required-hosted-gate-test.bash script/ci-changes-detector - passed
  • ruby -e "require 'yaml'; Dir['.github/workflows/*.{yml,yaml}'].sort.each { |f| YAML.safe_load_file(f, permitted_classes: [], aliases: false) }; puts 'workflow YAML OK'" - passed
  • bash script/ci-changes-detector-test.bash - 49 tests passed
  • actionlint .github/workflows/ci-required.yml - passed
  • pnpm dlx prettier@3.6.2 --check AGENTS.md .github/read-me.md internal/contributor-info/ci-optimization.md .github/workflows/ci-required.yml - passed
  • pnpm install --frozen-lockfile - passed; no tracked install churn
  • pnpm start format.listDifferent - passed after installing workspace dependencies
  • pre-commit hook - passed trailing-newlines, markdown-links, prettier
  • pre-push hook - passed branch-lint, markdown-links

Process Gap Disposition

Mechanism target: script.

Motivating miss: generator-sensitive PRs could merge after only ci-required / required-pr-gate, even when the hosted generator shard that would catch order/state failures was skipped.

Replay evidence: #4130 had a green required gate and skipped rspec-package-tests; post-merge main failed in the generator shard. #4147 fixed the spec failure. This PR blocks the equivalent future PR state before merge.

Non-goal: require full hosted CI for every PR. The guard only applies when change detection marks generator coverage relevant.

Labels

Labels: ready-for-hosted-ci, force-full-hosted-ci - changes GitHub Actions required-gate behavior, so path/hosted-CI selection itself is part of the risk.

Follow-up

Because this changes .github/workflows/ci-required.yml, follow-up issue #4150 was created to exercise the post-merge behavior: #4150.


Note

Medium Risk
Changes branch-protection behavior and CI routing for generator PRs; incorrect gating could block merges or allow skips, though behavior is covered by shell tests and documented exceptions for merge queue/release targets.

Overview
Ordinary PRs that touch generator-sensitive paths can no longer pass ci-required / required-pr-gate until hosted CI is requested. A new script/ci-required-hosted-gate fails when the event is pull_request, script/ci-changes-detector sets run_generators=true, and hosted-ci-selectors reports hosted CI is not eligible (e.g. no ready-for-hosted-ci). Merge queue and other non-PR paths are unchanged.

ci-required.yml now runs hosted-ci-selectors, captures detector outputs on the changes step, invokes the gate, adds issues: read, validates the new script, and runs ci-required-hosted-gate-test.bash in the required job.

Contributor docs (AGENTS.md, .github/read-me.md, ci-optimization.md) describe the generator exception. Pro node renderer: incrementalHtmlStreaming.test.ts updates the expected async-prop error message string only.

Reviewed by Cursor Bugbot for commit 7228de8. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Chores
    • Enhanced the CI required gate to block generator-sensitive pull requests until hosted CI is explicitly requested.
    • Updated the CI workflow to run the hosted-CI eligibility checks in the correct sequence and improved shell validation.
    • Expanded workflow permissions to include reading issues metadata.
  • Documentation
    • Updated CI contributor guidance to document hosted CI request requirements for generator-sensitive pull requests.
  • Tests
    • Added a Bash gate and a multi-scenario test harness to verify the gating behavior across supported event types.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Introduces script/ci-required-hosted-gate, a Bash script that exits 1 on pull_request events when RUN_GENERATORS=true but hosted CI is not requested. A companion test harness validates multiple event scenarios. The ci-required.yml workflow gains issues: read permission, syntax-checks the new script, runs the test harness and hosted-ci-selectors action, and enforces the gate. Three documentation files are updated to describe the new policy. An unrelated test assertion is updated for async prop error messaging.

Changes

Generator-sensitive hosted CI gate

Layer / File(s) Summary
Gate script and test harness
script/ci-required-hosted-gate, script/ci-required-hosted-gate-test.bash
script/ci-required-hosted-gate reads GITHUB_EVENT_NAME, RUN_GENERATORS, and SHOULD_RUN_HOSTED_CI; on pull_request events it exits 1 with a stderr message unless both generator and hosted-CI flags are true, otherwise exits 0. The test harness runs named scenarios covering PR, merge queue, and unset-event cases and exits non-zero on any failure.
Workflow integration
.github/workflows/ci-required.yml
Adds issues: read permission, extends the bash -n syntax-check loop to include the new gate script, inserts steps to run the test harness and the hosted-ci-selectors action, and adds the enforcement step that passes RUN_GENERATORS and SHOULD_RUN_HOSTED_CI to script/ci-required-hosted-gate.
Policy documentation
AGENTS.md, .github/read-me.md, internal/contributor-info/ci-optimization.md
Documents that generator-sensitive PRs (run_generators=true) fail the required-pr-gate until hosted CI is requested via +ci-run-hosted, bin/request-hosted-ci, or a ready-for-hosted-ci label; notes that merge queue, push-to-main, and release-target runs already satisfy hosted eligibility.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

Suggested labels

enhancement, review-needed, full-ci

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Require hosted CI for generator PRs' directly and clearly summarizes the main change: enforcing hosted CI requirements for pull requests that modify generator-sensitive paths.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg-codex/require-hosted-ci-for-generators

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@justin808

Copy link
Copy Markdown
Member Author

Post-merge workflow exercise follow-up created: #4150

@justin808

Copy link
Copy Markdown
Member Author

+ci-force-full

@github-actions github-actions Bot added force-full-hosted-ci Bypass optimized hosted CI selection and run all hosted suites ready-for-hosted-ci Run optimized hosted GitHub CI for this PR labels Jun 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Force-Full Hosted CI Requested

Triggered 9 workflow(s) for 7b592e6f25ff.
Mode: force-full hosted CI (bypasses optimized change selection).
Added ready-for-hosted-ci and force-full-hosted-ci, so future commits will bypass optimized hosted CI selection until +ci-stop-full is used.

View progress in the Actions tab.

@claude

claude Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Code Review

Summary

This PR adds a lightweight guard to the required CI gate that blocks generator-sensitive PRs from merging until hosted CI is explicitly requested. The approach is clean and targeted: it extends the existing ci-required workflow with a new script plus a test harness, and updates three documentation files to document the new policy.

What works well

  • Minimal blast radius. The gate script is 22 lines, reads only three env vars, and exits immediately when conditions are not met. Easy to reason about.
  • Tests run in the same gate. Running ci-required-hosted-gate-test.bash inside ci-required means a broken gate is caught before it can block or miss PRs.
  • Clear error message. The failure output names both the problem and all remediation paths (+ci-run-hosted, bin/request-hosted-ci, label).
  • issues: read permission is correctly justified. The hosted-ci-selectors action calls github.rest.issues.listLabelsOnIssue(), which is the canonical Octokit endpoint for PR labels and requires issues: read. The scope is appropriate.
  • Step ordering is correct. Gate tests run first (before the gate itself is relied upon), then hosted-ci-selectors is called, then ci-changes-detector, then the gate. This ensures the gate can reference both outputs before executing.

Issues

Test coverage gap – merge queue case is under-specified

Test case 4 passes should_run_hosted_ci="true" for a merge_group event:

run_case "allows merge queue generator checks" 0 "merge_group" "true" "true"

The gate's outer condition is [ "$event_name" = "pull_request" ], so merge queue events pass regardless of should_run_hosted_ci. The test therefore does not exercise the actual protection mechanism — it would still pass with should_run_hosted_ci="false". A companion case with the flag set to false would pin the real behaviour and guard against future refactors that accidentally broaden the outer condition.

Missing test: unknown/empty event name

Scheduled runs, workflow_dispatch, and other events leave GITHUB_EVENT_NAME either unset or set to a non-pull_request value. The gate defaults to event_name="" in that case and passes correctly, but there is no test for this. If a future edit changes the default or the condition, nothing catches the regression.

Minor observations

  • No explicit exit 0. The script falls through to the end of the file on the happy path, which is correct bash behaviour. Not a bug, but an explicit exit 0 at the end would make the intent clearer.
  • Documentation is thorough. All three doc files (AGENTS.md, .github/read-me.md, internal/contributor-info/ci-optimization.md) are consistent with each other and with the implementation.
  • bash -n syntax-check coverage. ci-required-hosted-gate is added to the existing syntax-check loop and ci-required-hosted-gate-test.bash is included in the same loop, so both are syntax-checked on every run.

Verdict

The logic is sound and the implementation is clean. The two test-coverage gaps above are worth addressing — especially the merge queue case, which currently does not exercise what it appears to test — but neither is a blocking correctness issue. Overall this is a solid, low-risk addition that directly addresses the gap described in the PR.

Comment on lines +80 to +87
"pull_request" \
"false" \
"false"

run_case \
"allows merge queue generator checks" \
0 \
"merge_group" \

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.

The merge queue test passes should_run_hosted_ci="true", but the gate's outer condition is [ "$event_name" = "pull_request" ], so the should_run_hosted_ci value is never read for non-PR events. This test passes even if you change the last argument to "false", meaning it doesn't exercise what it appears to document.

Consider adding a companion case that makes the real invariant explicit:

Suggested change
"pull_request" \
"false" \
"false"
run_case \
"allows merge queue generator checks" \
0 \
"merge_group" \
run_case \
"allows merge queue generator checks" \
0 \
"merge_group" \
"true" \
"true"
run_case \
"allows merge queue even without hosted CI flag (event_name guard is sufficient)" \
0 \
"merge_group" \
"true" \
"false"

fi

echo
echo "$TESTS_RUN tests passed"

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.

There's no test for an empty or unrecognised GITHUB_EVENT_NAME (e.g. workflow_dispatch, schedule, or a locally sourced run where the var is unset). The gate defaults event_name to "" and correctly passes, but that path has no coverage. A case like:

run_case \
  "allows unrecognised event names (e.g. workflow_dispatch)" \
  0 \
  "workflow_dispatch" \
  "true" \
  "false"

would pin this and catch any future edit that widens the outer if condition.

Then wait for the hosted generator checks before merging.
MSG
exit 1
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.

The file ends without an explicit exit 0. This is valid bash — the implicit exit code is the last command's result, and here the heredoc cat in the failure branch returns 0, so non-error paths are fine. Adding exit 0 as the final line would make the intent self-documenting and protect against a future edit that appends a failing command above this point.

Suggested change
fi
exit 1
fi
exit 0

@cursor

cursor Bot commented Jun 20, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_3146b5f2-2272-4778-9131-4f9063a5e8c3)

@justin808 justin808 marked this pull request as ready for review June 21, 2026 01:12
@justin808

Copy link
Copy Markdown
Member Author

+ci-force-full

@github-actions

Copy link
Copy Markdown
Contributor

Force-Full Hosted CI Requested

Triggered 9 workflow(s) for 4bb842899887.
Mode: force-full hosted CI (bypasses optimized change selection).
Added ready-for-hosted-ci and force-full-hosted-ci, so future commits will bypass optimized hosted CI selection until +ci-stop-full is used.

View progress in the Actions tab.

@justin808 justin808 force-pushed the jg-codex/require-hosted-ci-for-generators branch from 4bb8428 to d7e279c Compare June 21, 2026 01:14

@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: 4bb8428998

ℹ️ 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".

Generator changes require hosted CI before merge.

This PR changes generator-sensitive paths, but hosted CI has not been requested.
Comment +ci-run-hosted on the PR, or add the ready-for-hosted-ci label with a maintainer/user token.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Ensure +ci-run-hosted reruns the required gate

For generator PRs that use the documented +ci-run-hosted path, this instruction does not actually unblock the failed required check: the comment workflow adds ready-for-hosted-ci with GITHUB_TOKEN, and the repo docs note that such label writes do not start new pull_request workflow runs, while triggerHostedCi dispatches only the hosted workflows, not ci-required.yml. In that scenario the last ci-required / required-pr-gate run remains failed until someone pushes, manually reruns/dispatches the gate, or adds the label with a user token, so the primary requested workflow leaves branch protection blocked.

Useful? React with 👍 / 👎.

@claude

claude Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Code Review

Overview

This PR closes a real process gap: generator-touching PRs could previously merge after only the lightweight ci-required gate, while the hosted generator shard stayed skipped. The fix is well-targeted — a small gate script, shell tests, one new workflow step, and documentation updates across the relevant files.

What's Well Done

  • Minimal blast radius. The gate script is 24 lines and does exactly one thing. It doesn't pull in new dependencies, doesn't touch existing logic, and has a clear exit contract.
  • Fail-open on missing outputs. When steps.changes.outputs.run_generators is empty (e.g. if the detector step had an issue), the env var falls back to false via ${RUN_GENERATORS:-false}, so the gate won't falsely block PRs.
  • Defense-in-depth on event name. Even though should_run_hosted_ci is already true for non-pull_request events (the hosted-ci-selectors action sets it that way), the explicit event_name = "pull_request" check in the gate script is still correct: it ensures the script behaves safely when run locally or in any non-GitHub context where SHOULD_RUN_HOSTED_CI isn't set.
  • issues: read is the right permission. The hosted-ci-selectors action calls github.rest.issues.listLabelsOnIssue which requires this permission. The addition is minimal and scoped to the existing ci-required workflow.
  • Self-testing. Running ci-required-hosted-gate-test.bash inside the required gate means a broken gate script fails CI before it can be merged — nice.

Issues

Test count mismatch in PR description. The Validation section says "4 tests passed" but the test harness actually has 6 run_case calls. Minor, but could confuse someone auditing the validation evidence.

Redundant exit 0. The final exit 0 in script/ci-required-hosted-gate is unreachable given set -euo pipefail and the early exit 1 path — bash falls off the end of a script with exit code 0 anyway. Not a bug, but it adds a line that might imply the script has more paths than it does.

Security

No concerns. All env vars consumed by the gate script are set by the trusted GitHub Actions environment or the workflow's own env: block. No user-controlled input is used in shell expansion — all values are compared, not executed.

Verdict

Solid, well-scoped fix. The two items above are both minor. Approving.

fi

echo
echo "$TESTS_RUN tests passed"

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.

The PR description's Validation section says "4 tests passed", but there are 6 run_case calls in this file. The code is correct — just a stale count in the PR body.

MSG
exit 1
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.

This exit 0 is unreachable — with set -euo pipefail a bash script exits 0 when it falls off the end normally. Not a bug, but removing it would avoid implying there's a third exit path here.

@claude

claude Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Code Review — PR #4149: Require hosted CI for generator PRs

Overall: Well-targeted fix that closes a real process gap (see #4130). The gate script is small, deterministic, and correctly scoped to only pull_request events, leaving merge queue and push-to-main unaffected. Logic is sound and documentation updates are thorough.

Correctness

  • ci-changes-detector writes run_generators=true/false to $GITHUB_OUTPUT; the gate reads RUN_GENERATORS from the workflow env — the steps.changes.outputs.run_generators wiring is correct.
  • hosted-ci-selectors sets should_run_hosted_ci via core.setOutput(name, value ? 'true' : 'false'), so the string 'true' comparison in the gate is correct.
  • issues: read is the right permission for github.rest.issues.listLabelsOnIssue used by the action.
  • Step ordering (selectors → detector → gate) is correct; all inputs are available before the gate runs.

Minor Issues

  1. PR description says "4 tests passed" but the test file has 6 run_case invocations. The description appears to have been written before the two merge-queue cases were added. Low stakes but worth correcting to avoid confusion.

  2. exit 0 at end of ci-required-hosted-gate is redundant — with set -euo pipefail, reaching the end of the script already means success. Harmless but adds noise.

  3. Test harness uses set -uo pipefail (no -e) while the gate itself uses set -euo pipefail. The intentional set +e / set -e dance inside run_case is fine, but any error outside run_case (e.g., a bad path expand) would silently continue rather than abort. Consider set -euo pipefail at the top too, since the local set +e / set -e still handles the gate invocation correctly.

  4. No explicit push or workflow_dispatch test case. The empty-event-name case covers the "non-PR → pass" path, but a named case (e.g. push with run_generators=true) would make the intent explicit and guard against future edits that add event-specific branches.

Not Issues (confirming correctness)

  • The "allows merge queue generator checks even without hosted PR state" test correctly exercises the gate's own logic: it only checks event_name = pull_request, so the should_run_hosted_ci value is irrelevant for merge_group. In practice hosted-ci-selectors returns should_run_hosted_ci=true for merge_group anyway, but testing the gate in isolation with false is valid.
  • The concurrency cancel-in-progress: true still applies and is appropriate since a re-label triggers the workflow and should cancel an inflight run.

MSG
exit 1
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.

Redundant with set -euo pipefail — reaching this line already means success. Safe to remove.

Suggested change

#!/usr/bin/env bash
# Test harness for script/ci-required-hosted-gate.

set -uo pipefail

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.

Missing -e compared to the gate script's set -euo pipefail. Any error outside of a run_case block (e.g. a bad path substitution) will silently continue instead of aborting the test run. The local set +e / set -e inside run_case still handles the gate invocation correctly even with -e at the top level.

Suggested change
set -uo pipefail
set -euo pipefail

@greptile-apps

greptile-apps Bot commented Jun 21, 2026

Copy link
Copy Markdown

Greptile Summary

Closes the gap where a generator-sensitive PR could pass the required branch-protection gate (ci-required / required-pr-gate) while the hosted generator shard stayed skipped, as happened with #4130. The new script/ci-required-hosted-gate exits non-zero on pull_request events when run_generators=true and should_run_hosted_ci is not true, then the workflow wires the outputs of the existing hosted-ci-selectors action and ci-changes-detector into that gate.

  • script/ci-required-hosted-gate — 24-line bash script with safe :- defaults; merge-queue, push, and workflow-dispatch events are unaffected because the block only fires when GITHUB_EVENT_NAME=pull_request.
  • ci-required.yml — adds issues: read (required for label fetching inside hosted-ci-selectors), step IDs for hosted-ci and changes, a new test-harness step, and the enforcement step consuming both outputs.
  • Six-case test harness validates all meaningful combinations: blocking, label-granted pass, ordinary PR, merge-queue with and without should_run_hosted_ci, and empty event name; documentation updated in three places.

Confidence Score: 4/5

Safe to merge; the gate script is minimal and its worst-case failure mode is blocking a PR that should be allowed, not allowing one that should be blocked.

The gate logic is correct and well-tested across six cases. The issues: read permission addition is the right fix for label fetching inside hosted-ci-selectors. Step ordering in the workflow (selectors → detector → enforcement) is valid, and all output references match the IDs assigned. The one area that earns a slight reduction from fully clean is that this directly controls merge eligibility for an entire class of PRs — a mis-wired output or an unexpected output format from ci-changes-detector could silently block or unblock generator PRs — and that behavior can only be fully confirmed post-merge when a real generator PR exercises the live workflow.

.github/workflows/ci-required.yml deserves a second look to confirm the steps.changes.outputs.run_generators and steps.hosted-ci.outputs.should_run_hosted_ci references resolve correctly in the live Actions context, since output-wiring bugs in composite actions only surface at runtime.

Important Files Changed

Filename Overview
script/ci-required-hosted-gate New guard script that exits 1 on pull_request events when run_generators=true and should_run_hosted_ci≠true; logic is minimal and correct with safe defaults for all env vars.
script/ci-required-hosted-gate-test.bash Six-case test harness for the gate script; covers the blocking case, the label-granted case, ordinary PRs, and merge-queue variants, but the PR description claims only "4 tests passed" — minor stale description, code itself is correct.
.github/workflows/ci-required.yml Adds issues:read permission, wires hosted-ci-selectors and ci-changes-detector steps with IDs, then passes their outputs into the new gate step; step ordering and output references are all correct.
AGENTS.md Documents the new generator-sensitive PR policy inline with the existing CI label guidance; copy is accurate and consistent with implementation.
.github/read-me.md Adds three lines describing the generator-PR stricter rule under the existing hosted-CI docs section; accurate and clear.
internal/contributor-info/ci-optimization.md Adds two paragraphs explaining the generator exception to the lightweight gate and the merge-queue/push-to-main carve-outs; matches implementation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ci-required.yml triggered] --> B{Event type?}
    B -->|pull_request| C[hosted-ci-selectors\nreads ready-for-hosted-ci label\noutputs should_run_hosted_ci]
    B -->|merge_group / workflow_dispatch / push| G[Gate: event_name ≠ pull_request\n→ exit 0 ✅]
    C --> D[ci-changes-detector\noutputs run_generators]
    D --> E{run_generators = true\nAND should_run_hosted_ci ≠ true?}
    E -->|YES| F[exit 1 ❌\nRequired gate fails\nContributor must add ready-for-hosted-ci]
    E -->|NO| H[exit 0 ✅\nRequired gate passes]
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"}}}%%
flowchart TD
    A[ci-required.yml triggered] --> B{Event type?}
    B -->|pull_request| C[hosted-ci-selectors\nreads ready-for-hosted-ci label\noutputs should_run_hosted_ci]
    B -->|merge_group / workflow_dispatch / push| G[Gate: event_name ≠ pull_request\n→ exit 0 ✅]
    C --> D[ci-changes-detector\noutputs run_generators]
    D --> E{run_generators = true\nAND should_run_hosted_ci ≠ true?}
    E -->|YES| F[exit 1 ❌\nRequired gate fails\nContributor must add ready-for-hosted-ci]
    E -->|NO| H[exit 0 ✅\nRequired gate passes]
Loading

Reviews (1): Last reviewed commit: "Cover hosted CI gate edge cases" | Re-trigger Greptile

@claude

claude Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Code Review — PR #4149: Require hosted CI for generator PRs

Overview

Clean, focused change that closes a real gap. PR #4130's post-merge failure in the generator shard is a solid motivating case, and the implementation correctly targets only the lightweight required gate without affecting merge-queue or push-to-main paths.

Correctness

The gate logic in script/ci-required-hosted-gate is correct:

  • Only triggers on pull_request events (merge queue, push, workflow_dispatch all pass through)
  • Relies on SHOULD_RUN_HOSTED_CI from .github/actions/hosted-ci-selectors, which already correctly resolves labels, release targets, and non-PR events
  • The issues: read permission addition is necessary for listLabelsOnIssue inside that action

Issues

Minor — redundant exit 0
The final line of script/ci-required-hosted-gate is unreachable under set -euo pipefail — a script exits 0 after the last statement unless an error triggers the -e trap. No functional impact.

Minor — set -e enabled mid-test-run
script/ci-required-hosted-gate-test.bash starts with set -uo pipefail (no -e). Inside run_case, the sequence is set +e / run gate / set -e. This means exit-on-error is off during the first test but on from the second test onwards for the outer script. Functions like fail() and assert_contains() survive this because they don't produce non-zero exits themselves, but the inconsistency is worth noting. A cleaner pattern is to add -e to the initial set and rely solely on the set +e / set -e guards inside run_case.

Cosmetic — stale test count in PR description
The Validation section says "4 tests passed" but the test file contains 6 test cases. No code issue.

Observation — one test exercises a scenario that can't happen in production
"allows merge queue generator checks even without hosted PR state" passes merge_group + SHOULD_RUN_HOSTED_CI=false. The hosted-ci-selectors action always sets should_run_hosted_ci=true for merge_group events (since eventName !== 'pull_request'), so this combination can't occur in practice. Testing the gate in isolation is fine, but a comment clarifying it's a unit-level isolation case would help future readers.

Positive notes

  • Gate script is small and auditable (set -euo pipefail, single responsibility, clear error message)
  • Documentation updates in AGENTS.md, read-me.md, and ci-optimization.md are consistent and complete
  • Step ordering in the workflow (selectors → changes → gate) is sensible
  • Test harness covers the blocking case, all pass-through cases, and boundary events — good coverage

exit 1
fi

exit 0

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.

Redundant — set -euo pipefail means the script already exits 0 after the last successful statement. Safe to drop.

Suggested change
exit 0

#!/usr/bin/env bash
# Test harness for script/ci-required-hosted-gate.

set -uo pipefail

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.

-e is absent here but gets enabled inside run_case via set -e after each test execution. This means exit-on-error is off during the first test's outer-script context and on for all subsequent ones. Adding -e here and relying on the existing set +e/set -e guards in run_case makes the behaviour consistent throughout.

Suggested change
set -uo pipefail
set -euo pipefail

"true" \
"false"

run_case \

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.

This combination (merge_group + SHOULD_RUN_HOSTED_CI=false) can't happen in production: .github/actions/hosted-ci-selectors always emits should_run_hosted_ci=true for merge_group events because eventName !== 'pull_request'. The test is valid as a gate-in-isolation unit case, but worth a comment so readers don't think this reflects a real workflow state.

@cursor

cursor Bot commented Jun 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_d5664f52-d882-4070-bd67-999aaf4373b8)

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
react-on-rails/client bundled (gzip) 63.5 KB (0%)
react-on-rails/client bundled (gzip) (time) 63.5 KB (0%)
react-on-rails/client bundled (brotli) 54.51 KB (0%)
react-on-rails/client bundled (brotli) (time) 54.51 KB (0%)
react-on-rails-pro/client bundled (gzip) 64.27 KB (0%)
react-on-rails-pro/client bundled (gzip) (time) 64.27 KB (0%)
react-on-rails-pro/client bundled (brotli) 55.21 KB (0%)
react-on-rails-pro/client bundled (brotli) (time) 55.21 KB (0%)
registerServerComponent/client bundled (gzip) 74.43 KB (0%)
registerServerComponent/client bundled (gzip) (time) 74.43 KB (0%)
registerServerComponent/client bundled (brotli) 64.04 KB (0%)
registerServerComponent/client bundled (brotli) (time) 64.04 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) 67.23 KB (0%)
wrapServerComponentRenderer/client bundled (gzip) (time) 67.23 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) 57.67 KB (0%)
wrapServerComponentRenderer/client bundled (brotli) (time) 57.67 KB (0%)

@claude

claude Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Code Review: Require hosted CI for generator PRs

Overview

This PR introduces a lightweight CI guard that prevents generator-sensitive PRs from passing ci-required / required-pr-gate without hosted CI being requested first. It was motivated by PR #4130 where a post-merge generator shard failure was only caught after main went red.

Correctness

The gate logic is correct:

  • ci-required-hosted-gate only fires on pull_request events — merge_group, push, workflow_dispatch, and unset event names all pass through safely.
  • Variable defaults use :-false as a safe/pass default when env vars are unset.
  • ci-changes-detector outputs run_generators=true as a string, and the gate compares against the string "true" — types are consistent.
  • Step ordering in ci-required.yml is correct: hosted-ci-selectors resolves before ci-changes-detector, and both run before the enforcement step.
  • The issues: read permission addition is necessary for github.rest.issues.listLabelsOnIssue() in hosted-ci-selectors.
  • The test harness correctly sets set -uo pipefail WITHOUT -e so it can capture exit codes from the gate.

Minor Issues

1. Redundant exit 0 at the end of the gate script

With set -euo pipefail, reaching the end of the script exits with 0 naturally. The explicit final exit 0 is harmless but unnecessary noise.


2. Missing test cases for push and workflow_dispatch events

The test harness covers pull_request, merge_group, and empty event name. Since the gate only blocks pull_request, both push and workflow_dispatch pass through — but they are not tested explicitly. The empty-event-name case implicitly covers them, but named cases would serve as documentation that these paths are intentionally exempt.

Suggested additions:

run_case \
  "allows workflow_dispatch events even with generator changes" \
  0 \
  "workflow_dispatch" \
  "true" \
  "false"

run_case \
  "allows push events even with generator changes" \
  0 \
  "push" \
  "true" \
  "false"

3. Unrelated test fix bundled into CI infrastructure PR

packages/react-on-rails-pro-node-renderer/tests/incrementalHtmlStreaming.test.ts updates an expected error message wording from "is not received. Ensure to send the async prop from ruby side" to "was not received. Make sure you send it from the Rails side". This is clearly a correct fix, but it is unrelated to the CI gate machinery. Consider noting this explicitly in the PR description as an incidental fix to avoid reviewer confusion, or splitting it out.

Positive Notes

  • The gate script itself is admirably minimal — exactly right for something that runs on every PR.
  • Running the test harness as a workflow step (before the enforcement step) is smart: it validates gate logic using mocked env vars without needing any GitHub context.
  • The 6 test cases cover all the important branches of the gate logic.
  • Documentation updates across AGENTS.md, .github/read-me.md, and ci-optimization.md are consistent and complete.
  • The PR description includes a thorough replay-evidence section that makes the motivation clear.

Summary

The implementation is correct and the approach is sound. The three items above are all minor — the redundant exit 0 is cosmetic, the missing test cases are a documentation gap rather than a correctness gap, and the bundled test fix is benign. This is ready to merge with those points noted.

@cursor

cursor Bot commented Jun 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_be2aaba2-ee25-497f-baaf-897836008e29)

@justin808

Copy link
Copy Markdown
Member Author

Confidence note:

@justin808 justin808 added this pull request to the merge queue Jun 21, 2026
Merged via the queue into main with commit 21f4b4e Jun 21, 2026
58 checks passed
@justin808 justin808 deleted the jg-codex/require-hosted-ci-for-generators branch June 21, 2026 02:26
justin808 added a commit that referenced this pull request Jun 21, 2026
…-pr-batch-skills

* origin/main:
  Bound the RSCProvider RSC payload cache with an LRU (#3564) (#4097)
  Harden PR security preflight follow-ups (#4151)
  [codex] Trust ShakaCode team for agent inputs (#4154)
  Default adversarial PR review to current branch (#4155)
  Require hosted CI for generator PRs (#4149)

# Conflicts:
#	.agents/skills/pr-batch/SKILL.md
#	.agents/workflows/pr-processing.md
justin808 added a commit that referenced this pull request Jun 21, 2026
…trap-4138

* origin/main:
  Docs: point Pro license to purchase site (#4160)
  docs: paired ShakaPerf A/B methodology for RSC perf regressions (#4137) (#4142)
  Bound the RSCProvider RSC payload cache with an LRU (#3564) (#4097)
  Harden PR security preflight follow-ups (#4151)
  [codex] Trust ShakaCode team for agent inputs (#4154)
  Default adversarial PR review to current branch (#4155)
  Require hosted CI for generator PRs (#4149)
  Make review-fix push confirmation context-sensitive (#4152)
  Harden PR batch security preflight (#4148)
  Add bidirectional streaming for async props (pull mode) (#4048)
  Fix main generator pretend spec isolation (#4147)
  Revive Pro streaming validation coverage (#4035)
  Fix ci-local detector JSON parsing (#4061)
  ci(pro): add Rspack build leg for execjs-compatible-dummy (#4091) (#4106)
  Add High-Risk Mode to adversarial-pr-review (#4050) (#4115)
  Fix hydration error reporting for thrown values (#4120)
  Add batch cancellation / drain protocol to stop in-flight PR batches (#4119)
  [codex] Document current RSC architecture and version policy (#4103)
  Clarify PR-batch merge authority and ready gates (#4140)

# Conflicts:
#	docs/oss/building-features/performance-tracks-and-profiling.md
#	llms-full.txt
justin808 added a commit that referenced this pull request Jun 21, 2026
…o-agent-guidance

* origin/main: (647 commits)
  Consolidate analysis/ into internal/analysis/ (#4159)
  Docs: point Pro license to purchase site (#4160)
  docs: paired ShakaPerf A/B methodology for RSC perf regressions (#4137) (#4142)
  Bound the RSCProvider RSC payload cache with an LRU (#3564) (#4097)
  Harden PR security preflight follow-ups (#4151)
  [codex] Trust ShakaCode team for agent inputs (#4154)
  Default adversarial PR review to current branch (#4155)
  Require hosted CI for generator PRs (#4149)
  Make review-fix push confirmation context-sensitive (#4152)
  Harden PR batch security preflight (#4148)
  Add bidirectional streaming for async props (pull mode) (#4048)
  Fix main generator pretend spec isolation (#4147)
  Revive Pro streaming validation coverage (#4035)
  Fix ci-local detector JSON parsing (#4061)
  ci(pro): add Rspack build leg for execjs-compatible-dummy (#4091) (#4106)
  Add High-Risk Mode to adversarial-pr-review (#4050) (#4115)
  Fix hydration error reporting for thrown values (#4120)
  Add batch cancellation / drain protocol to stop in-flight PR batches (#4119)
  [codex] Document current RSC architecture and version policy (#4103)
  Clarify PR-batch merge authority and ready gates (#4140)
  ...

# Conflicts:
#	AGENTS_USER_GUIDE.md
justin808 added a commit that referenced this pull request Jun 22, 2026
…ales-js

* origin/main:
  [codex] Document flagship demo coordination (#4164)
  Enrich deferred-render RSC errors with the bundle diagnostic (#3475) (#4100)
  Consolidate analysis/ into internal/analysis/ (#4159)
  Docs: point Pro license to purchase site (#4160)
  docs: paired ShakaPerf A/B methodology for RSC perf regressions (#4137) (#4142)
  Bound the RSCProvider RSC payload cache with an LRU (#3564) (#4097)
  Harden PR security preflight follow-ups (#4151)
  [codex] Trust ShakaCode team for agent inputs (#4154)
  Default adversarial PR review to current branch (#4155)
  Require hosted CI for generator PRs (#4149)
  Make review-fix push confirmation context-sensitive (#4152)
  Harden PR batch security preflight (#4148)
  Add bidirectional streaming for async props (pull mode) (#4048)
  Fix main generator pretend spec isolation (#4147)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

force-full-hosted-ci Bypass optimized hosted CI selection and run all hosted suites ready-for-hosted-ci Run optimized hosted GitHub CI for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant