Skip to content

feat: tie-breaking of optimal action values by random rewards [LWCGC24, Lemma 6] #10591

feat: tie-breaking of optimal action values by random rewards [LWCGC24, Lemma 6]

feat: tie-breaking of optimal action values by random rewards [LWCGC24, Lemma 6] #10591

Workflow file for this run

name: PR status

Check warning on line 1 in .github/workflows/pr-status.yml

View workflow run for this annotation

GitHub Actions / PR status

Workflow execution policy warning (evaluate mode)

On December 2, 2026, GitHub will restrict `pull_request_target` on public repositories by default. To continue allowing the event trigger, configure an Actions policy. Learn more: https://gh.io/securely-using-pull_request_target#default-policy-for-pull_request_target
# Keeps every PR's status label and its Zulip post current, reconciling in batches.
#
# This used to be three per-event workflows (pr-labels.yml's per-event jobs, zulip-pr.yml and
# zulip-pr-status.yml): one GitHub-hosted job for every label, comment, push and build event on every
# PR, over a thousand an hour, each spending most of its short life on setup. Those jobs competed with
# PR builds for the organisation's twenty GitHub-hosted slots.
#
# Now the events only wake this workflow. Its concurrency group is global, and GitHub admits one run
# at a time and keeps only the newest waiting run, cancelling the others before they take a runner.
# Each fresh scan reconciles every PR touched since its saved watermark
# (scripts/pr_status/batch.py), so an event whose own run was collapsed away is still covered by the
# run that replaced it. The price is latency: an update waits out a one-minute debounce (see the
# job's `environment`) and then the run ahead of it, typically one to three minutes in all.
# Failed runs retain unfinished work and quota deadlines in a verified artifact;
# the next run resumes without replaying its successful prefix.
# pr-labels.yml keeps the hourly reconcile-all sweep of labels and the manual re-sync.
on:
# Retry retained work even after the final PR event of a quiet period.
schedule:
- cron: "7 * * * *"
workflow_dispatch:
pull_request_target:
types: [opened, reopened, synchronize, closed, edited, converted_to_draft, ready_for_review, labeled, unlabeled]
workflow_run:
workflows: ["pr-build", "Review"]
types: [requested, completed]
issue_comment:
types: [created, edited, deleted]
permissions:
contents: read
actions: read
jobs:
app-credentials:
if: >-
((github.repository == 'LeanMachineLearning/LMLExplore' && ( ((github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request_target' && (github.event.action != 'edited' || github.event.changes.base != null)) || (github.event_name == 'workflow_run' && ((github.event.workflow_run.name == 'pr-build' && github.event.workflow_run.event == 'pull_request_target') || (github.event.workflow_run.name == 'Review' && github.event.action == 'completed'))) || (github.event_name == 'issue_comment' && github.event.issue.pull_request != null && (contains(github.event.comment.body, 'tauceti-scoreboard') || contains(github.event.changes.body.from, 'tauceti-scoreboard') )) )))
runs-on: ubuntu-latest
permissions: {}
outputs:
ready: ${{ steps.check.outputs.ready }}
steps:
- name: Check App settings for setup
id: check
env:
APP_ID: ${{ secrets.APP_ID }}
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
shell: bash
run: |
ready=true
for name in APP_ID APP_PRIVATE_KEY; do
if [ -z "${!name}" ]; then
ready=false
printf 'Missing %s. Finish App credential setup with tauceti-tools doctor.\n' "$name" >> "$GITHUB_STEP_SUMMARY"
fi
done
printf 'ready=%s\n' "$ready" >> "$GITHUB_OUTPUT"
reconcile:
needs: app-credentials
# Meaningful PR events plus periodic/manual recovery; other events skip.
if: >-
needs.app-credentials.outputs.ready == 'true' && (github.repository == 'LeanMachineLearning/LMLExplore' && ( ((github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request_target' && (github.event.action != 'edited' || github.event.changes.base != null)) || (github.event_name == 'workflow_run' && ((github.event.workflow_run.name == 'pr-build' && github.event.workflow_run.event == 'pull_request_target') || (github.event.workflow_run.name == 'Review' && github.event.action == 'completed'))) || (github.event_name == 'issue_comment' && github.event.issue.pull_request != null && (contains(github.event.comment.body, 'tauceti-scoreboard') || contains(github.event.changes.body.from, 'tauceti-scoreboard') )) ))
runs-on: ubuntu-latest
timeout-minutes: 30
# On the job, not the workflow: a workflow-level group admits runs before the `if` above is
# evaluated, so an irrelevant event could displace the one pending run that mattered and then
# skip. Here only runs that pass the filter enter the group. (Nothing else may share it: GitHub
# replaces a pending member with the newest, so a different kind of job would cancel a batch.)
concurrency:
group: pr-status
cancel-in-progress: false
# A one-minute debounce that holds no runner. The pr-status-debounce environment's only
# protection rule is a one-minute wait timer; a job waiting on it holds the concurrency group
# but no runner, while newer events collapse into the one pending run behind it. Without it,
# events arriving continuously kept one runner busy back to back; with it, a batch runs at most
# about every two minutes (the wait plus the batch) and covers everything that arrived meanwhile.
# `deployment: false` keeps the wait timer without recording a deployment for every batch.
# Keep secrets out of this environment: they would become available to the job.
environment:
name: pr-status-debounce
deployment: false
steps:
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1; v1 ignores permission-* inputs
id: app-token
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
owner: LeanMachineLearning
repositories: LMLExplore
permission-issues: write
permission-pull-requests: write
permission-contents: read
# No `actions` permission: the App does not hold it, and the run listings batch.py reads
# are public for this public repository.
# The trusted base checkout: the scripts that run are the ones on the target branch, never the
# version proposed by the PR.
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
# The policy checkout below is a local action, so it must come from this trusted checkout.
sparse-checkout: |
scripts/pr_status
.github/actions/checkout-merge-policy
persist-credentials: false
- name: Prepare pinned shared tools
uses: TauCetiProject/TauCetiTools/.github/actions/setup@68ca7893e90b82454ab58ba64dca753a05cd2720
with:
tools-repository: TauCetiProject/TauCetiTools
tools-ref: 68ca7893e90b82454ab58ba64dca753a05cd2720
project-directory: .
- name: Checkout the pinned merge policy (read-only)
uses: ./.github/actions/checkout-merge-policy
# Discover artifacts directly: cancelled pending runs have no artifact and
# can otherwise crowd the last useful checkpoint out of a run listing.
- name: Restore latest trusted progress
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/state-in"
trusted_run=$(cat scripts/pr_status/trusted-run.jq)
ids=$(gh api "repos/$REPO/actions/artifacts?name=pr-status-progress&per_page=10" \
--jq '.artifacts | sort_by(.created_at) | reverse | .[] | select(.expired == false) | .workflow_run.id')
for id in $ids; do
trusted=$(gh api "repos/$REPO/actions/runs/$id" --jq "$trusted_run")
if [ "$trusted" = true ]; then
gh run download "$id" -R "$REPO" -n pr-status-progress -D "$RUNNER_TEMP/state-in"
break
fi
done
# Cold-start --since fallback only; restored progress owns its watermark.
# Use the last trusted success, overlapping two minutes and capped at 48h;
# before any success, inspect the previous two hours. A lookup failure fails
# the job rather than guessing.
- name: Find where the previous run started
id: since
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
trusted_run=$(cat scripts/pr_status/trusted-run.jq)
prev=$(gh api "repos/${{ github.repository }}/actions/workflows/pr-status.yml/runs?status=success&per_page=10" \
--jq "[.workflow_runs[] | select($trusted_run)] | .[0]")
last=$(jq -r '.run_started_at // ""' <<< "$prev")
id=$(jq -r '.id // ""' <<< "$prev")
# One-time migration of the former retry-only artifact when no new
# checkpoint exists. Missing legacy state uses the cold-start window.
if [ ! -f "$RUNNER_TEMP/state-in/state.json" ] && [ -n "$id" ]; then
gh run download "$id" -R "${{ github.repository }}" -n pr-status-retry -D "$RUNNER_TEMP/state-in" \
2>/dev/null || true
fi
if [ -f "$RUNNER_TEMP/state-in/retry.json" ]; then
mv "$RUNNER_TEMP/state-in/retry.json" "$RUNNER_TEMP/state-in/state.json"
fi
python3 - "$last" >> "$GITHUB_OUTPUT" <<'EOF'
import datetime as dt, sys
now = dt.datetime.now(dt.timezone.utc)
if sys.argv[1]:
t = dt.datetime.fromisoformat(sys.argv[1].replace("Z", "+00:00")) - dt.timedelta(minutes=2)
else:
t = now - dt.timedelta(hours=2)
t = max(t, now - dt.timedelta(hours=48))
print("since=" + t.strftime("%Y-%m-%dT%H:%M:%SZ"))
EOF
- name: Reconcile PR status labels
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
GH_REPO: ${{ github.repository }}
ZULIP_API_KEY: ${{ secrets.ZULIP_API_KEY }}
ZULIP_EMAIL: ${{ secrets.ZULIP_EMAIL }}
ZULIP_SITE:
SINCE: ${{ steps.since.outputs.since }}
# The event's own PR, when its payload names one, goes first.
PR: ${{ github.event.pull_request.number || github.event.issue.number || github.event.workflow_run.pull_requests[0].number }}
# From the repository root: readiness finds the pinned policy at .tauceti-review/runner.
run: |
args=(--labels-only --since "$SINCE" --state-in "$RUNNER_TEMP/state-in/state.json" --state-out "$RUNNER_TEMP/progress/state.json")
mkdir -p "$RUNNER_TEMP/progress"
case "$PR" in ''|*[!0-9]*) ;; *) args+=(--pr "$PR") ;; esac
python3 scripts/pr_status/batch.py "${args[@]}"
- name: Save completed progress and unfinished work
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: pr-status-progress
path: ${{ runner.temp }}/progress/state.json
if-no-files-found: error
retention-days: 7
overwrite: true