Skip to content

Add analyze-payload command and improve CI skills - #341

Merged
openshift-merge-bot[bot] merged 7 commits into
openshift-eng:mainfrom
stbenjam:analyze-payload
Feb 27, 2026
Merged

openshift-merge-bot[bot] merged 7 commits into
openshift-eng:mainfrom
stbenjam:analyze-payload

Conversation

@stbenjam

@stbenjam stbenjam commented Feb 27, 2026

Copy link
Copy Markdown
Member

Summary

  • fetch-new-prs-in-payload fallback: Falls back to the release controller API when Sippy hasn't ingested the payload yet (e.g., in-progress or very recent payloads)
  • Aggregated job awareness: analyze-test-failure now understands aggregated jobs and their three failure modes (statistically significant failure, insufficient completed runs, non-deterministic test presence)
  • Copy-paste revert instructions: When analyze-payload recommends a revert, the HTML report includes a ready-to-paste block with evidence summary and /ci:revert-pr command

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Interactive copy-paste revert instructions with a dedicated UI block, copy button, multi-job placeholders and improved revert recommendations.
    • Dual-source PR fetching with automatic fallback to a secondary API when the primary source is unavailable.
  • Documentation

    • Guidance for detecting and analyzing aggregated job failures with three failure modes.
    • Expanded PR data-source docs with explicit endpoints, parameters, response schemas and clearer notes; minor editorial tweaks.
  • Chores

    • Plugin version bumped to 0.0.12.

stbenjam and others added 3 commits February 27, 2026 12:33
Sippy only ingests payloads after they complete, so in-progress or very
recent payloads are unavailable. The script now tries Sippy first and
automatically falls back to the release controller API, which has the
data immediately but with shorter retention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Aggregated jobs run the same test in parallel and do statistical analysis,
which produces different failure modes than normal jobs. Document how to
detect aggregation, the three failure modes (statistically significant
failure, insufficient completed runs, non-deterministic test presence),
and how to find underlying job run URLs via junit-aggregated.xml.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the payload analysis recommends a revert, the HTML report now
includes a ready-to-paste block with the PR, affected jobs, evidence
summary, and /ci:revert-pr command. Includes a copy button for
convenience.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 27, 2026
@coderabbitai

coderabbitai Bot commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds an interactive, copyable revert UI in payload analysis, implements resilient dual-source PR fetching (Sippy first, release-controller fallback) with new helpers, and inserts aggregated-job detection and analysis guidance into prow-job test-failure skill.

Changes

Cohort / File(s) Summary
Interactive Revert UI
plugins/ci/skills/analyze-payload/SKILL.md, plugins/ci/commands/analyze-payload.md
Replaces plain-text revert note with an interactive "Revert Instructions" block and copy button, adds CSS for .revert-prompt, removes the old .revert-note, restructures "Recommended Reverts" and "no revert" variants to support multiple jobs and Evidence, and minor Contents editorial tweak.
Dual-Source PR Fetching
plugins/ci/skills/fetch-new-prs-in-payload/SKILL.md, plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py
Introduces fetch_new_prs() that tries fetch_from_sippy() then falls back to fetch_from_release_controller(). Adds helpers _http_get_json(), _parse_stream(), _find_previous_tag(), normalizes PR output, updates docs with Data Sources, Sippy endpoint schema, parameters, and fallback notes.
Aggregated Job Detection
plugins/ci/skills/prow-job-analyze-test-failure/SKILL.md
Adds Step 4.0 to detect aggregated jobs (name prefix or aggregator container/step), defines three aggregated-job failure modes, recommends mode-specific analysis focus, and documents locating underlying runs via aggregated JUnit XML fields (jobrunid, humanurl, gcsartifacturl).
Version Bumps / Metadata
.claude-plugin/marketplace.json, docs/data.json, plugins/ci/.claude-plugin/plugin.json
Bumps plugin version from 0.0.11 to 0.0.12 in plugin metadata and docs; purely metadata updates with no behavioral changes.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Fetch as fetch_new_prs()
    participant Sippy as Sippy API
    participant RC as Release Controller API

    Client->>Fetch: fetch_new_prs(payload_tag)
    Fetch->>Sippy: fetch_from_sippy(payload_tag)
    alt Sippy returns PRs
        Sippy-->>Fetch: PR list
        Fetch-->>Client: PR list
    else Sippy missing/failure
        Fetch->>RC: fetch_from_release_controller(payload_tag)
        RC-->>Fetch: PR list (from changelog)
        Fetch-->>Client: PR list (with fallback warning)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

🚥 Pre-merge checks | ✅ 8
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding a new analyze-payload command and improving CI skills with enhanced capabilities.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
No Real People Names In Style References ✅ Passed The PR contains no real people names used as style references in any modified files; all documentation uses technical language only.
No Assumed Git Remote Names ✅ Passed Comprehensive search across all markdown, Python, and JSON files found no hardcoded git remote names (origin/upstream) in any git commands or instructions.
Git Push Safety Rules ✅ Passed No git push operations or autonomous pushing logic detected in any modified Python, markdown, or configuration files within the pull request.
No Untrusted Mcp Servers ✅ Passed The pull request does not introduce any MCP server installations from untrusted or any other sources. Changes consist of documentation updates, Python code utilizing only standard library modules, and configuration updates.
Ai-Helpers Overlap Detection ✅ Passed Systematic semantic analysis confirms analyze-payload introduces novel payload-level orchestration functionality with only ~40% similarity to most related command (analyze-regression), well below the 60% MODERATE overlap threshold.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

stbenjam and others added 2 commits February 27, 2026 12:49
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@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: 6

🧹 Nitpick comments (2)
plugins/ci/skills/analyze-payload/SKILL.md (2)

273-273: Document clipboard API requirements.

The navigator.clipboard.writeText API requires a secure context (HTTPS or localhost) and is not supported in older browsers (IE11, older Safari versions). Consider adding a note in the documentation that the HTML report requires a modern browser and secure context for the Copy functionality to work, or provide fallback guidance (e.g., "If the Copy button doesn't work, manually select and copy the text").

📋 Suggested documentation note

After line 283 or in the "Notes" section (line 476), add:

**Note**: The Copy button uses the Clipboard API, which requires:
- A modern browser (Chrome 63+, Firefox 53+, Safari 13.1+, Edge 79+)
- A secure context (HTTPS or localhost)

If the Copy button does not work, users can manually select and copy the text from the code block.

Also applies to: 302-316

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/ci/skills/analyze-payload/SKILL.md` at line 273, The documentation
lacks a note that the Copy button's onclick handler uses
navigator.clipboard.writeText which requires a secure context and modern browser
support; update SKILL.md to document these Clipboard API requirements and add
fallback guidance: state that the Copy button needs HTTPS or localhost and
modern browsers (give brief version constraints or "modern browser"), and add an
instruction like "If the Copy button doesn't work, manually select and copy the
text" near the existing Copy button examples (the button element with
onclick="navigator.clipboard.writeText(...)") and in the Notes section so users
know why copying may fail and how to proceed.

285-287: Clarify CSS placement for implementers.

The instruction "Add the following styles for the revert prompt block" doesn't specify where in the existing <style> section (described in Section 7.5) these rules should be placed. While CSS order typically doesn't matter for these selectors, explicit guidance would help implementers.

📝 Suggested clarification
-Add the following styles for the revert prompt block:
+Add the following styles to the `<style>` section (described in Section 7.5, before the closing `</style>` tag):
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/ci/skills/analyze-payload/SKILL.md` around lines 285 - 287, The doc
asks to "Add the following styles for the revert prompt block" but doesn't say
where to place them; update SKILL.md to explicitly instruct implementers to
insert those CSS rules into the existing <style> block referenced in Section 7.5
(preferably alongside other prompt/block styles or appended to the end of that
<style> section) so the rules for the "revert prompt block" are colocated with
related prompt styles; mention the specific target (the <style> section
described in Section 7.5 and the "revert prompt block" selectors) so
implementers know exactly where to put the new rules.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/ci/skills/analyze-payload/SKILL.md`:
- Around line 269-283: Update the revert UI block to add an accessible label on
the copy button and clarify the repeated-heading structure: add aria-label="Copy
revert command" (or aria-label="Copy revert command for PR #{pr_number}" when
iterating) to the <button> in the .revert-prompt block so screen readers
announce the action, and ensure only one <h3>Revert Instructions</h3> heading
appears before multiple .revert-prompt blocks (i.e., render one top-level <h3>
and then repeat the .revert-prompt <div> for each revert candidate) rather than
repeating the heading for every candidate; update the template variables
(pr_url, originating_payload_tag, job_name_*) used inside each .revert-prompt
accordingly so each button’s aria-label can reference the specific PR when
available.

In `@plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py`:
- Around line 140-143: The fallback print message in fetch_new_prs_in_payload.py
is too specific ("Sippy does not have payload '{payload_tag}'") although
fetch_from_sippy can fall back for connectivity and unexpected-response cases;
update the print in the fallback path (the print call that references
payload_tag) to use a generic warning such as "Falling back to release
controller for payload '{payload_tag}'" and include context (e.g., the error or
status) when available from fetch_from_sippy so the message correctly covers all
fallback reasons and points to fetch_from_sippy and the payload_tag variable for
where to change it.
- Around line 88-95: The call to _find_previous_tag in fetch_new_prs_in_payload
can raise network/HTTP exceptions (the I/O happens inside _find_previous_tag)
and currently runs outside the controlled exit path; wrap the call to
_find_previous_tag(stream, payload_tag) in a try/except that catches
network-related exceptions (e.g., requests.exceptions.RequestException or a
broad Exception if requests isn't directly imported) and on exception print the
same stderr message and call sys.exit(1) (the same behavior used when prev_tag
is falsy), so both lookup failures and network errors follow the identical
controlled error path.
- Around line 121-123: The fallback currently derives bug_url from only
commit.get("issues", {}) which misses release-controller payloads that use
"bugs"; update the logic in fetch_new_prs_in_payload.py where issues and bug_url
are computed (around the commit handling block) to merge both
commit.get("issues", {}) and commit.get("bugs", {}) (or prefer one over the
other) before calling next(iter(...)) so bug links from either field are
captured when building prs in the prs.append block.

In `@plugins/ci/skills/fetch-new-prs-in-payload/SKILL.md`:
- Line 140: Update the documentation sentence that claims the fallback is
“transparent” to accurately reflect runtime behavior: change the phrasing near
the existing line that contains the word “transparent” to state that a fallback
warning is emitted to stderr when the fallback is used (i.e., it’s automatic but
not silent); ensure the new wording mentions “fallback warning to stderr” so it
matches the actual stderr behavior described in the code.

In `@plugins/ci/skills/prow-job-analyze-test-failure/SKILL.md`:
- Around line 120-122: The fenced code block containing the GCS path string (the
block showing gs://test-platform-results/{bucket-path}/.../junit-aggregated.xml)
is missing a language tag; update that fenced block to include a language
identifier (e.g., add "text" after the opening ```), so the block becomes
```text ... ``` to satisfy Markdown best practices and render correctly in
SKILL.md.

---

Nitpick comments:
In `@plugins/ci/skills/analyze-payload/SKILL.md`:
- Line 273: The documentation lacks a note that the Copy button's onclick
handler uses navigator.clipboard.writeText which requires a secure context and
modern browser support; update SKILL.md to document these Clipboard API
requirements and add fallback guidance: state that the Copy button needs HTTPS
or localhost and modern browsers (give brief version constraints or "modern
browser"), and add an instruction like "If the Copy button doesn't work,
manually select and copy the text" near the existing Copy button examples (the
button element with onclick="navigator.clipboard.writeText(...)") and in the
Notes section so users know why copying may fail and how to proceed.
- Around line 285-287: The doc asks to "Add the following styles for the revert
prompt block" but doesn't say where to place them; update SKILL.md to explicitly
instruct implementers to insert those CSS rules into the existing <style> block
referenced in Section 7.5 (preferably alongside other prompt/block styles or
appended to the end of that <style> section) so the rules for the "revert prompt
block" are colocated with related prompt styles; mention the specific target
(the <style> section described in Section 7.5 and the "revert prompt block"
selectors) so implementers know exactly where to put the new rules.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 886e802 and 9821ca0.

📒 Files selected for processing (4)
  • plugins/ci/skills/analyze-payload/SKILL.md
  • plugins/ci/skills/fetch-new-prs-in-payload/SKILL.md
  • plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py
  • plugins/ci/skills/prow-job-analyze-test-failure/SKILL.md

Comment thread plugins/ci/skills/analyze-payload/SKILL.md
Comment thread plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py Outdated
Comment thread plugins/ci/skills/fetch-new-prs-in-payload/SKILL.md
Comment thread plugins/ci/skills/prow-job-analyze-test-failure/SKILL.md

def fetch_from_sippy(payload_tag: str) -> Optional[list]:
"""Try fetching PR diff from Sippy. Returns None if the payload is not available."""
url = f"{SIPPY_API_BASE}/payloads/diff?toPayload={urllib.parse.quote(payload_tag)}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea I guess so, that's existing code here. I only added fallback to the release controller, the diff is indentation changes

stbenjam and others added 2 commits February 27, 2026 14:41
Instruct Claude to use target="_blank" on all anchor tags in the
generated payload analysis HTML report.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap the call to _find_previous_tag in a try/except for urllib
HTTP/URL errors so network failures follow the same controlled
exit path as a missing previous tag.

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

@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.

🧹 Nitpick comments (2)
plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py (2)

109-116: Consider catching json.JSONDecodeError here as well.

Similar to the Sippy path, if the release controller returns malformed JSON, this would crash with an unhandled exception rather than providing a controlled error message.

🛡️ Proposed fix
     try:
         data = _http_get_json(url, timeout=60)
     except urllib.error.HTTPError as e:
         print(f"Error: HTTP {e.code} from release controller: {e.reason}", file=sys.stderr)
         sys.exit(1)
     except urllib.error.URLError as e:
         print(f"Error: Failed to connect to release controller: {e.reason}", file=sys.stderr)
         sys.exit(1)
+    except json.JSONDecodeError as e:
+        print(f"Error: Invalid JSON response from release controller: {e}", file=sys.stderr)
+        sys.exit(1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py`
around lines 109 - 116, Add handling for malformed JSON in the try/except around
the _http_get_json call: catch json.JSONDecodeError in the same block that
currently catches urllib.error.HTTPError and urllib.error.URLError, log a clear
error message to stderr (similar style to the existing prints) and call
sys.exit(1). Ensure the json module is available where this code runs (import
json if not already) and reference the existing call/site around
_http_get_json(url, timeout=60) to locate where to add the new except branch.

56-61: Consider catching json.JSONDecodeError for fallback robustness.

If Sippy returns malformed JSON, json.loads in _http_get_json raises JSONDecodeError, which isn't caught here. This would crash instead of gracefully falling back to the release controller.

🛡️ Proposed fix
     try:
         data = _http_get_json(url)
     except urllib.error.HTTPError:
         return None
     except urllib.error.URLError:
         return None
+    except json.JSONDecodeError:
+        return None
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py`
around lines 56 - 61, The try/except around the call to _http_get_json currently
only catches urllib.error.HTTPError and urllib.error.URLError; add a handler for
json.JSONDecodeError as well so malformed JSON from Sippy is treated the same
way (return None) instead of raising; update the except block that references
_http_get_json to include json.JSONDecodeError and ensure json is imported if
not already.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py`:
- Around line 109-116: Add handling for malformed JSON in the try/except around
the _http_get_json call: catch json.JSONDecodeError in the same block that
currently catches urllib.error.HTTPError and urllib.error.URLError, log a clear
error message to stderr (similar style to the existing prints) and call
sys.exit(1). Ensure the json module is available where this code runs (import
json if not already) and reference the existing call/site around
_http_get_json(url, timeout=60) to locate where to add the new except branch.
- Around line 56-61: The try/except around the call to _http_get_json currently
only catches urllib.error.HTTPError and urllib.error.URLError; add a handler for
json.JSONDecodeError as well so malformed JSON from Sippy is treated the same
way (return None) instead of raising; update the except block that references
_http_get_json to include json.JSONDecodeError and ensure json is imported if
not already.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 7aaa3e0 and 3250439.

📒 Files selected for processing (1)
  • plugins/ci/skills/fetch-new-prs-in-payload/fetch_new_prs_in_payload.py

@neisw

neisw commented Feb 27, 2026

Copy link
Copy Markdown

/lgtm

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

openshift-ci Bot commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: neisw, 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

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants