Skip to content

Add eval CI jobs for edge-tooling - #81386

Merged
openshift-merge-bot[bot] merged 4 commits into
openshift:mainfrom
kasturinarra:edge-tooling-eval-ci
Jul 23, 2026
Merged

openshift-merge-bot[bot] merged 4 commits into
openshift:mainfrom
kasturinarra:edge-tooling-eval-ci

Conversation

@kasturinarra

@kasturinarra kasturinarra commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds 4 eval CI job entries for openshift-eng/edge-tooling:
    • eval-cluster-diagnostic — manual trigger via /test eval-cluster-diagnostic
    • eval-cluster-diagnostic-changed — auto-triggers when plugins/two-node/evals/.*cluster-diagnostic files change
    • eval-threat-model-tnf — manual trigger via /test eval-threat-model-tnf
    • eval-threat-model-tnf-changed — auto-triggers when plugins/two-node/evals/.*threat-model-tnf files change
  • All use openshift-claude-agent-eval workflow, claude-opus-4-6 model, parallelism 3
  • All are optional: true — failures don't block merge

Context

Replaces #81166 which used on-the-fly eval generation (EVAL_SETUP_SCRIPT). This PR points at committed eval configs from edge-tooling PR #178 instead — no dynamic generation, enabling regression detection with committed judges.

Pattern follows openshift-eng/ai-helpers eval CI config exactly (per-skill manual + -changed auto-trigger pairs).

Test plan

  • Verify YAML is valid (done locally)
  • After edge-tooling PR Add config locations for config-updater #178 merges, test with /test eval-cluster-diagnostic on an edge-tooling PR
  • Verify -changed auto-trigger fires when eval case files are modified

🤖 Generated with Claude Code

Summary by CodeRabbit

This PR updates CI configuration in openshift/release for openshift-eng/edge-tooling by adding two new optional Claude eval presubmit entries that run the openshift-claude-agent-eval workflow with the claude-opus-4-6 model and EVAL_PARALLELISM: "3". The jobs support both manual and change-driven execution:

  • eval-all (manual via /test eval-all): runs with EVAL_DISCOVER: "true" to auto-discover eval configs.
  • eval-changed (manual via /test eval-changed, auto-triggered via run_if_changed: ^plugins/.*/evals/|^plugins/.*/skills/): runs with EVAL_CHANGED_ONLY: "true" (and EVAL_DISCOVER: "true") to limit execution to changed evals.

To support these modes, the openshift-claude-agent-eval step runner was enhanced to:

  • validate EVAL_DISCOVER vs EVAL_CONFIG mutual exclusivity,
  • loop over multiple selected/discovered eval configs (with per-config RUN_ID),
  • filter “changed” evals/cases when EVAL_CHANGED_ONLY=true and PULL_BASE_SHA is set,
  • aggregate results into a combined junit_claude-eval.xml,
  • write/flush JUnit after each config completes so results aren’t lost if the step is interrupted,
  • add a step-level timeout guard (~2h50m) to stop before the 3-hour limit is reached.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR adds discovery-based openshift-claude-agent-eval jobs and updates the eval step to run one or more configs, optionally limit execution to changed evals, and aggregate results into a combined JUnit report.

Changes

Claude agent eval discovery flow

Layer / File(s) Summary
Inputs and job wiring
ci-operator/step-registry/openshift/claude/agent-eval/openshift-claude-agent-eval-ref.yaml, ci-operator/config/openshift-eng/edge-tooling/openshift-eng-edge-tooling-main.yaml
Adds EVAL_DISCOVER to the step environment and adds two optional CI jobs that invoke the eval workflow with discovery, model, parallelism, and changed-only settings.
Config selection
ci-operator/step-registry/openshift/claude/agent-eval/openshift-claude-agent-eval-commands.sh
Documents EVAL_DISCOVER, builds CONFIGS_TO_RUN from discovery or EVAL_CONFIG, rejects setting both, filters discovered configs to changed evals when requested, and validates config existence in the non-discovery path.
Per-config eval execution
ci-operator/step-registry/openshift/claude/agent-eval/openshift-claude-agent-eval-commands.sh
Loops over selected configs, derives per-config run IDs and cases, runs claude with per-config arguments, and writes combined JUnit output across all configs.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding eval CI jobs for edge-tooling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Stable And Deterministic Test Names ✅ Passed PR only changes ci-operator YAML and a shell step; no Ginkgo It/Describe/Context/When titles were added or modified.
Test Structure And Quality ✅ Passed No Ginkgo test code was changed; the PR only updates ci-operator YAML and a shell eval step script, so the test-quality rubric is not applicable.
Microshift Test Compatibility ✅ Passed Touched files only add CI wiring and eval runner logic; no new Ginkgo It/Describe/Context tests or MicroShift-unsafe API use appear.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The PR only changes ci-operator YAML and an eval shell script; no Ginkgo e2e tests or SNO-sensitive test bodies were added.
Topology-Aware Scheduling Compatibility ✅ Passed PASS: The PR only changes CI job config and eval step scripts; no deployment/controller code or scheduling fields (nodeSelector/affinity/PDB) were added.
Ote Binary Stdout Contract ✅ Passed PR only changes ci-operator config and a shell step script; no OTE Go binary main/init/TestMain stdout contract code is touched.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the PR only changes CI config and an eval harness script.
No-Weak-Crypto ✅ Passed Changed files only add eval job YAML/env wiring; grep found no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or custom crypto/secret comparisons in the diff.
Container-Privileges ✅ Passed Touched CI YAML and step-registry files only add eval jobs/env vars; no privileged, hostPID/Network/IPC, SYS_ADMIN, or allowPrivilegeEscalation settings appear.
No-Sensitive-Data-In-Logs ✅ Passed Only operational metadata is logged; token handling prints presence/path, and no direct passwords, tokens, PII, or hostnames are echoed.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci
openshift-ci Bot requested review from dhensel-rh and jeff-roche July 2, 2026 10:57

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@ci-operator/config/openshift-eng/edge-tooling/openshift-eng-edge-tooling-main.yaml`:
- Around line 67-76: The eval job in openshift-claude-agent-eval is setting
EVAL_CHANGED_ONLY without a non-empty EVAL_CASES_DIR, so the changed-only path
becomes a no-op. Update the eval job definition for
eval-cluster-diagnostic-changed to either add EVAL_CASES_DIR alongside
EVAL_CONFIG and EVAL_MODEL in the env block, or remove EVAL_CHANGED_ONLY if the
intent is to run the full eval instead.

In
`@ci-operator/step-registry/lvms/zstream/trigger/lvms-zstream-trigger-commands.sh`:
- Around line 99-105: `get_last_digest` is currently treating any previously
recorded image digest as tested, even when the prior trigger run failed. Update
the logic around `get_last_digest` and the summary-write path that stores the
image after `jobs_failed > 0` so failed Gangway trigger attempts do not persist
the digest for reuse; only record the image when the run succeeds, or clear/skip
writing it on failure so the next cron run retries the same digest.
- Around line 283-289: The entry parsing in
trigger/lvms-zstream-trigger-commands.sh can still pass a trailing Prow JS
semicolon into jq, causing the lookup to fall back to unknown. Update the entry
assignment logic near the jq pipeline to strip the trailing “;” from prow_json
before parsing, matching the behavior already used by load_previous_summary, so
the JSON is valid and the last run state is extracted correctly.
- Around line 165-168: The snapshot extraction pipeline in extract_snapshot is
aborting under set -euo pipefail when grep finds no match, which prevents the
per-release error handler from running. Update the extraction logic around the
jq/grep/head pipeline so that a missing snapshot yields an empty
string/zero-status result instead of failing, while preserving the current
parsing behavior for valid matches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 5ddda36d-ab21-494e-820e-cf2b347b59b3

📥 Commits

Reviewing files that changed from the base of the PR and between d947fcf and 007eb23.

⛔ Files ignored due to path filters (1)
  • ci-operator/jobs/openshift/lvm-operator/openshift-lvm-operator-main-periodics.yaml is excluded by !ci-operator/jobs/**
📒 Files selected for processing (7)
  • ci-operator/config/openshift-eng/edge-tooling/openshift-eng-edge-tooling-main.yaml
  • ci-operator/config/openshift/lvm-operator/openshift-lvm-operator-main__zstream.yaml
  • ci-operator/step-registry/lvms/zstream/OWNERS
  • ci-operator/step-registry/lvms/zstream/trigger/OWNERS
  • ci-operator/step-registry/lvms/zstream/trigger/lvms-zstream-trigger-commands.sh
  • ci-operator/step-registry/lvms/zstream/trigger/lvms-zstream-trigger-ref.metadata.json
  • ci-operator/step-registry/lvms/zstream/trigger/lvms-zstream-trigger-ref.yaml

Comment on lines +99 to +105
get_last_digest() {
local release="$1"
if [[ -z "${PREV_SUMMARY}" ]]; then
echo ""
return
fi
jq -r --arg r "${release}" '.[$r].image // "" | split("@") | if length > 1 then .[1] else "" end' "${PREV_SUMMARY}" 2>/dev/null || echo ""

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Don’t mark a digest tested when trigger attempts failed.

get_last_digest accepts any prior image, but Line 410 writes that image even when jobs_failed > 0; the next cron run will skip the same digest instead of retrying failed Gangway triggers.

Proposed fix
-    jq -r --arg r "${release}" '.[$r].image // "" | split("@") | if length > 1 then .[1] else "" end' "${PREV_SUMMARY}" 2>/dev/null || echo ""
+    jq -r --arg r "${release}" '
+      .[$r]
+      | select((.status == "triggered" and (.jobs_failed // 0) == 0) or .status == "skipped")
+      | .image // ""
+      | split("@")
+      | if length > 1 then .[1] else "" end
+    ' "${PREV_SUMMARY}" 2>/dev/null || echo ""

Also applies to: 407-410

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/lvms/zstream/trigger/lvms-zstream-trigger-commands.sh`
around lines 99 - 105, `get_last_digest` is currently treating any previously
recorded image digest as tested, even when the prior trigger run failed. Update
the logic around `get_last_digest` and the summary-write path that stores the
image after `jobs_failed > 0` so failed Gangway trigger attempts do not persist
the digest for reuse; only record the image when the run succeeds, or clear/skip
writing it on failure so the next cron run retries the same digest.

Comment on lines +165 to +168
echo "${files_json}" | jq -r '
[.[] | select(.filename | contains("catalog")) | .patch // ""] |
join("\n")
' | grep -oP '(?<=snapshot: )\S+' | head -1

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Make snapshot extraction return empty instead of aborting.

With set -euo pipefail, grep returning no match makes snapshot=$(extract_snapshot ...) exit before the handler at Line 342 can write the intended per-release error summary.

Proposed fix
     echo "${files_json}" | jq -r '
         [.[] | select(.filename | contains("catalog")) | .patch // ""] |
         join("\n")
-    ' | grep -oP '(?<=snapshot: )\S+' | head -1
+    ' | { grep -oP '(?<=snapshot: )\S+' || true; } | head -1
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo "${files_json}" | jq -r '
[.[] | select(.filename | contains("catalog")) | .patch // ""] |
join("\n")
' | grep -oP '(?<=snapshot: )\S+' | head -1
echo "${files_json}" | jq -r '
[.[] | select(.filename | contains("catalog")) | .patch // ""] |
join("\n")
' | { grep -oP '(?<=snapshot: )\S+' || true; } | head -1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/lvms/zstream/trigger/lvms-zstream-trigger-commands.sh`
around lines 165 - 168, The snapshot extraction pipeline in extract_snapshot is
aborting under set -euo pipefail when grep finds no match, which prevents the
per-release error handler from running. Update the extraction logic around the
jq/grep/head pipeline so that a missing snapshot yields an empty
string/zero-status result instead of failing, while preserving the current
parsing behavior for valid matches.

Comment on lines +283 to +289
local entry
entry=$(echo "${prow_json}" | sed 's/^var allBuilds = //' | \
jq -r --arg n "${test_name}" '
[.items[] | select(.status.state == "success" or .status.state == "failure" or .status.state == "error" or .status.state == "aborted")] |
if length > 0 then .[0] else null end |
if . then {name: $n, state: .status.state, url: .status.url, started: .status.startTime} else {name: $n, state: "unknown"} end
' 2>/dev/null || echo "{\"name\": \"${test_name}\", \"state\": \"unknown\"}")

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Strip the trailing Prow JS semicolon here too.

load_previous_summary already removes ;$; this path does not, so jq can fail on the trailing semicolon and report every last run as unknown.

Proposed fix
-        entry=$(echo "${prow_json}" | sed 's/^var allBuilds = //' | \
+        entry=$(echo "${prow_json}" | sed 's/^var allBuilds = //; s/;$//' | \
             jq -r --arg n "${test_name}" '
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
local entry
entry=$(echo "${prow_json}" | sed 's/^var allBuilds = //' | \
jq -r --arg n "${test_name}" '
[.items[] | select(.status.state == "success" or .status.state == "failure" or .status.state == "error" or .status.state == "aborted")] |
if length > 0 then .[0] else null end |
if . then {name: $n, state: .status.state, url: .status.url, started: .status.startTime} else {name: $n, state: "unknown"} end
' 2>/dev/null || echo "{\"name\": \"${test_name}\", \"state\": \"unknown\"}")
local entry
entry=$(echo "${prow_json}" | sed 's/^var allBuilds = //; s/;$//' | \
jq -r --arg n "${test_name}" '
[.items[] | select(.status.state == "success" or .status.state == "failure" or .status.state == "error" or .status.state == "aborted")] |
if length > 0 then .[0] else null end |
if . then {name: $n, state: .status.state, url: .status.url, started: .status.startTime} else {name: $n, state: "unknown"} end
' 2>/dev/null || echo "{\"name\": \"${test_name}\", \"state\": \"unknown\"}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/lvms/zstream/trigger/lvms-zstream-trigger-commands.sh`
around lines 283 - 289, The entry parsing in
trigger/lvms-zstream-trigger-commands.sh can still pass a trailing Prow JS
semicolon into jq, causing the lookup to fall back to unknown. Update the entry
assignment logic near the jq pipeline to strip the trailing “;” from prow_json
before parsing, matching the behavior already used by load_previous_summary, so
the JSON is valid and the last run state is extracted correctly.

@kasturinarra
kasturinarra force-pushed the edge-tooling-eval-ci branch from 007eb23 to a870610 Compare July 2, 2026 11:52
@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 2, 2026
@kasturinarra

Copy link
Copy Markdown
Contributor Author

/test eval-cluster-diagnostic

@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@kasturinarra: The specified target(s) for /test were not found.
The following commands are available to trigger required jobs:

/test boskos-config
/test boskos-config-generation
/test check-gh-automation
/test check-gh-automation-tide
/test check-trigger-trusted-apps
/test ci-operator-config
/test ci-operator-config-metadata
/test ci-operator-registry
/test ci-secret-bootstrap-config-validation
/test ci-testgrid-allow-list
/test cluster-manifest-verifier
/test clusterimageset-validate
/test config
/test core-valid
/test generated-config
/test generated-dashboards
/test hyperfleet-risk-scorer-test
/test image-mirroring-config-validation
/test jira-lifecycle-config
/test labels
/test openshift-image-mirror-mappings
/test ordered-prow-config
/test owners
/test pr-reminder-config
/test prow-config
/test prow-config-filenames
/test prow-config-semantics
/test pylint
/test release-config
/test release-controller-config
/test rover-groups-config-validation
/test secret-generator-config-valid
/test services-valid
/test stackrox-stackrox-stackrox-stackrox-check
/test step-registry-metadata
/test step-registry-shellcheck
/test sync-rover-groups
/test verified-config
/test yamllint

The following commands are available to trigger optional jobs:

/test check-cluster-profiles-config

Use /test all to run the following jobs that were automatically triggered:

pull-ci-openshift-release-check-gh-automation
pull-ci-openshift-release-main-ci-operator-config
pull-ci-openshift-release-main-ci-operator-config-metadata
pull-ci-openshift-release-main-ci-operator-registry
pull-ci-openshift-release-main-config
pull-ci-openshift-release-main-core-valid
pull-ci-openshift-release-main-generated-config
pull-ci-openshift-release-main-ordered-prow-config
pull-ci-openshift-release-main-owners
pull-ci-openshift-release-main-prow-config-filenames
pull-ci-openshift-release-main-prow-config-semantics
pull-ci-openshift-release-main-release-controller-config
pull-ci-openshift-release-openshift-image-mirror-mappings
pull-ci-openshift-release-yamllint
Details

In response to this:

/test eval-cluster-diagnostic

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kasturinarra

Copy link
Copy Markdown
Contributor Author

/test eval-cluster-diagnostic

@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@kasturinarra: The specified target(s) for /test were not found.
The following commands are available to trigger required jobs:

/test boskos-config
/test boskos-config-generation
/test check-gh-automation
/test check-gh-automation-tide
/test check-trigger-trusted-apps
/test ci-operator-config
/test ci-operator-config-metadata
/test ci-operator-registry
/test ci-secret-bootstrap-config-validation
/test ci-testgrid-allow-list
/test cluster-manifest-verifier
/test clusterimageset-validate
/test config
/test core-valid
/test generated-config
/test generated-dashboards
/test hyperfleet-risk-scorer-test
/test image-mirroring-config-validation
/test jira-lifecycle-config
/test labels
/test openshift-image-mirror-mappings
/test ordered-prow-config
/test owners
/test pr-reminder-config
/test prow-config
/test prow-config-filenames
/test prow-config-semantics
/test pylint
/test release-config
/test release-controller-config
/test rover-groups-config-validation
/test secret-generator-config-valid
/test services-valid
/test stackrox-stackrox-stackrox-stackrox-check
/test step-registry-metadata
/test step-registry-shellcheck
/test sync-rover-groups
/test verified-config
/test yamllint

The following commands are available to trigger optional jobs:

/test check-cluster-profiles-config

Use /test all to run the following jobs that were automatically triggered:

pull-ci-openshift-release-check-gh-automation
pull-ci-openshift-release-main-ci-operator-config
pull-ci-openshift-release-main-ci-operator-config-metadata
pull-ci-openshift-release-main-ci-operator-registry
pull-ci-openshift-release-main-config
pull-ci-openshift-release-main-core-valid
pull-ci-openshift-release-main-generated-config
pull-ci-openshift-release-main-ordered-prow-config
pull-ci-openshift-release-main-owners
pull-ci-openshift-release-main-prow-config-filenames
pull-ci-openshift-release-main-prow-config-semantics
pull-ci-openshift-release-main-release-controller-config
pull-ci-openshift-release-openshift-image-mirror-mappings
pull-ci-openshift-release-yamllint
Details

In response to this:

/test eval-cluster-diagnostic

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kasturinarra
kasturinarra force-pushed the edge-tooling-eval-ci branch from a870610 to 1c5c4dc Compare July 2, 2026 17:27
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kasturinarra
kasturinarra force-pushed the edge-tooling-eval-ci branch from 1c5c4dc to ffe9d4a Compare July 2, 2026 17:28
@openshift-ci openshift-ci Bot removed the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 2, 2026
When EVAL_DISCOVER is set ("true" or a glob pattern), the workflow
auto-discovers eval configs, diffs against PULL_BASE_SHA to run only
affected evals, and produces per-eval JUnit test cases. Single
EVAL_CONFIG mode is preserved for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kasturinarra
kasturinarra force-pushed the edge-tooling-eval-ci branch from 2ed5fe3 to 2ce7768 Compare July 2, 2026 17:52

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@ci-operator/step-registry/openshift/claude/agent-eval/openshift-claude-agent-eval-commands.sh`:
- Around line 207-216: The per-config eval in
`openshift-claude-agent-eval-commands.sh` still uses a fixed `timeout 7200`
inside the serial `CONFIGS_TO_RUN` loop, which can overrun the overall step
budget and prevent the final JUnit output from being written. Update the timeout
logic around the `claude` invocation in the discovery-mode loop to use the
remaining time budget per config, or otherwise write JUnit results incrementally
so each run is preserved even if later configs hit the step limit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 6a6cf46f-d381-4301-bf14-55a7f0802c1f

📥 Commits

Reviewing files that changed from the base of the PR and between ffe9d4a and 2ce7768.

⛔ Files ignored due to path filters (1)
  • ci-operator/jobs/openshift-eng/edge-tooling/openshift-eng-edge-tooling-main-presubmits.yaml is excluded by !ci-operator/jobs/**
📒 Files selected for processing (3)
  • ci-operator/config/openshift-eng/edge-tooling/openshift-eng-edge-tooling-main.yaml
  • ci-operator/step-registry/openshift/claude/agent-eval/openshift-claude-agent-eval-commands.sh
  • ci-operator/step-registry/openshift/claude/agent-eval/openshift-claude-agent-eval-ref.yaml

Write JUnit XML after each eval config completes so results are
preserved if the step gets killed mid-loop. Add a step-level time
guard (2h50m) to skip remaining configs before hitting the 3h limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dhensel-rh

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 8, 2026
@kasturinarra

Copy link
Copy Markdown
Contributor Author

@stbenjam could you please help review ? thanks !!

@not-stbenjam

not-stbenjam commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Deep Review Verdict

Disposition: REQUEST_CHANGES — 2 reproduced bugs require fixes before merge


Specialist Findings

Bugs: Found timeout guard timing issues (STEP_START set too late, per-eval timeout not adjusted for remaining time), timeout-skipped configs silently reporting success, artifact overwrites in multi-config mode, and regex metacharacters in grep filter. No BLOCKING findings — all rated SUGGESTION/NOTE.

Adversarial: Found 2 BLOCKING bugs, both confirmed by reproducers:

  1. config_name collision when two plugins share a config filename — log files overwrite each other, JUnit names collide
  2. EVAL_CHANGED_ONLY regression in non-discovery mode — running all cases instead of skipping when nothing changed

Also flagged timeout overshoot, regex escaping, and zero-discovery silent success.

Security & Supply Chain: Flagged unpinned git clone of opendatahub-io/agent-eval-harness as a supply chain risk. Note: this is pre-existing code, not introduced by this branch. Also noted regex injection in grep, unvalidated EVAL_EXTRA_ARGS passthrough, and JUnit XML escaping gaps.

Architecture: Independently corroborated the config_name collision as BLOCKING. Also flagged timeout-skipped configs reporting silent success and artifact file overwrites in multi-config mode.

Codebase Consistency: Found stale model defaults in header comments (claude-sonnet-4-6 vs actual claude-opus-4-6), missing EVAL_CHANGED_ONLY and EVAL_CASES_DIR docs in header, and redundant -name filter in the find command. All SUGGESTION/NOTE.

QA Engineer: Found nounset safety issues (${EVAL_CHANGED_ONLY} without :- guard), printf on potentially empty array, per-config timeout not adjusted for remaining budget, and JUnit gaps for skipped configs. Also noted EVAL_SETUP_SCRIPT stdout capture fragility.

Technical Writer: Found model defaults in header comments contradict ref.yaml, EVAL_CONFIG incorrectly labeled as "Required", EVAL_CHANGED_ONLY and EVAL_CASES_DIR missing from header, and ref.yaml documentation field doesn't mention discovery mode.

Panel Synthesis

Two independently discovered bugs are confirmed by runtime reproducers:

Bug 1 — config_name collision (Architecture + Adversarial corroborated, reproducer confirmed): When plugins/alpha/evals/test.yaml and plugins/beta/evals/test.yaml both exist, basename produces test for both. The second eval's log silently overwrites the first, JUnit shows duplicate test names, and RUN_IDs can collide. This is the most impactful bug — it causes silent data loss in the primary use case (discovery mode with eval-all).

Bug 2 — EVAL_CHANGED_ONLY regression (Adversarial, reproducer confirmed): The old code had an explicit early-exit when EVAL_CHANGED_ONLY=true and no cases changed. The refactor removed this path. In non-discovery mode, no changed cases now means "run everything" — the exact opposite of the intent. While current CI configs use discovery mode (which has its own filtering at line 86), this is a behavioral regression for any external consumer using the old EVAL_CHANGED_ONLY + EVAL_CASES_DIR pattern.

The unpinned git clone (Security, BLOCKING) is a legitimate supply-chain concern but is pre-existing code unchanged by this PR — it should not block this merge but warrants a follow-up.

The timeout guard issues were found by 4 specialists independently (Bugs, Adversarial, QA, Architecture), giving high confidence. The per-eval timeout can exceed remaining step time, and skipped configs produce no JUnit signal. These are SUGGESTION severity — the 3h Prow limit is a hard backstop — but worth addressing.

The regex metacharacters issue was found by 6 of 7 specialists. Practically low-risk given naming conventions, but technically incorrect.

The documentation findings (stale model defaults, missing env vars) were corroborated by Writer, Consistency, and Architecture.


Required Actions Before Merge

  1. Fix config_name collision (commands.sh:179): Derive a unique slug from the full config path instead of just basename. For example: config_name=$(echo "${config}" | tr '/' '-' | sed 's/\.yaml$//') or include the parent directory. Apply to log filename (line 232), JUnit testcase name (line 236), and RUN_ID (line 185).

    Reproducer

    Steps: Created two configs at plugins/alpha/evals/test.yaml and plugins/beta/evals/test.yaml, ran the discovery + eval loop.
    Expected: 2 distinct log files, 2 unique JUnit test names.
    Actual: 1 log file (alpha's overwritten by beta), 2 identical JUnit names [sig-claude] test evaluation.

  2. Fix EVAL_CHANGED_ONLY regression (commands.sh:189-212): After the per-config case detection block, add early continue when EVAL_CHANGED_ONLY=true and no cases were detected:

    if [[ "${EVAL_CHANGED_ONLY:-}" == "true" ]] && [[ -z "${CASE_ARGS}" ]] && [[ -z "${EVAL_CASES}" ]]; then
        echo "No changed cases for ${config_name}, skipping."
        continue
    fi
    Reproducer

    Steps: Set EVAL_CHANGED_ONLY=true, EVAL_DISCOVER=, EVAL_CASES_DIR=cases, EVAL_CASES=, with no changed case files in git diff.
    Expected: Eval is skipped ("No changed cases detected, skipping").
    Actual: CASE_ARGS remains empty, eval runs ALL cases.


Optional Follow-ups

  • Timeout guard improvements: Set STEP_START at script top; compute dynamic per-eval timeout as min(7200, remaining_budget); add <skipped> JUnit entries for timeout-skipped configs
  • Artifact overwrites: Include config name in copied artifact filenames for multi-config mode
  • nounset guards: Use ${EVAL_CHANGED_ONLY:-} pattern on lines 70, 189, 193, 211, 217, 218
  • Regex escaping: Switch grep -qE to grep -qF on line 80, or escape metacharacters
  • Documentation: Update header comment model defaults to claude-opus-4-6; add EVAL_CHANGED_ONLY, EVAL_CASES_DIR to header; update ref.yaml documentation field
  • Supply chain (pre-existing): Pin agent-eval-harness git clone to a specific commit hash

Stats

Arbiter summary: 35 findings from 7 specialists.
Kept: 2 blocking (2 reproduced), 14 suggestions/notes.
Dropped: 19 duplicates (regex escaping found by 6 specialists, timeout issues by 4, stale docs by 3, artifact overwrite by 3).

Generated by /deep-review

@not-stbenjam

Copy link
Copy Markdown
Contributor

Thanks for writing up the changed functionality, it looks good. Claude has 2 bugs that are worth fixing above ^

Derive config_name from full path (tr '/' '-') instead of basename to
prevent log/JUnit/RUN_ID collisions when multiple configs share the
same filename. Also add early continue when EVAL_CHANGED_ONLY is set
but no changed cases are detected, preventing unintended full eval runs.
Use consistent ${EVAL_CHANGED_ONLY:-} across all references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label Jul 8, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

[REHEARSALNOTIFIER]
@kasturinarra: the pj-rehearse plugin accommodates running rehearsal tests for the changes in this PR. Expand 'Interacting with pj-rehearse' for usage details. The following rehearsable tests have been affected by this change:

Test name Repo Type Reason
pull-ci-openshift-eng-edge-tooling-main-eval-all openshift-eng/edge-tooling presubmit Presubmit changed
pull-ci-openshift-eng-edge-tooling-main-eval-changed openshift-eng/edge-tooling presubmit Presubmit changed
pull-ci-openshift-eng-ai-helpers-main-eval-payload-analysis openshift-eng/ai-helpers presubmit Registry content changed
pull-ci-openshift-eng-ai-helpers-main-eval-payload-analysis-changed openshift-eng/ai-helpers presubmit Registry content changed
pull-ci-openshift-eng-ai-helpers-main-eval-payload-analysis-minimal openshift-eng/ai-helpers presubmit Registry content changed
pull-ci-openshift-eng-ai-helpers-main-eval-prow-job-analysis openshift-eng/ai-helpers presubmit Registry content changed
pull-ci-openshift-eng-ai-helpers-main-eval-prow-job-analysis-minimal openshift-eng/ai-helpers presubmit Registry content changed
pull-ci-openshift-eng-ai-helpers-main-eval-classify-review-comment openshift-eng/ai-helpers presubmit Registry content changed
pull-ci-openshift-eng-ai-helpers-main-eval-address-reviews openshift-eng/ai-helpers presubmit Registry content changed
periodic-ci-openshift-eng-ai-helpers-main-periodics-eval-payload-analysis N/A periodic Registry content changed
Interacting with pj-rehearse

Comment: /pj-rehearse to run up to 5 rehearsals
Comment: /pj-rehearse skip to opt-out of rehearsals
Comment: /pj-rehearse {test-name}, with each test separated by a space, to run one or more specific rehearsals
Comment: /pj-rehearse more to run up to 10 rehearsals
Comment: /pj-rehearse max to run up to 25 rehearsals
Comment: /pj-rehearse auto-ack to run up to 5 rehearsals, and add the rehearsals-ack label on success
Comment: /pj-rehearse list to get an up-to-date list of affected jobs
Comment: /pj-rehearse abort to abort all active rehearsals
Comment: /pj-rehearse network-access-allowed to allow rehearsals of tests that have the restrict_network_access field set to false. This must be executed by an openshift org member who is not the PR author

Once you are satisfied with the results of the rehearsals, comment: /pj-rehearse ack to unblock merge. When the rehearsals-ack label is present on your PR, merge will no longer be blocked by rehearsals.
If you would like the rehearsals-ack label removed, comment: /pj-rehearse reject to re-block merging.

@kasturinarra

Copy link
Copy Markdown
Contributor Author

Thanks for writing up the changed functionality, it looks good. Claude has 2 bugs that are worth fixing above ^

@stbenjam done with fixing the issue, would you mind taking another look ? thanks !!

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

@not-stbenjam: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

@stbenjam

stbenjam commented Jul 9, 2026

Copy link
Copy Markdown
Member

/pj-rehearse pull-ci-openshift-eng-ai-helpers-main-eval-payload-analysis-minimal pull-ci-openshift-eng-ai-helpers-main-eval-prow-job-analysis pull-ci-openshift-eng-ai-helpers-main-eval-address-reviews

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

@stbenjam: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

@kasturinarra: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/rehearse/openshift-eng/ai-helpers/main/eval-prow-job-analysis 188e695 link unknown /pj-rehearse pull-ci-openshift-eng-ai-helpers-main-eval-prow-job-analysis

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@kasturinarra

Copy link
Copy Markdown
Contributor Author

@stbenjam addressed the comments, would you mind taking a look ? I looked at the failure and it looked like not caused by the changes in the PR ?

@kasturinarra

Copy link
Copy Markdown
Contributor Author

@stbenjam hey, i see the PR you referenced is failing for version bump and if we can get that fixed, we could merge this as well may be ? Just wanted to have this merged so that our team can start writing evals and have them running...

@stbenjam

stbenjam commented Jul 23, 2026

Copy link
Copy Markdown
Member

Would you mind to /lgtm openshift-eng/ai-helpers#633 and then re-run the eval-prow-job-analysis job here (about 10 minutes after it merges to ai-helpers)

@stbenjam

Copy link
Copy Markdown
Member

Actually the other evals passed so I think this is fine, thanks!

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 23, 2026
@openshift-ci

openshift-ci Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dhensel-rh, kasturinarra, stbenjam

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 23, 2026
@kasturinarra

Copy link
Copy Markdown
Contributor Author

/pj-rehearse ack

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

@kasturinarra: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

@openshift-merge-bot openshift-merge-bot Bot added the rehearsals-ack Signifies that rehearsal jobs have been acknowledged label Jul 23, 2026
@openshift-merge-bot
openshift-merge-bot Bot merged commit 1b1b4a8 into openshift:main Jul 23, 2026
20 of 21 checks passed
apahim pushed a commit to apahim/release that referenced this pull request Jul 24, 2026
* Add eval discovery mode to agent-eval workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add EVAL_DISCOVER support to agent-eval workflow

When EVAL_DISCOVER is set ("true" or a glob pattern), the workflow
auto-discovers eval configs, diffs against PULL_BASE_SHA to run only
affected evals, and produces per-eval JUnit test cases. Single
EVAL_CONFIG mode is preserved for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add incremental JUnit writes and step timeout guard

Write JUnit XML after each eval config completes so results are
preserved if the step gets killed mid-loop. Add a step-level time
guard (2h50m) to skip remaining configs before hitting the 3h limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix config_name collision and EVAL_CHANGED_ONLY skip logic

Derive config_name from full path (tr '/' '-') instead of basename to
prevent log/JUnit/RUN_ID collisions when multiple configs share the
same filename. Also add early continue when EVAL_CHANGED_ONLY is set
but no changed cases are detected, preventing unintended full eval runs.
Use consistent ${EVAL_CHANGED_ONLY:-} across all references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
mrniranjan pushed a commit to mrniranjan/release that referenced this pull request Jul 28, 2026
* Add eval discovery mode to agent-eval workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add EVAL_DISCOVER support to agent-eval workflow

When EVAL_DISCOVER is set ("true" or a glob pattern), the workflow
auto-discovers eval configs, diffs against PULL_BASE_SHA to run only
affected evals, and produces per-eval JUnit test cases. Single
EVAL_CONFIG mode is preserved for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add incremental JUnit writes and step timeout guard

Write JUnit XML after each eval config completes so results are
preserved if the step gets killed mid-loop. Add a step-level time
guard (2h50m) to skip remaining configs before hitting the 3h limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix config_name collision and EVAL_CHANGED_ONLY skip logic

Derive config_name from full path (tr '/' '-') instead of basename to
prevent log/JUnit/RUN_ID collisions when multiple configs share the
same filename. Also add early continue when EVAL_CHANGED_ONLY is set
but no changed cases are detected, preventing unintended full eval runs.
Use consistent ${EVAL_CHANGED_ONLY:-} across all references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
amogh-redhat pushed a commit to amogh-redhat/release that referenced this pull request Aug 5, 2026
* Add eval discovery mode to agent-eval workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add EVAL_DISCOVER support to agent-eval workflow

When EVAL_DISCOVER is set ("true" or a glob pattern), the workflow
auto-discovers eval configs, diffs against PULL_BASE_SHA to run only
affected evals, and produces per-eval JUnit test cases. Single
EVAL_CONFIG mode is preserved for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add incremental JUnit writes and step timeout guard

Write JUnit XML after each eval config completes so results are
preserved if the step gets killed mid-loop. Add a step-level time
guard (2h50m) to skip remaining configs before hitting the 3h limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix config_name collision and EVAL_CHANGED_ONLY skip logic

Derive config_name from full path (tr '/' '-') instead of basename to
prevent log/JUnit/RUN_ID collisions when multiple configs share the
same filename. Also add early continue when EVAL_CHANGED_ONLY is set
but no changed cases are detected, preventing unintended full eval runs.
Use consistent ${EVAL_CHANGED_ONLY:-} across all references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
TimurMP pushed a commit to TimurMP/release that referenced this pull request Sep 5, 2026
* Add eval discovery mode to agent-eval workflow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add EVAL_DISCOVER support to agent-eval workflow

When EVAL_DISCOVER is set ("true" or a glob pattern), the workflow
auto-discovers eval configs, diffs against PULL_BASE_SHA to run only
affected evals, and produces per-eval JUnit test cases. Single
EVAL_CONFIG mode is preserved for backward compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add incremental JUnit writes and step timeout guard

Write JUnit XML after each eval config completes so results are
preserved if the step gets killed mid-loop. Add a step-level time
guard (2h50m) to skip remaining configs before hitting the 3h limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix config_name collision and EVAL_CHANGED_ONLY skip logic

Derive config_name from full path (tr '/' '-') instead of basename to
prevent log/JUnit/RUN_ID collisions when multiple configs share the
same filename. Also add early continue when EVAL_CHANGED_ONLY is set
but no changed cases are detected, preventing unintended full eval runs.
Use consistent ${EVAL_CHANGED_ONLY:-} across all references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. rehearsals-ack Signifies that rehearsal jobs have been acknowledged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants