From a14cd5feef9be3becc6672a4d87abe852cd690b2 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 9 Mar 2026 14:50:35 +0100 Subject: [PATCH 1/8] [GR-73734] Relax setuptools constraints in Python benchmark suite setup --- mx.graalpython/mx_graalpython_python_benchmarks.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mx.graalpython/mx_graalpython_python_benchmarks.py b/mx.graalpython/mx_graalpython_python_benchmarks.py index de40679029..a37370ba24 100644 --- a/mx.graalpython/mx_graalpython_python_benchmarks.py +++ b/mx.graalpython/mx_graalpython_python_benchmarks.py @@ -98,6 +98,8 @@ "reshape.Explode.time_explode", # Transient failure GR-61245, exit code -11 ] +SETUPTOOLS_PIN = "77.0.1" + DEFAULT_PYPERFORMANCE_BENCHMARKS = [ # "2to3", # "chameleon", @@ -564,7 +566,7 @@ class NumPySuite(PySuite): BENCHMARK_REQ = [ "asv==0.5.1", - "setuptools==70.3.0", + f"setuptools=={SETUPTOOLS_PIN}", "distlib==0.3.6", "filelock==3.8.0", "platformdirs==2.5.2", @@ -671,7 +673,7 @@ class PandasSuite(PySuite): BENCHMARK_REQ = [ "asv==0.5.1", - "setuptools==70.3.0", + f"setuptools=={SETUPTOOLS_PIN}", "distlib==0.3.6", "filelock==3.8.0", "platformdirs==2.5.2", @@ -762,8 +764,7 @@ def _vmRun(self, vm, workdir, command, benchmarks, bmSuiteArgs): vm.run(workdir, ["-m", "venv", join(workdir, vm_venv)]) pip = join(workdir, vm_venv, "bin", "pip") with tempfile.NamedTemporaryFile('w') as constraints: - # Constrain the version of setuptools used to build pandas - constraints.write('setuptools==70.3.0\n') + constraints.write(f"setuptools=={SETUPTOOLS_PIN}\n") constraints.flush() env = os.environ.copy() env['PIP_CONSTRAINT'] = constraints.name From 6909862cf50bb595f88414723e6f3e6f46de72bd Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 9 Mar 2026 14:51:34 +0100 Subject: [PATCH 2/8] [GR-73876] Make flock interop test wait deterministically for subprocess --- .../src/tests/test_fcntl.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_fcntl.py b/graalpython/com.oracle.graal.python.test/src/tests/test_fcntl.py index bc59641ce8..3ea160223c 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_fcntl.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_fcntl.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -65,6 +65,7 @@ def log(msg): def python_flock_blocks_sh_flock(python_flock_type, sh_flock_type): os.close(os.open(TEST_FILENAME_FULL_PATH, os.O_WRONLY | os.O_CREAT)) file = os.open(TEST_FILENAME_FULL_PATH, os.O_WRONLY) + p = None try: fcntl.flock(file, python_flock_type) p = subprocess.Popen("flock -%s %s -c 'exit 42'" % (sh_flock_type, TEST_FILENAME_FULL_PATH), shell=True) @@ -74,10 +75,13 @@ def python_flock_blocks_sh_flock(python_flock_type, sh_flock_type): log("unlocking the file...") fcntl.flock(file, fcntl.LOCK_UN) # release the lock log("checking the retcode...") - time.sleep(0.25) - assert p.poll() == 42 - log(f"{p.returncode=}") + retcode = p.wait(timeout=5) + assert retcode == 42 + log(f"{retcode=}") finally: + if p is not None and p.poll() is None: + p.terminate() + p.wait(timeout=2) fcntl.flock(file, fcntl.LOCK_UN) os.close(file) From ff1f916710555d8021a3e6e9b9af9c4373a5e207 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 9 Mar 2026 14:51:46 +0100 Subject: [PATCH 3/8] [GR-73909] Retry jacocoreport once on transient coverage read failures --- mx.graalpython/mx_graalpython.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mx.graalpython/mx_graalpython.py b/mx.graalpython/mx_graalpython.py index baa98f8b87..e36f63a74d 100644 --- a/mx.graalpython/mx_graalpython.py +++ b/mx.graalpython/mx_graalpython.py @@ -2347,7 +2347,7 @@ def python_coverage(args): '--strict-mode', '--tags', args.tags, ] + jacoco_args, env=env) - run_mx([ + jacoco_report_cmd = [ '--strict-compliance', '--kill-with-sigquit', 'jacocoreport', @@ -2356,7 +2356,14 @@ def python_coverage(args): 'coverage', '--generic-paths', '--exclude-src-gen', - ], env=env) + ] + # CI can occasionally leave transiently truncated execution data; retry once to reduce flakiness. + try: + run_mx(jacoco_report_cmd, env=env) + except Exception: # pylint: disable=broad-except + mx.warn("jacocoreport failed, retrying once after a short delay") + time.sleep(5) + run_mx(jacoco_report_cmd, env=env) if args.mode == 'truffle': executable = graalpy_standalone_jvm() From aa0a1f4afb8d3690b0c5d960e2b7cdad1c3f50ac Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 9 Mar 2026 19:35:42 +0100 Subject: [PATCH 4/8] Update imports --- ci/graal/common.json | 2 +- mx.graalpython/suite.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/graal/common.json b/ci/graal/common.json index f4266e2539..c6368727fc 100644 --- a/ci/graal/common.json +++ b/ci/graal/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.69.0", + "mx_version": "7.71.0", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { diff --git a/mx.graalpython/suite.py b/mx.graalpython/suite.py index dec4e83ba4..6c92430151 100644 --- a/mx.graalpython/suite.py +++ b/mx.graalpython/suite.py @@ -53,7 +53,7 @@ }, { "name": "tools", - "version": "bb17fd7e8ec441c087b63300c2d75e06828b8dde", + "version": "fcbc5553eb65a0d6c88495efc24e998606dd5fa6", "subdir": True, "urls": [ {"url": "https://github.com/oracle/graal", "kind": "git"}, @@ -61,7 +61,7 @@ }, { "name": "regex", - "version": "bb17fd7e8ec441c087b63300c2d75e06828b8dde", + "version": "fcbc5553eb65a0d6c88495efc24e998606dd5fa6", "subdir": True, "urls": [ {"url": "https://github.com/oracle/graal", "kind": "git"}, From 0fc72b6a5c9108ca095d5c2428829e8c7ea06763 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 9 Mar 2026 22:39:59 +0100 Subject: [PATCH 5/8] [GR-73912] Skip hanging numpy indexing benchmarks in periodic run --- mx.graalpython/mx_graalpython_python_benchmarks.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mx.graalpython/mx_graalpython_python_benchmarks.py b/mx.graalpython/mx_graalpython_python_benchmarks.py index a37370ba24..d4bc420f92 100644 --- a/mx.graalpython/mx_graalpython_python_benchmarks.py +++ b/mx.graalpython/mx_graalpython_python_benchmarks.py @@ -77,6 +77,8 @@ "bench_core.CountNonzero.time_count_nonzero_multi_axis(2, 1000000, )", # Times out "bench_core.CountNonzero.time_count_nonzero_multi_axis(3, 1000000, )", # Times out "bench_linalg.LinalgSmallArrays.time_det_small_array", # TODO fails with numpy.linalg.LinAlgError + "bench_indexing.IndexingSeparate.time_mmap_fancy_indexing", # Hangs in periodic job GR-73912 + "bench_indexing.IndexingStructured0D.time_array_slice", # Hangs in periodic job GR-73912 ] DEFAULT_PANDAS_BENCHMARKS = [ From 8958a5c52a098e4a31493f97fb73cbe735001d6b Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 10 Mar 2026 09:43:19 +0100 Subject: [PATCH 6/8] Add a skill for ROTA --- .agents/skills/graalpython-rota/SKILL.md | 83 ++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 .agents/skills/graalpython-rota/SKILL.md diff --git a/.agents/skills/graalpython-rota/SKILL.md b/.agents/skills/graalpython-rota/SKILL.md new file mode 100644 index 0000000000..2dee80f46a --- /dev/null +++ b/.agents/skills/graalpython-rota/SKILL.md @@ -0,0 +1,83 @@ +--- +name: graalpython-rota +description: Run GraalPy ROTA maintenance workflows for (1) import update pull requests and (2) triage of recent periodic job failures in Jira. Use when asked to perform or guide recurring ROTA tasks from `docs/contributor/ROTA.md`, including branch setup, `mx` update commands, PR creation with reviewers/gates via `ol-cli bitbucket`, and date-bounded periodic-failure issue triage via `ol-cli jira`. +--- + +# GraalPy ROTA + +## Overview +Execute recurring GraalPy ROTA tasks with exact commands and strict output structure. Prefer the procedures in this skill, and use `docs/contributor/ROTA.md` as the detailed source text. + +## Source Of Truth +- Primary: `docs/contributor/ROTA.md` +- If this skill workflow differs from the primary source, follow `docs/contributor/ROTA.md`. + +## Choose Workflow +- Use `Import update` when asked to refresh imports and open the standard PR. +- Use `Recent periodic issues` when asked to triage periodic job failures in Jira. + +## Import Update Workflow +1. Create a branch from latest `master`: +```bash +git checkout master +git pull --ff-only +git checkout -b "update/GR-21590/$(date +%d%m%y)" +``` +2. Update graal import: +```bash +mx python-update-import +``` +3. Update CPython unittest whitelist and inspect diff for plausibility. Expect mostly additions, not removals: +```bash +mx --dy /graalpython-enterprise python-update-unittest-tags +``` +4. Create PR with description `[GR-21590] Import update`. +5. Use `ol-cli bitbucket` to create PR, start gates, and set reviewers: +- `tim.felgentreff@oracle.com` +- `michael.simacek@oracle.com` +- `stepan.sindelar@oracle.com` +6. Fix gate failures and push updates until gates pass. + +## Recent Periodic Issues Workflow +1. Verify creator identity mapping: +- Treat `ol-automation_ww` as Jira username `olauto`. +- If query returns zero results, test both identities, then keep `creator = olauto` once verified. + +2. Filter to recent periodic job failures, excluding in progress or closed. +- Default to the last 14 days unless user specifies otherwise. +- Always state concrete start/end calendar dates in the response. +```bash +ol-cli jira search --json --max 100 \ + -f key,summary,creator,created,status,labels,components,assignee \ + -jql "project = GR AND component = Python AND creator = olauto AND labels = periodic-job-failures AND created >= -14d AND status != Closed AND status != 'In Progress' ORDER BY created DESC" +``` + +3. Fetch shortlisted issue details with `get-issue`: +```bash +ol-cli jira get-issue --json -id GR-XXXX \ + | jq '{key, summary:.fields.summary, status:.fields.status.name, created:.fields.created, labels:.fields.labels, assignee:(.fields.assignee.name // null), description:.fields.description, comments:(.fields.comment.comments | map({author:.author.name, created, body}))}' +``` + +7. Convert findings into an implementation-ready plan per issue: +- Extract failing job name, error signature, and log clue. +- Map probable source area in repo. +- Propose first verification command. +- Define exit criteria to close ticket. +- Prepare temporary git worktree per issue with branch naming based on Jira key plus very short hyphenated description. + +## Output Contract For Periodic Triage +Return exactly: +1. Query scope used (component, creator, time window, status filter). +2. Count summary (total recent automation issues vs periodic failures). +3. Issue list with key, created date, summary, status. +4. Per-issue plan with: +- Hypothesis +- First code locations to inspect +- First reproducibility command +- Exit criteria for closing ticket +5. Recommended implementation order. + +## Guardrails +- State concrete dates for recency windows. +- Prefer `--json` and explicit `-f` fields in searches. +- Use `get-issue` only for shortlisted issues to keep output small. From f2af00c8c993d170d4500658a955795d3ea453d7 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 10 Mar 2026 09:57:16 +0100 Subject: [PATCH 7/8] Add a skill to check a PR's gates --- .agents/skills/pr-gate-check/SKILL.md | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .agents/skills/pr-gate-check/SKILL.md diff --git a/.agents/skills/pr-gate-check/SKILL.md b/.agents/skills/pr-gate-check/SKILL.md new file mode 100644 index 0000000000..571812ca69 --- /dev/null +++ b/.agents/skills/pr-gate-check/SKILL.md @@ -0,0 +1,59 @@ +--- +name: pr-gate-check +description: Check gate status for a Bitbucket PR by resolving the PR head commit, finding the gate merge commit, inspecting builds on that merge commit, and summarizing root-cause failures with actionable next steps. +--- + +# PR Gate Check + +## Overview +Use this workflow when asked for gate status of a PR. Usually the builds are tied to a merge commit generated on Bitbucket, so this skill goes through finding the remote merge commit. + +## Workflow +1. Get PR commits and identify PR head commit (first commit in `ol-cli bitbucket commits` output): +```bash +ol-cli bitbucket commits --project=G --repo=graalpython --pullrequest= --all --json +``` + +2. Fetch refs and locate merge commit whose parent includes PR head: +```bash +git ls-remote origin 'refs/pull-requests//*' +git fetch --no-tags origin '+refs/heads/*:refs/remotes/origin/*' --prune +git rev-list --all --parents | rg ' ( |$)' +``` +Pick the merge commit where one parent is `` and the other is the target branch tip at merge time. + +3. Check builds on that merge commit: +```bash +ol-cli bitbucket get-builds --commit= --all --format=key,state,url +``` + +4. Separate root failures from fan-out failures: +- `FAILED` + `/builders/.../builds/...` URL: executed failed build (root failure candidate). +- `FAILED` + `build_request?brid=` URL: usually not-run/downstream due to earlier failure. + +5. Inspect root failed build logs and extract exact failing test/error: +- Open build URL and `Run executor` stdio log. +- Capture failing test id, traceback/assertion, and command context. + +6. Report back: +- PR head SHA +- merge SHA + parents (target parent + PR parent) +- build summary counts +- root cause failure(s) +- fix options and next action question + +## Output Template +1. `PR head:` `` +2. `Gate merge commit:` `` (`parent1=`, `parent2=`) +3. `Builds:` `` total, `` successful, `` failed +4. `Root failure(s):` +- ``: `` +- `` +- `` +5. `Proposed fixes:` short list +6. Ask user what to do next. + +## Guardrails +- Do not conclude from PR commit statuses alone; always resolve and inspect merge-commit builds. +- If many builds are failed but only one executed failure exists, treat that one as primary cause. +- Keep proposed fixes minimal and scoped to observed failure. From 0edeb912126ccd41886df0dfb2d2b56cca06118e Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 10 Mar 2026 10:29:15 +0100 Subject: [PATCH 8/8] Patch test_concurrent_futures.test_map_timeout to make it less flaky --- .../lib-python/3/test/test_concurrent_futures/executor.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/graalpython/lib-python/3/test/test_concurrent_futures/executor.py b/graalpython/lib-python/3/test/test_concurrent_futures/executor.py index e85f22da58..25e1e37d2f 100644 --- a/graalpython/lib-python/3/test/test_concurrent_futures/executor.py +++ b/graalpython/lib-python/3/test/test_concurrent_futures/executor.py @@ -59,9 +59,11 @@ def test_map_timeout(self): # GraalPy change: submit some dummy work first, so the next map call doesn't time out in the worker start up list(self.executor.map(time.sleep, [0])) try: + # GraalPy change: larger timeout for CI flakiness + # for i in self.executor.map(time.sleep, [0, 0, 6], timeout=5): for i in self.executor.map(time.sleep, - [0, 0, 6], - timeout=5): + [0, 0, 8], + timeout=3): results.append(i) except futures.TimeoutError: pass