Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c15ea6c
Let a generated version run its tasks in several built images
rzonyx Oct 21, 2026
bc7ea01
Generate exercism-polyglot@1.0 from Exercism's tracks
rzonyx Oct 21, 2026
03bc8a2
exercism-polyglot: fix C++ and shebang examples, drop stubs that pass
rzonyx Oct 21, 2026
9ceebf3
exercism-polyglot: a Rust inner attribute is not a shebang
rzonyx Oct 21, 2026
49bc808
Generate swebench-verified@1.0 and swebench-lite@1.0
rzonyx Oct 21, 2026
31742da
Merge origin/main: generated datasets and humaneval-plus@1.0's image …
rzonyx Oct 21, 2026
e4797b7
exercism-polyglot: drop the one-off Gradle timing
rzonyx Oct 21, 2026
333920a
Merge remote-tracking branch 'origin/main' into generated-exercism-po…
rzonyx Oct 21, 2026
384c191
swebench-lite@1.0: leave out psf__requests-863, which nop resolves
rzonyx Oct 21, 2026
d35484e
Hand the sampled tasks to the jobs that run them
rzonyx Oct 21, 2026
99b6bb4
Generate swebench-multilingual@1.0 and multi-swe-bench@1.0
rzonyx Oct 21, 2026
6c5167f
Merge generated-swebench: the sampled tasks are handed to the jobs th…
rzonyx Oct 21, 2026
613547d
multi-swe-bench@1.0: name its tasks in generated.lock.json, digests f…
rzonyx Oct 21, 2026
d750a2f
multi-swe-bench@1.0: lock its tasks' digests
rzonyx Oct 21, 2026
5e8fc1b
multi-swe-bench@1.0: give the evaluation three hours
rzonyx Oct 21, 2026
c1d76da
multi-swe-bench@1.0: lock its tasks' digests with the three-hour eval…
rzonyx Oct 21, 2026
67ef034
Merge remote-tracking branch 'origin/main' into generated-exercism-po…
rzonyx Oct 22, 2026
29002f7
Merge generated-exercism-polyglot (main and #9) into generated-swebench
rzonyx Oct 22, 2026
cef0b86
Merge remote-tracking branch 'origin/generated-swebench' into generat…
rzonyx Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions .github/workflows/exercism-polyglot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
name: Exercism polyglot

on:
pull_request:
paths:
- .github/workflows/exercism-polyglot.yml
- adapters/common/**
- adapters/exercism_polyglot/**
- datasets/exercism-polyglot/**
- images/bases.yaml
- images/images.yaml
- images/exercism-*/**
- scripts/environment_images.py
- scripts/generated_checks.py
- scripts/generated_source.py
- scripts/install-hbench.sh
push:
branches: [main]
paths:
- .github/workflows/exercism-polyglot.yml
- adapters/common/**
- adapters/exercism_polyglot/**
- datasets/exercism-polyglot/**
- images/bases.yaml
- images/images.yaml
- images/exercism-*/**
- scripts/environment_images.py
- scripts/generated_checks.py
- scripts/generated_source.py
- scripts/install-hbench.sh
workflow_dispatch:

permissions:
contents: read

concurrency:
group: exercism-polyglot-${{ github.ref }}
cancel-in-progress: true

defaults:
run:
shell: bash

jobs:
tasks:
name: "${{ matrix.language }}: build the image, then every oracle must pass and every stub fail"
runs-on: ubuntu-24.04
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
language: [cpp, go, java, javascript, python, rust]
env:
HBENCH_VERSION: v0.2.6
IMAGE_TAG: exercism-polyglot-${{ matrix.language }}-1.0
TASKS: exercism-${{ matrix.language }}-*
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Install the pinned Python packages
run: python -m pip install --require-hashes -r requirements.txt
- name: Install hbench, verifying SHA256SUMS and its build provenance
env:
GH_TOKEN: ${{ github.token }}
run: scripts/install-hbench.sh "$HBENCH_VERSION" "$RUNNER_TEMP/hbench"
- name: Build the image from its Dockerfile, from its base's Docker Hub source while GHCR has no copy of it yet
run: |
context="$(python scripts/environment_images.py image "$IMAGE_TAG" | jq -r .context)"
base="$(python scripts/environment_images.py base-of "$IMAGE_TAG")"
build_context="$RUNNER_TEMP/build-context"
cp -R "$context" "$build_context"
if ! docker pull --quiet "$base" > /dev/null 2>&1; then
source="$(python scripts/environment_images.py bases | awk -v target="${base%@*}" '$2 == target { print $1 }')"
echo "::notice title=Base not on GHCR yet::$base cannot be pulled, so $IMAGE_TAG is built from $source, the same digest."
sed -i "s|^FROM $base\$|FROM $source|" "$build_context/Dockerfile"
fi
started=$SECONDS
docker build --tag "ghcr.io/node-q/hbench-envs:$IMAGE_TAG" "$build_context"
echo "BUILD_SECONDS=$((SECONDS - started))" >> "$GITHUB_ENV"
- name: Generate the tasks, naming their images by tag
run: |
python scripts/generated_source.py generate --allow-unfilled-lock \
datasets/exercism-polyglot/1.0/source.yaml "$RUNNER_TEMP/generated"
- name: Run every task's oracle, which must pass, and its untouched stubs, which must fail
env:
HBENCH: ${{ runner.temp }}/hbench/hbench
run: |
started=$SECONDS
python -m adapters.verify exercism_polyglot "$RUNNER_TEMP/generated/tasks" --jobs 4 --task "$TASKS" \
| tee "$RUNNER_TEMP/check.log"
echo "CHECK_SECONDS=$((SECONDS - started))" >> "$GITHUB_ENV"
- name: Write the image's size and the times to the job summary
if: always()
run: |
reference="ghcr.io/node-q/hbench-envs:$IMAGE_TAG"
{
echo "## $IMAGE_TAG"
echo
if docker image inspect "$reference" > /dev/null 2>&1; then
size="$(docker image inspect --format '{{ .Size }}' "$reference")"
compressed="$(docker save "$reference" | gzip | wc -c)"
echo "- Image: $((size / 1000000)) MB on disk, $((compressed / 1000000)) MB gzip-compressed, built in ${BUILD_SECONDS:-?} s"
fi
echo "- Oracle and stub runs of every task, 4 at a time: ${CHECK_SECONDS:-?} s"
if [[ -f "$RUNNER_TEMP/check.log" ]]; then
grep -E '^(oracle|nop): ' "$RUNNER_TEMP/check.log" | sed 's/^/- /' || true
tail -n 1 "$RUNNER_TEMP/check.log" | sed 's/^/- /'
echo
echo '```'
grep -E '^(ok |FAIL)' "$RUNNER_TEMP/check.log" || true
echo '```'
fi
} | tee -a "$GITHUB_STEP_SUMMARY"
6 changes: 6 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ jobs:
case "$policy" in
pinned-mirror) package="hbench-envs/$DATASET" ;;
built) package="hbench-envs" ;;
built-locally) package="" ;;
*)
echo "The environment policy is $policy: no mirrored or built images to check."
exit 0
Expand All @@ -141,6 +142,11 @@ jobs:
unpullable=$((unpullable + 1))
fi
done < <(jq -r '[.[].pinned] | unique | .[]' "$images_lock")
if (( unpullable > 0 )) && [[ -z "$package" ]]; then
cat "$RUNNER_TEMP/mirror-pull.log" >&2
echo "::error title=Base images gone::$unpullable upstream base images in $images_lock cannot be pulled anonymously any more, so the tasks would not build. Pin them again with the Pin images workflow, as a new version. Nothing was pushed."
exit 1
fi
if (( unpullable > 0 )); then
cat "$RUNNER_TEMP/mirror-pull.log" >&2
echo "::error title=Environment images not public::$unpullable images in $images_lock cannot be pulled anonymously. A new GHCR package starts private: make ghcr.io/node-q/$package public in its package settings (https://github.com/orgs/node-q/packages/container/${package//\//%2F}/settings). Nothing was pushed."
Expand Down
162 changes: 162 additions & 0 deletions .github/workflows/sample-tasks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
name: Sample tasks

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

concurrency:
group: sample-tasks-${{ github.ref }}
cancel-in-progress: true

defaults:
run:
shell: bash

env:
HBENCH_VERSION: v0.3.0
SAMPLE_SIZE: "10"

jobs:
plan:
name: Choose a sample of each built-locally dataset
runs-on: ubuntu-24.04
timeout-minutes: 20
outputs:
matrix: ${{ steps.sample.outputs.matrix }}
sampled: ${{ steps.sample.outputs.sampled }}
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Install the pinned Python packages
run: python -m pip install --require-hashes -r requirements.txt
- name: Generate each built-locally version and choose its sample
id: sample
env:
PYTHONPATH: scripts
run: |
python scripts/sample_tasks.py --count "$SAMPLE_SIZE" --output "$RUNNER_TEMP/generated" \
--copy-to "$RUNNER_TEMP/sampled" > "$RUNNER_TEMP/matrix.json"
jq -r '.include[] | "\(.dataset)@\(.version) \(.task)"' "$RUNNER_TEMP/matrix.json"
echo "matrix=$(jq -c . "$RUNNER_TEMP/matrix.json")" >> "$GITHUB_OUTPUT"
echo "sampled=$(jq '.include | length > 0' "$RUNNER_TEMP/matrix.json")" >> "$GITHUB_OUTPUT"
- name: Upload the sampled tasks
if: steps.sample.outputs.sampled == 'true'
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: sampled-tasks
path: ${{ runner.temp }}/sampled
if-no-files-found: error
retention-days: 7

check:
name: ${{ matrix.dataset }}@${{ matrix.version }} ${{ matrix.task }}
needs: plan
if: needs.plan.outputs.sampled == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 360
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}
env:
DATASET: ${{ matrix.dataset }}
VERSION: ${{ matrix.version }}
ADAPTER: ${{ matrix.adapter }}
TASK: ${{ matrix.task }}
steps:
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Install the pinned Python packages
run: python -m pip install --require-hashes -r requirements.txt
- name: Install hbench, verifying SHA256SUMS and its build provenance
env:
GH_TOKEN: ${{ github.token }}
run: scripts/install-hbench.sh "$HBENCH_VERSION" "$RUNNER_TEMP/hbench"
- name: Download the sampled tasks
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: sampled-tasks
path: ${{ runner.temp }}/sampled
- name: Run the oracle and nop on the task, building its environment from the pinned base image
env:
HBENCH: ${{ runner.temp }}/hbench/hbench
PYTHONDONTWRITEBYTECODE: "1"
run: |
df -B1 --output=used / | tail -1 > "$RUNNER_TEMP/disk-before"
mkdir -p "$RUNNER_TEMP/result"
started=$SECONDS
status=0
python -m adapters.verify "$ADAPTER" "$RUNNER_TEMP/sampled/$DATASET-$VERSION" --task "$TASK" \
--summary "$RUNNER_TEMP/result/summary.json" < /dev/null || status=$?
echo $((SECONDS - started)) > "$RUNNER_TEMP/seconds"
exit "$status"
- name: Record the time and disk the task took
if: always()
run: |
used_before="$(cat "$RUNNER_TEMP/disk-before" 2>/dev/null || echo 0)"
used_after="$(df -B1 --output=used / | tail -1)"
seconds="$(cat "$RUNNER_TEMP/seconds" 2>/dev/null || echo 0)"
mkdir -p "$RUNNER_TEMP/result"
jq -n --arg dataset "$DATASET" --arg version "$VERSION" --arg task "$TASK" \
--argjson seconds "$seconds" --argjson disk_bytes "$((used_after - used_before))" \
--slurpfile summary <(cat "$RUNNER_TEMP/result/summary.json" 2>/dev/null || echo '[]') \
'{dataset: $dataset, version: $version, task: $task, seconds: $seconds, disk_bytes: $disk_bytes, summary: $summary[0][0]}' \
> "$RUNNER_TEMP/result/measurement.json"
{
echo "## $DATASET@$VERSION $TASK"
echo
echo "- Wall time: ${seconds} s; disk used by the images and trials: $(( (used_after - used_before) / 1024 / 1024 )) MiB"
echo
echo '```'
docker system df
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload the result
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: sample-${{ matrix.dataset }}-${{ matrix.version }}-${{ matrix.task }}
path: ${{ runner.temp }}/result
if-no-files-found: warn
retention-days: 30

summary:
name: Summarise the sample
needs: [plan, check]
if: always() && needs.plan.outputs.sampled == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Download every task's result
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
pattern: sample-*
path: ${{ runner.temp }}/results
- name: Write the sample's rewards, times and disk to the job summary
run: |
shopt -s nullglob
measurements=("$RUNNER_TEMP"/results/*/measurement.json)
{
echo "## Sampled tasks"
echo
echo "| Dataset | Task | Oracle | nop | Wall time (s) | Disk (MiB) | Problems |"
echo "| --- | --- | ---: | ---: | ---: | ---: | --- |"
for measurement in "${measurements[@]}"; do
jq -r '"| \(.dataset)@\(.version) | \(.task) | \(.summary.trials.oracle.reward // "-") | \(.summary.trials.nop.reward // "-") | \(.seconds) | \(.disk_bytes / 1048576 | floor) | \((.summary.problems // ["no summary"]) | join("; ")) |"' "$measurement"
done
} >> "$GITHUB_STEP_SUMMARY"
Loading
Loading