Skip to content

Close RegExp migration after stage 3 abort #561

Close RegExp migration after stage 3 abort

Close RegExp migration after stage 3 abort #561

name: Performance Preview (Informational, Non-Gating)
on:
push:
branches: [main]
pull_request_target:
branches: [main]
workflow_dispatch:
inputs:
base_sha:
description: Full SHA of a merged main ancestor to use as the fixed base
required: false
type: string
permissions:
contents: read
# Keep only the latest run for one PR; give each main push its own run-bound
# group so rapid pushes still produce one run each.
concurrency:
group: performance-preview-${{ github.event_name }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
reference-engine-cache:
name: Prepare reusable QuickJS-NG executable cache
if: >-
github.event_name == 'push' ||
(github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
runs-on: ubuntu-latest
timeout-minutes: 15
env:
PYTHONDONTWRITEBYTECODE: '1'
CACHE_ROOT: ${{ github.workspace }}/target/performance-preview/build-cache
PLAN_ROOT: ${{ github.workspace }}/target/performance-preview/reference-cache-plan
steps:
- name: Checkout exact trusted main revision
uses: actions/checkout@v6
with:
repository: ${{ github.repository }}
ref: ${{ github.sha }}
fetch-depth: 1
persist-credentials: false
submodules: false
- name: Compute pinned reference executable cache identity
id: reference-cache-plan
run: |
python3 -m tools.benchmark.build_cache reference-plan \
--manifest benchmarks/manifest.json \
--output-dir "$PLAN_ROOT" \
--github-output "$GITHUB_OUTPUT"
- name: Restore pinned QuickJS-NG executable cache
id: quickjs-cache
uses: actions/cache/restore@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/quickjs-ng/${{ steps.reference-cache-plan.outputs.quickjs-key }}
key: performance-preview-quickjs-ng-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.reference-cache-plan.outputs.quickjs-key }}
- name: Build pinned QuickJS-NG only on cache miss
if: steps.quickjs-cache.outputs.cache-hit != 'true'
run: |
reference_repo="$(python3 -m tools.benchmark.preview reference \
--manifest benchmarks/manifest.json --field repo)"
reference_revision="$(python3 -m tools.benchmark.preview reference \
--manifest benchmarks/manifest.json --field revision)"
git submodule sync -- third_party/quickjs-ng
git submodule update --init --depth 1 third_party/quickjs-ng
test "$(git -C third_party/quickjs-ng remote get-url origin)" = "$reference_repo"
python3 -m tools.benchmark.preview verify-source \
--source third_party/quickjs-ng --revision "$reference_revision"
quickjs_make_args=()
while IFS= read -r argument; do quickjs_make_args+=("$argument"); done \
< <(python3 -m tools.benchmark.build_cache recipe \
--kind quickjs --field make_args)
test "${#quickjs_make_args[@]}" -gt 0
make -C third_party/quickjs-ng "CC=$(command -v cc)" "${quickjs_make_args[@]}"
python3 -m tools.benchmark.preview verify-source \
--source third_party/quickjs-ng --revision "$reference_revision"
python3 -m tools.benchmark.build_cache store \
--entry "$CACHE_ROOT/quickjs-ng/${{ steps.reference-cache-plan.outputs.quickjs-key }}" \
--spec "$PLAN_ROOT/quickjs-ng.json" \
--binary third_party/quickjs-ng/build/qjs
- name: Revalidate pinned QuickJS-NG executable cache
run: |
python3 -m tools.benchmark.build_cache ready \
--entry "$CACHE_ROOT/quickjs-ng/${{ steps.reference-cache-plan.outputs.quickjs-key }}" \
--spec "$PLAN_ROOT/quickjs-ng.json"
- name: Save pinned QuickJS-NG executable cache before measurement
if: steps.quickjs-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/quickjs-ng/${{ steps.reference-cache-plan.outputs.quickjs-key }}
key: performance-preview-quickjs-ng-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.reference-cache-plan.outputs.quickjs-key }}
base-owned-preview:
name: Base-owned preview - cooperative same-repository PR
if: >-
github.event_name == 'pull_request_target' &&
github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name
runs-on: ubuntu-latest
timeout-minutes: 57
env:
QJS_HARNESS_ROOT: ${{ github.workspace }}
QJS_HARNESS_MODE: base_owned_harness
EVIDENCE_DIR: ${{ github.workspace }}/target/performance-preview/evidence
PYTHONDONTWRITEBYTECODE: '1'
PREVIEW_EVENT_NAME: ${{ github.event_name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
PR_BASE_REPOSITORY: ${{ github.event.pull_request.base.repo.full_name }}
PR_HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_BASE_CLONE_URL: ${{ github.event.pull_request.base.repo.clone_url }}
PR_HEAD_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url }}
steps:
# The orchestrator can only see its own step's clock. The sentinel lane
# must also respect the job deadline, because a job carries setup, cache,
# and publication steps that the script never observes.
- name: Record when this job began
run: echo "QJS_PREVIEW_JOB_STARTED_AT=$(date +%s)" >> "$GITHUB_ENV"
- name: Checkout explicit PR base as base-owned harness
uses: actions/checkout@v6
with:
repository: ${{ github.event.pull_request.base.repo.full_name }}
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 1
persist-credentials: false
submodules: false
- name: Checkout explicit candidate head as benchmark subject
uses: actions/checkout@v6
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
path: target/performance-preview/candidate-source
fetch-depth: 1
persist-credentials: false
submodules: false
- name: Admit long-term base-owned transition state
run: |
python3 -m tools.benchmark.hosted_preview admit \
--event-name "$PREVIEW_EVENT_NAME" \
--head-repository "$PR_HEAD_REPOSITORY" \
--base-repository "$PR_BASE_REPOSITORY" \
--base-sha "$PR_BASE_SHA" \
--base-ref "$PR_BASE_REF" \
--pr-number "$PR_NUMBER" \
--head-ref "$PR_HEAD_REF" \
--require-mode base_owned_harness
- name: Initialize pending evidence before setup and audit
run: |
mkdir -p "$EVIDENCE_DIR"
reference_revision="$(python3 -m tools.benchmark.preview reference \
--manifest benchmarks/manifest.json --field revision)"
python3 -m tools.benchmark.preview status \
--state pending --phase pre_setup --output-dir "$EVIDENCE_DIR" \
--harness-mode "$QJS_HARNESS_MODE" \
--harness-revision "$PR_BASE_SHA" \
--candidate-revision "$PR_HEAD_SHA" \
--base-revision "$PR_BASE_SHA" \
--reference-revision "$reference_revision" \
--message "setup or audit has not completed; no performance conclusion is available"
- name: Setup Rust from PR base
uses: ./.github/actions/setup-rust
with:
source-root: .
- name: Audit base-owned harness policy
run: |
reference_revision="$(python3 -m tools.benchmark.preview reference \
--manifest benchmarks/manifest.json --field revision)"
python3 -m tools.benchmark.preview status \
--state pending --phase audit --output-dir "$EVIDENCE_DIR" \
--harness-mode "$QJS_HARNESS_MODE" \
--harness-revision "$PR_BASE_SHA" \
--candidate-revision "$PR_HEAD_SHA" \
--base-revision "$PR_BASE_SHA" \
--reference-revision "$reference_revision" \
--message "selected base-owned harness audits have not completed"
./scripts/performance-policy-audit.sh
./scripts/external-corpus-audit.sh
- name: Compute exact executable cache identities
id: build-cache-plan
run: |
python3 -m tools.benchmark.build_cache plan \
--candidate-source "$GITHUB_WORKSPACE/target/performance-preview/candidate-source" \
--base-source "$GITHUB_WORKSPACE" \
--manifest benchmarks/manifest.json \
--output-dir "$GITHUB_WORKSPACE/target/performance-preview/build-cache-plan" \
--github-output "$GITHUB_OUTPUT"
- name: Restore candidate executable cache (read-only)
id: candidate-cache
uses: actions/cache/restore@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/rust/${{ steps.build-cache-plan.outputs.candidate-key }}
key: performance-preview-rust-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.candidate-key }}
- name: Restore distinct base executable cache (read-only)
if: steps.build-cache-plan.outputs.base-key != steps.build-cache-plan.outputs.candidate-key
id: base-cache
uses: actions/cache/restore@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/rust/${{ steps.build-cache-plan.outputs.base-key }}
key: performance-preview-rust-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.base-key }}
- name: Restore QuickJS-NG executable cache (read-only)
id: quickjs-cache
uses: actions/cache/restore@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/quickjs-ng/${{ steps.build-cache-plan.outputs.quickjs-key }}
key: performance-preview-quickjs-ng-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.quickjs-key }}
# 47 rather than 35: the sentinel lane adds a hard-bounded 600 seconds
# after the broad lane, and the step must have room for that bound plus
# the fallback write, or a timeout here would discard the broad lane's
# durable conclusion.
- name: Build and measure three pinned engines
timeout-minutes: 47
run: |
"$QJS_HARNESS_ROOT/scripts/performance-preview.sh" \
--harness-mode "$QJS_HARNESS_MODE" \
--candidate-source "$GITHUB_WORKSPACE/target/performance-preview/candidate-source" \
--base-source "$GITHUB_WORKSPACE" \
--candidate-sha "$PR_HEAD_SHA" \
--base-sha "$PR_BASE_SHA" \
--candidate-repo "$PR_HEAD_CLONE_URL" \
--base-repo "$PR_BASE_CLONE_URL" \
--output "$EVIDENCE_DIR" \
--build-cache-root "$GITHUB_WORKSPACE/target/performance-preview/build-cache"
- name: Publish complete or durable failure summary
if: always()
shell: bash
run: |
mkdir -p "$EVIDENCE_DIR"
if [ -f "$QJS_HARNESS_ROOT/tools/benchmark/hosted_preview.py" ]; then
python3 -m tools.benchmark.hosted_preview publish \
--output-dir "$EVIDENCE_DIR" --step-summary "$GITHUB_STEP_SUMMARY" \
--job-status "${{ job.status }}"
else
printf '%s\n' '{"classification":"no_performance_conclusion","message":"checkout failed before evidence initialization","phase":"pre_orchestrator","schema_version":1,"state":"failed"}' > "$EVIDENCE_DIR/status.json"
printf '%s\n' '## Performance Preview Failed' '' '> **No performance conclusion was produced.**' '> Checkout failed before evidence initialization.' '' '- Failure phase: `pre_orchestrator`' > "$EVIDENCE_DIR/summary.md"
cat "$EVIDENCE_DIR/summary.md" >> "$GITHUB_STEP_SUMMARY"
fi
- name: Upload complete or partial preview evidence
if: always()
uses: actions/upload-artifact@v6
with:
name: performance-preview-${{ github.event_name }}-${{ github.run_id }}-${{ github.run_attempt }}
path: target/performance-preview/evidence/
if-no-files-found: error
retention-days: 14
main-push-preview:
name: Head-owned preview - trusted main update
needs: reference-engine-cache
if: >-
always() &&
(github.event_name == 'push' ||
(github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main'))
runs-on: ubuntu-latest
timeout-minutes: 57
env:
QJS_HARNESS_ROOT: ${{ github.workspace }}
QJS_HARNESS_MODE: ${{ github.event_name == 'workflow_dispatch' && 'manual_main_head_owned_harness' || 'main_push_head_owned_harness' }}
EVIDENCE_DIR: ${{ github.workspace }}/target/performance-preview/evidence
PYTHONDONTWRITEBYTECODE: '1'
PREVIEW_EVENT_NAME: ${{ github.event_name }}
RUN_REPOSITORY: ${{ github.repository }}
RUN_EVENT_REPOSITORY: ${{ github.event.repository.full_name }}
RUN_REF: ${{ github.ref }}
RUN_BASE_SHA: ${{ github.event_name == 'push' && github.event.before || inputs.base_sha || github.sha }}
RUN_CANDIDATE_SHA: ${{ github.sha }}
RUN_WORKFLOW_SHA: ${{ github.sha }}
RUN_CLONE_URL: ${{ github.event.repository.clone_url }}
steps:
# Same reason as the base-owned job: the job deadline is not visible to
# the orchestrator unless it is recorded here.
- name: Record when this job began
run: echo "QJS_PREVIEW_JOB_STARTED_AT=$(date +%s)" >> "$GITHUB_ENV"
- name: Checkout exact main revision as head-owned harness and candidate
uses: actions/checkout@v6
with:
repository: ${{ github.repository }}
ref: ${{ github.sha }}
fetch-depth: ${{ github.event_name == 'workflow_dispatch' && '0' || '1' }}
persist-credentials: false
submodules: false
- name: Checkout exact comparison revision
uses: actions/checkout@v6
with:
repository: ${{ github.repository }}
ref: ${{ github.event_name == 'push' && github.event.before || inputs.base_sha || github.sha }}
path: target/performance-preview/base-source
fetch-depth: 1
persist-credentials: false
submodules: false
- name: Admit exact trusted main update
run: |
if [ "$PREVIEW_EVENT_NAME" = "push" ]; then
python3 -m tools.benchmark.hosted_preview admit-push \
--event-name "$PREVIEW_EVENT_NAME" \
--repository "$RUN_REPOSITORY" \
--event-repository "$RUN_EVENT_REPOSITORY" \
--ref "$RUN_REF" \
--before-sha "$RUN_BASE_SHA" \
--after-sha "$RUN_CANDIDATE_SHA" \
--workflow-sha "$RUN_WORKFLOW_SHA" \
--require-mode main_push_head_owned_harness
else
python3 -m tools.benchmark.hosted_preview admit-dispatch \
--event-name "$PREVIEW_EVENT_NAME" \
--repository "$RUN_REPOSITORY" \
--event-repository "$RUN_EVENT_REPOSITORY" \
--ref "$RUN_REF" \
--revision "$RUN_CANDIDATE_SHA" \
--base-revision "$RUN_BASE_SHA" \
--workflow-sha "$RUN_WORKFLOW_SHA" \
--require-mode manual_main_head_owned_harness
git -C "$GITHUB_WORKSPACE" \
merge-base --is-ancestor "$RUN_BASE_SHA" "$RUN_CANDIDATE_SHA" || {
echo "error: manual base must be an ancestor of the selected main candidate" >&2
exit 2
}
fi
- name: Initialize pending evidence before setup and audit
run: |
mkdir -p "$EVIDENCE_DIR"
reference_revision="$(python3 -m tools.benchmark.preview reference \
--manifest benchmarks/manifest.json --field revision)"
python3 -m tools.benchmark.preview status \
--state pending --phase pre_setup --output-dir "$EVIDENCE_DIR" \
--harness-mode "$QJS_HARNESS_MODE" \
--harness-revision "$RUN_CANDIDATE_SHA" \
--candidate-revision "$RUN_CANDIDATE_SHA" \
--base-revision "$RUN_BASE_SHA" \
--reference-revision "$reference_revision" \
--message "setup or audit has not completed; no performance conclusion is available"
- name: Setup Rust from trusted main harness
uses: ./.github/actions/setup-rust
with:
source-root: .
- name: Audit trusted main harness policy
run: |
reference_revision="$(python3 -m tools.benchmark.preview reference \
--manifest benchmarks/manifest.json --field revision)"
python3 -m tools.benchmark.preview status \
--state pending --phase audit --output-dir "$EVIDENCE_DIR" \
--harness-mode "$QJS_HARNESS_MODE" \
--harness-revision "$RUN_CANDIDATE_SHA" \
--candidate-revision "$RUN_CANDIDATE_SHA" \
--base-revision "$RUN_BASE_SHA" \
--reference-revision "$reference_revision" \
--message "selected trusted main harness audits have not completed"
./scripts/performance-policy-audit.sh
./scripts/external-corpus-audit.sh
- name: Compute exact executable cache identities
id: build-cache-plan
run: |
python3 -m tools.benchmark.build_cache plan \
--candidate-source "$GITHUB_WORKSPACE" \
--base-source "$GITHUB_WORKSPACE/target/performance-preview/base-source" \
--manifest benchmarks/manifest.json \
--output-dir "$GITHUB_WORKSPACE/target/performance-preview/build-cache-plan" \
--github-output "$GITHUB_OUTPUT"
- name: Restore candidate executable cache
id: candidate-cache
uses: actions/cache/restore@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/rust/${{ steps.build-cache-plan.outputs.candidate-key }}
key: performance-preview-rust-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.candidate-key }}
- name: Restore distinct base executable cache
if: steps.build-cache-plan.outputs.base-key != steps.build-cache-plan.outputs.candidate-key
id: base-cache
uses: actions/cache/restore@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/rust/${{ steps.build-cache-plan.outputs.base-key }}
key: performance-preview-rust-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.base-key }}
- name: Restore QuickJS-NG executable cache
id: quickjs-cache
uses: actions/cache/restore@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/quickjs-ng/${{ steps.build-cache-plan.outputs.quickjs-key }}
key: performance-preview-quickjs-ng-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.quickjs-key }}
# 47 rather than 35: the sentinel lane adds a hard-bounded 600 seconds
# after the broad lane, and the step must have room for that bound plus
# the fallback write, or a timeout here would discard the broad lane's
# durable conclusion.
- name: Build and measure three pinned engines
timeout-minutes: 47
run: |
"$QJS_HARNESS_ROOT/scripts/performance-preview.sh" \
--harness-mode "$QJS_HARNESS_MODE" \
--candidate-source "$GITHUB_WORKSPACE" \
--base-source "$GITHUB_WORKSPACE/target/performance-preview/base-source" \
--candidate-sha "$RUN_CANDIDATE_SHA" \
--base-sha "$RUN_BASE_SHA" \
--candidate-repo "$RUN_CLONE_URL" \
--base-repo "$RUN_CLONE_URL" \
--output "$EVIDENCE_DIR" \
--build-cache-root "$GITHUB_WORKSPACE/target/performance-preview/build-cache"
- name: Revalidate candidate executable cache for trusted save
if: always() && !cancelled()
id: candidate-cache-ready
run: |
ready=false
if python3 -m tools.benchmark.build_cache ready \
--entry "target/performance-preview/build-cache/rust/${{ steps.build-cache-plan.outputs.candidate-key }}" \
--spec "target/performance-preview/build-cache-plan/candidate.json"; then
ready=true
fi
echo "ready=$ready" >> "$GITHUB_OUTPUT"
- name: Revalidate base executable cache for trusted save
if: always() && !cancelled()
id: base-cache-ready
run: |
ready=false
if python3 -m tools.benchmark.build_cache ready \
--entry "target/performance-preview/build-cache/rust/${{ steps.build-cache-plan.outputs.base-key }}" \
--spec "target/performance-preview/build-cache-plan/base.json"; then
ready=true
fi
echo "ready=$ready" >> "$GITHUB_OUTPUT"
- name: Revalidate QuickJS-NG executable cache for trusted save
if: always() && !cancelled()
id: quickjs-cache-ready
run: |
ready=false
if python3 -m tools.benchmark.build_cache ready \
--entry "target/performance-preview/build-cache/quickjs-ng/${{ steps.build-cache-plan.outputs.quickjs-key }}" \
--spec "target/performance-preview/build-cache-plan/quickjs-ng.json"; then
ready=true
fi
echo "ready=$ready" >> "$GITHUB_OUTPUT"
- name: Save candidate executable cache from trusted main
if: >-
always() && !cancelled() &&
steps.candidate-cache-ready.outputs.ready == 'true' &&
steps.candidate-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/rust/${{ steps.build-cache-plan.outputs.candidate-key }}
key: performance-preview-rust-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.candidate-key }}
- name: Save distinct base executable cache from trusted main
if: >-
always() && !cancelled() &&
steps.base-cache-ready.outputs.ready == 'true' &&
steps.build-cache-plan.outputs.base-key != steps.build-cache-plan.outputs.candidate-key &&
steps.base-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/rust/${{ steps.build-cache-plan.outputs.base-key }}
key: performance-preview-rust-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.base-key }}
- name: Save QuickJS-NG executable cache from trusted main
if: >-
always() && !cancelled() &&
steps.quickjs-cache-ready.outputs.ready == 'true' &&
steps.quickjs-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
continue-on-error: true
with:
path: target/performance-preview/build-cache/quickjs-ng/${{ steps.build-cache-plan.outputs.quickjs-key }}
key: performance-preview-quickjs-ng-v1-${{ runner.os }}-${{ runner.arch }}-${{ steps.build-cache-plan.outputs.quickjs-key }}
- name: Publish complete or durable failure summary
if: always()
shell: bash
run: |
mkdir -p "$EVIDENCE_DIR"
if [ -f "$QJS_HARNESS_ROOT/tools/benchmark/hosted_preview.py" ]; then
python3 -m tools.benchmark.hosted_preview publish \
--output-dir "$EVIDENCE_DIR" --step-summary "$GITHUB_STEP_SUMMARY" \
--job-status "${{ job.status }}"
else
printf '%s\n' '{"classification":"no_performance_conclusion","message":"checkout failed before evidence initialization","phase":"pre_orchestrator","schema_version":1,"state":"failed"}' > "$EVIDENCE_DIR/status.json"
printf '%s\n' '## Performance Preview Failed' '' '> **No performance conclusion was produced.**' '> Checkout failed before evidence initialization.' '' '- Failure phase: `pre_orchestrator`' > "$EVIDENCE_DIR/summary.md"
cat "$EVIDENCE_DIR/summary.md" >> "$GITHUB_STEP_SUMMARY"
fi
- name: Upload complete or partial preview evidence
if: always()
uses: actions/upload-artifact@v6
with:
name: performance-preview-${{ github.event_name }}-${{ github.run_id }}-${{ github.run_attempt }}
path: target/performance-preview/evidence/
if-no-files-found: error
retention-days: 14
fork-preview-unsupported:
name: Fork preview unsupported by cooperative integrity scope
if: >-
github.event_name == 'pull_request_target' &&
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
runs-on: ubuntu-latest
steps:
- name: Record explicit fork skip
run: |
printf '%s\n' \
'## Performance Preview Unsupported' \
'' \
'> Hosted performance preview is skipped for fork pull requests.' \
'> The current integrity scope is cooperative same-repository PRs only.' \
>> "$GITHUB_STEP_SUMMARY"