Skip to content

USHIFT-7328: CI Doctor: prow-job-analyzer agent + hook ensuring correct output JSON - #226

Merged
openshift-merge-bot[bot] merged 6 commits into
openshift-eng:mainfrom
pmtk:prow-job-analyzer-agent-w-hook
Jul 16, 2026
Merged

USHIFT-7328: CI Doctor: prow-job-analyzer agent + hook ensuring correct output JSON#226
openshift-merge-bot[bot] merged 6 commits into
openshift-eng:mainfrom
pmtk:prow-job-analyzer-agent-w-hook

Conversation

@pmtk

@pmtk pmtk commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

report-microshift-ci-doctor.html

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added an agent-driven root-cause analysis workflow that outputs machine-consumable JSON array reports per CI job, including tightened evidence and confidence fields.
  • Improvements

    • Updated doctor, prow-job analysis, bug search, session continuation, and aggregation to consume .json job artifacts (with updated counting and discovery rules).
    • Refreshed MicroShift CI skill documentation to enforce JSON-only output and structured evidence formatting.
  • Bug Fixes

    • Improved parsing to load JSON-first and reliably extract valid JSON arrays when embedded.
    • Normalized null-like string fields to empty strings for more consistent downstream output.
  • Chores

    • Bumped plugin versions in the marketplace manifests.

@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: pmtk

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 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The PR replaces text-based CI Doctor RCA reports with strict JSON arrays, adds a MicroShift analyzer and output validator, updates workflow persistence, and migrates parsing, aggregation, bug search, continuation, documentation, and plugin versions to the JSON report format.

Changes

JSON RCA reporting pipeline

Layer / File(s) Summary
Analyzer contract and evidence workflow
plugins/microshift-ci/agents/..., plugins/microshift-ci/agents/references/..., plugins/lvms-ci/skills/prow-job/SKILL.md
Defines artifact investigation, causal-chain evidence, confidence fields, and strict JSON-array output requirements.
RCA validation hook
plugins/microshift-ci/.claude/settings.json, plugins/microshift-ci/scripts/validate-rca-output.py
Validates JSON structure, allowed values, causal-chain evidence, and cited filesystem lines.
Analyzer orchestration and persistence
plugins/microshift-ci/skills/{doctor,prow-job}/*, plugins/lvms-ci/skills/{doctor,prow-job}/*
Invokes prow-job-analyzer, passes artifact context, and saves per-job JSON responses.
JSON parsing and downstream consumers
plugins/shared/scripts/*, plugins/microshift-ci/scripts/*, plugins/microshift-ci/skills/{continue-session,create-bugs}/*
Updates report discovery, parsing fallback behavior, aggregation, counts, bug search, and documentation for JSON files.
Plugin version updates
.claude-plugin/marketplace.json, plugins/*/.claude-plugin/plugin.json
Bumps the LVMS CI and MicroShift CI plugin versions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: ready-for-human-review

🚥 Pre-merge checks | ✅ 9 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Ai-Attribution ⚠️ Warning PR introduces/mentions AI agent work, but no Assisted-by/Generated-by trailer appears in commits or diff. Add a Red Hat Assisted-by or Generated-by trailer to the relevant commit(s)/PR; do not use Co-Authored-By for AI assistance.
✅ Passed checks (9 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 change: adding the prow-job-analyzer agent and a hook to enforce valid JSON output.
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.
No-Weak-Crypto ✅ Passed PR diff only updates docs and JSON validation/parsing; no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or secret-comparison code was added.
Container-Privileges ✅ Passed Reviewed all changed files; none introduce privileged/container manifest settings or root/allowPrivilegeEscalation flags.
No-Sensitive-Data-In-Logs ✅ Passed The diff only changes file globs, JSON validation, and benign status messages; no new logging of secrets, PII, or internal hostnames was introduced.
No-Hardcoded-Secrets ✅ Passed Changed files contain only docs, paths, and validator logic; no hardcoded API keys, tokens, passwords, private keys, embedded creds, or real base64 secrets were found.
No-Injection-Vectors ✅ Passed Changed files add JSON parsing/validation only; no eval/exec, shell=True, pickle.loads, yaml.load, os.system, or dangerous HTML sinks appear.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 markdownlint-cli2 (0.23.0)
plugins/lvms-ci/skills/doctor/SKILL.md

markdownlint-cli2 v0.23.0 (markdownlint v0.41.0)
Finding: :plugins/lvms-ci/skills/doctor/SKILL.md :plugins/lvms-ci/skills/prow-job/SKILL.md :plugins/microshift-ci/agents/prow-job-analyzer.md :plugins/microshift-ci/agents/references/microshift-ci-primer.md :plugins/microshift-ci/skills/continue-session/SKILL.md :plugins/microshift-ci/skills/create-bugs/SKILL.md :plugins/microshift-ci/skills/doctor/SKILL.md :plugins/microshift-ci/skills/prow-job/SKILL.md !node_modules/** !two-node-toolbox/**
Linting: 8 file(s)
Summary: 0 error(s)
AggregateError: Unable to import module 'markdownlint-cli2-formatter-pretty'.
at importModule (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:92:11)
at async Promise.all (index 0)
at async outputResults (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:879:9)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:1072:5)
at async file:///usr/local/lib/nod

... [truncated 1446 characters] ...

node:internal/modules/esm/resolve:271:11)
at moduleResolve (node:internal/modules/esm/resolve:861:10)
at defaultResolve (node:internal/modules/esm/resolve:988:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:697:20)
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:714:38)
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:746:52)
at #resolve (node:internal/modules/esm/loader:679:17)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:599:35)
at node:internal/modules/esm/loader:628:32
at TracingChannel.tracePromise (node:diagnostics_channel:362:14) {
code: 'ERR_MODULE_NOT_FOUND',
url: 'file:///markdownlint-cli2-formatter-pretty'
}
]
}

plugins/lvms-ci/skills/prow-job/SKILL.md

markdownlint-cli2 v0.23.0 (markdownlint v0.41.0)
Finding: :plugins/lvms-ci/skills/doctor/SKILL.md :plugins/lvms-ci/skills/prow-job/SKILL.md :plugins/microshift-ci/agents/prow-job-analyzer.md :plugins/microshift-ci/agents/references/microshift-ci-primer.md :plugins/microshift-ci/skills/continue-session/SKILL.md :plugins/microshift-ci/skills/create-bugs/SKILL.md :plugins/microshift-ci/skills/doctor/SKILL.md :plugins/microshift-ci/skills/prow-job/SKILL.md !node_modules/** !two-node-toolbox/**
Linting: 8 file(s)
Summary: 0 error(s)
AggregateError: Unable to import module 'markdownlint-cli2-formatter-pretty'.
at importModule (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:92:11)
at async Promise.all (index 0)
at async outputResults (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:879:9)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:1072:5)
at async file:///usr/local/lib/nod

... [truncated 1446 characters] ...

node:internal/modules/esm/resolve:271:11)
at moduleResolve (node:internal/modules/esm/resolve:861:10)
at defaultResolve (node:internal/modules/esm/resolve:988:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:697:20)
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:714:38)
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:746:52)
at #resolve (node:internal/modules/esm/loader:679:17)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:599:35)
at node:internal/modules/esm/loader:628:32
at TracingChannel.tracePromise (node:diagnostics_channel:362:14) {
code: 'ERR_MODULE_NOT_FOUND',
url: 'file:///markdownlint-cli2-formatter-pretty'
}
]
}

plugins/microshift-ci/agents/prow-job-analyzer.md

markdownlint-cli2 v0.23.0 (markdownlint v0.41.0)
Finding: :plugins/lvms-ci/skills/doctor/SKILL.md :plugins/lvms-ci/skills/prow-job/SKILL.md :plugins/microshift-ci/agents/prow-job-analyzer.md :plugins/microshift-ci/agents/references/microshift-ci-primer.md :plugins/microshift-ci/skills/continue-session/SKILL.md :plugins/microshift-ci/skills/create-bugs/SKILL.md :plugins/microshift-ci/skills/doctor/SKILL.md :plugins/microshift-ci/skills/prow-job/SKILL.md !node_modules/** !two-node-toolbox/**
Linting: 8 file(s)
Summary: 0 error(s)
AggregateError: Unable to import module 'markdownlint-cli2-formatter-pretty'.
at importModule (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:92:11)
at async Promise.all (index 0)
at async outputResults (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:879:9)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:1072:5)
at async file:///usr/local/lib/nod

... [truncated 1446 characters] ...

node:internal/modules/esm/resolve:271:11)
at moduleResolve (node:internal/modules/esm/resolve:861:10)
at defaultResolve (node:internal/modules/esm/resolve:988:11)
at #cachedDefaultResolve (node:internal/modules/esm/loader:697:20)
at #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:714:38)
at ModuleLoader.resolveSync (node:internal/modules/esm/loader:746:52)
at #resolve (node:internal/modules/esm/loader:679:17)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:599:35)
at node:internal/modules/esm/loader:628:32
at TracingChannel.tracePromise (node:diagnostics_channel:362:14) {
code: 'ERR_MODULE_NOT_FOUND',
url: 'file:///markdownlint-cli2-formatter-pretty'
}
]
}

  • 5 others

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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 (1)
plugins/microshift-ci/scripts/validate-rca-output.py (1)

56-63: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Full readlines() on every evidence citation is a scalability risk against the 30s hook timeout.

CI build-log.txt files can be tens of MB. Reading the entire file into memory per causal_chain link (up to 5 entries × multiple links each) adds up, and the hook is registered with "timeout": 30 in settings.json — a timeout here fails the hook silently (non-blocking error per Claude Code's hook contract), defeating the validation this PR exists to add. Consider seeking/streaming to the target line instead of loading the whole file.

♻️ Proposed fix using itertools.islice
+    import itertools
     try:
-        with open(path, errors="replace") as f:
-            lines = f.readlines()
+        with open(path, errors="replace") as f:
+            target_line = next(itertools.islice(f, line_no - 1, line_no), None)
+            total_lines = sum(1 for _ in f) + line_no  # only if bound check needed beyond target
     except OSError:
         return [f"{prefix}: evidence file could not be read: {path}"]
🤖 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 `@plugins/microshift-ci/scripts/validate-rca-output.py` around lines 56 - 63,
Update the evidence-file validation flow around the current open/readlines logic
to stream only through the file until the cited line, rather than loading all
lines into memory for each citation. Preserve the existing error messages and
line-number validation, including reporting when line_no is beyond the available
lines, while ensuring repeated causal_chain validations remain efficient within
the hook timeout.
🤖 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 `@plugins/microshift-ci/.claude/settings.json`:
- Around line 5-12: Update the command in the prow-job-analyzer hook
configuration to prefix the validate-rca-output.py path with
$CLAUDE_PROJECT_DIR, ensuring it resolves from any working directory. Leave the
existing matcher and timeout/status settings unchanged.

In `@plugins/microshift-ci/agents/prow-job-analyzer.md`:
- Line 25: Resolve the inconsistent failure-count contract in the analyzer
instructions around the JSON response requirements and the failure-reporting
section near lines 269–273. Choose one maximum failure count, then update the
documented output limit, validator behavior, and downstream consumers to enforce
that same limit consistently without truncating or rejecting otherwise valid
reports.

In `@plugins/microshift-ci/scripts/validate-rca-output.py`:
- Around line 14-19: Update NON_EMPTY_STRING_FIELDS and the validation logic in
validate_rca_output so step_name, root_cause, and remediation are validated as
non-empty strings, not merely checked for key presence. Preserve the existing
validation behavior for the already-covered fields and ensure empty or
non-string values are rejected.
- Around line 65-71: The validation flow in the cited evidence handling must not
silently skip invalid entries: require a non-empty causal_chain before
validation, and update the quote handling in the relevant validation function to
reject empty or shorter-than-10-character quotes as errors rather than returning
[]. Ensure every cited file, line, and quote proceeds through the documented
validation and line-match checks.
- Around line 35-63: Update validate_evidence to canonicalize the parsed
evidence path with os.path.realpath and validate it against the configured
workdir/artifact-root allow-list before any isfile or open call. Reject paths
outside those roots, including traversal and symlink escapes, while preserving
existing format and line-validation behavior for allowed files.

In `@plugins/microshift-ci/skills/prow-job/SKILL.md`:
- Around line 105-125: Define and apply an explicit report-schema validation
gate before formatting or persisting agent output. In
plugins/microshift-ci/skills/prow-job/SKILL.md lines 105-125, validate that the
parsed value is the expected JSON array and that every entry satisfies the
documented fields and types before display or raw-JSON saving; on failure,
report the validation error and do not persist. Apply the same array contract in
plugins/lvms-ci/skills/doctor/SKILL.md lines 78-83 before Write, and gate the
persistence flow in plugins/microshift-ci/skills/doctor/SKILL.md lines 121-123
so invalid reports are skipped.

---

Nitpick comments:
In `@plugins/microshift-ci/scripts/validate-rca-output.py`:
- Around line 56-63: Update the evidence-file validation flow around the current
open/readlines logic to stream only through the file until the cited line,
rather than loading all lines into memory for each citation. Preserve the
existing error messages and line-number validation, including reporting when
line_no is beyond the available lines, while ensuring repeated causal_chain
validations remain efficient within the hook timeout.
🪄 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: 9e25e831-aebd-4c1a-881b-c46f086c81b8

📥 Commits

Reviewing files that changed from the base of the PR and between c6d133e and 3907b29.

📒 Files selected for processing (15)
  • plugins/lvms-ci/skills/doctor/SKILL.md
  • plugins/lvms-ci/skills/prow-job/SKILL.md
  • plugins/microshift-ci/.claude/settings.json
  • plugins/microshift-ci/agents/prow-job-analyzer.md
  • plugins/microshift-ci/agents/references/microshift-ci-primer.md
  • plugins/microshift-ci/scripts/continue-session.sh
  • plugins/microshift-ci/scripts/search-bugs.py
  • plugins/microshift-ci/scripts/validate-rca-output.py
  • plugins/microshift-ci/skills/continue-session/SKILL.md
  • plugins/microshift-ci/skills/create-bugs/SKILL.md
  • plugins/microshift-ci/skills/doctor/SKILL.md
  • plugins/microshift-ci/skills/prow-job/SKILL.md
  • plugins/shared/scripts/aggregate.py
  • plugins/shared/scripts/doctor.sh
  • plugins/shared/scripts/parse.py

Comment thread plugins/microshift-ci/.claude/settings.json
Comment thread plugins/microshift-ci/agents/prow-job-analyzer.md
Comment thread plugins/microshift-ci/scripts/validate-rca-output.py
Comment thread plugins/microshift-ci/scripts/validate-rca-output.py Outdated
Comment thread plugins/microshift-ci/scripts/validate-rca-output.py
Comment thread plugins/microshift-ci/skills/prow-job/SKILL.md
@pmtk
pmtk force-pushed the prow-job-analyzer-agent-w-hook branch from 3907b29 to 4d62e01 Compare July 14, 2026 11:40
@coderabbitai coderabbitai Bot added the ready-for-human-review Indicates a PR has been reviewed by automated tools and is ready for human review label Jul 14, 2026
@pmtk
pmtk force-pushed the prow-job-analyzer-agent-w-hook branch 2 times, most recently from 8f18242 to 749c830 Compare July 14, 2026 11:47

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/microshift-ci/skills/doctor/SKILL.md (1)

88-128: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add error handling for agent orchestration in Step 2.

Per plugins/docs/SKILL-GUIDELINES.md: "if the skill orchestrates agents, include edge cases and guard checks (e.g., 'block/handle invalid JSON outputs')." Step 2 orchestrates multiple agents but lacks an "Error Handling" block. Based on learnings, you must co-locate failure policies and edge-case rules inline with the specific step that needs them. Please add an "Error Handling" section explicitly detailing how to handle agent failures, timeouts, or invalid JSON outputs for this step.

🤖 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 `@plugins/microshift-ci/skills/doctor/SKILL.md` around lines 88 - 128, Add an
“Error Handling” subsection within Step 2, after the agent orchestration
instructions, defining how to handle analyzer agent failures, timeouts, and
invalid or missing JSON responses. Require recording a structured failure result
for the affected job, continuing with other agents, and ensuring Step 3 receives
only valid saved results.

Sources: Path instructions, Learnings

♻️ Duplicate comments (2)
plugins/microshift-ci/scripts/validate-rca-output.py (2)

68-74: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Reject short quotes instead of silently returning.

As flagged in a previous review, the validation flow silently skips invalid entries by returning an empty error list for short quotes. This breaks the documented requirement that each cited file, line, and quote be rigorously checked. Update the quote handling to reject empty or shorter-than-10-character quotes as validation errors rather than returning [].

🔧 Proposed fix
-    if not isinstance(quote, str) or len(quote) < 10:
-        return []
+    if not isinstance(quote, str) or len(quote) < 10:
+        return [f"{prefix}: quote must be a string of at least 10 characters"]
🤖 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 `@plugins/microshift-ci/scripts/validate-rca-output.py` around lines 68 - 74,
Update the quote validation flow around normalized_quote and cited_line so empty
or shorter-than-10-character quotes return a validation error containing the
existing prefix context, instead of returning an empty list. Preserve the
existing line-content comparison and quote-not-found error behavior for
valid-length quotes.

50-63: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Constrain evidence to allowed artifact roots before opening it.

Per CONTRIBUTING.md: "Path traversal: canonicalize paths, reject ../" and "Validate at trust boundaries with allow-lists, not deny-lists." As flagged in a previous review, the validation using os.path.isabs() still allows arbitrary paths like /etc/passwd and symlink escapes. Canonicalize the path with os.path.realpath() and reject anything outside the expected workdir or artifact roots before calling isfile() or open().

🤖 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 `@plugins/microshift-ci/scripts/validate-rca-output.py` around lines 50 - 63,
Update the evidence-path validation flow around the visible isabs/isfile checks
to canonicalize paths with os.path.realpath() and enforce an allow-list of the
expected workdir and artifact roots. Reject traversal, absolute paths outside
those roots, and symlink escapes before invoking os.path.isfile() or open(),
while preserving the existing binary and read-error handling for accepted paths.

Sources: Coding guidelines, Path instructions

🤖 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 `@plugins/microshift-ci/scripts/validate-rca-output.py`:
- Around line 107-128: Update the causal_chain validation in the
entry-processing flow to reject an empty list, requiring it to be a non-empty
array while preserving the existing type and link-level checks for populated
lists.

---

Outside diff comments:
In `@plugins/microshift-ci/skills/doctor/SKILL.md`:
- Around line 88-128: Add an “Error Handling” subsection within Step 2, after
the agent orchestration instructions, defining how to handle analyzer agent
failures, timeouts, and invalid or missing JSON responses. Require recording a
structured failure result for the affected job, continuing with other agents,
and ensuring Step 3 receives only valid saved results.

---

Duplicate comments:
In `@plugins/microshift-ci/scripts/validate-rca-output.py`:
- Around line 68-74: Update the quote validation flow around normalized_quote
and cited_line so empty or shorter-than-10-character quotes return a validation
error containing the existing prefix context, instead of returning an empty
list. Preserve the existing line-content comparison and quote-not-found error
behavior for valid-length quotes.
- Around line 50-63: Update the evidence-path validation flow around the visible
isabs/isfile checks to canonicalize paths with os.path.realpath() and enforce an
allow-list of the expected workdir and artifact roots. Reject traversal,
absolute paths outside those roots, and symlink escapes before invoking
os.path.isfile() or open(), while preserving the existing binary and read-error
handling for accepted paths.
🪄 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: ac664b80-60b4-4178-804b-6f08311121db

📥 Commits

Reviewing files that changed from the base of the PR and between 3907b29 and 4d62e01.

📒 Files selected for processing (13)
  • plugins/lvms-ci/skills/doctor/SKILL.md
  • plugins/lvms-ci/skills/prow-job/SKILL.md
  • plugins/microshift-ci/.claude/settings.json
  • plugins/microshift-ci/agents/prow-job-analyzer.md
  • plugins/microshift-ci/scripts/continue-session.sh
  • plugins/microshift-ci/scripts/search-bugs.py
  • plugins/microshift-ci/scripts/validate-rca-output.py
  • plugins/microshift-ci/skills/continue-session/SKILL.md
  • plugins/microshift-ci/skills/create-bugs/SKILL.md
  • plugins/microshift-ci/skills/doctor/SKILL.md
  • plugins/shared/scripts/aggregate.py
  • plugins/shared/scripts/doctor.sh
  • plugins/shared/scripts/parse.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • plugins/microshift-ci/.claude/settings.json
  • plugins/microshift-ci/skills/continue-session/SKILL.md
  • plugins/lvms-ci/skills/doctor/SKILL.md
  • plugins/microshift-ci/agents/prow-job-analyzer.md
  • plugins/microshift-ci/scripts/continue-session.sh
  • plugins/microshift-ci/skills/create-bugs/SKILL.md
  • plugins/microshift-ci/scripts/search-bugs.py
  • plugins/shared/scripts/aggregate.py

Comment thread plugins/microshift-ci/scripts/validate-rca-output.py
@pmtk
pmtk force-pushed the prow-job-analyzer-agent-w-hook branch from 749c830 to 2f85054 Compare July 15, 2026 10:54

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/microshift-ci/skills/doctor/SKILL.md (1)

125-128: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Add error handling for subagent failures in Step 2.

Step 2 launches multiple microshift-ci:prow-job-analyzer agents in parallel but lacks an Error Handling block specifying what to do if an agent fails, times out, or returns a tool error.

As per path instructions for plugins/*/skills/**/SKILL.md, you must flag missing edge cases or safety guards. Additionally, based on learnings, failure policies and edge-case rules must be explicitly co-located inline with the specific step that needs them.

Please append an explicit error-handling directive at the end of Step 2 to ensure one failing job does not block the entire analysis.

🔧 Proposed fix
 3. Launch **ALL** agents (all releases + PRs) in a **single message** as **foreground** agents (do NOT use `run_in_background`). Foreground agents in the same message run concurrently — this is just as fast as background agents but keeps your turn active until all complete.
 4. Say "Analyzing N jobs in parallel..." in your message text alongside the Agent tool calls.
 5. When all agents return, immediately proceed to Step 3 in the same turn. Do NOT stop or end your turn between Step 2 and Step 3.
+
+**Error Handling**:
+
+- If a subagent fails, times out, or returns an error, note the failure for that specific job and proceed with the rest. Do not let one job's failure block the workflow.
🤖 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 `@plugins/microshift-ci/skills/doctor/SKILL.md` around lines 125 - 128, Append
an explicit error-handling directive to Step 2 after the parallel
`microshift-ci:prow-job-analyzer` launch instructions. Specify that failed,
timed-out, or tool-error agents must be recorded as failed and must not block
waiting for or processing the remaining agents; continue to Step 3 once all
successful results and failure statuses are collected.

Sources: Path instructions, Learnings

🤖 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 `@plugins/microshift-ci/agents/prow-job-analyzer.md`:
- Around line 149-152: The failure-localization tip in the Tips section is tied
to one specific Prow job. Replace the hardcoded step name in the build-log
search guidance with a generic pattern, and present the existing e2e step name
only as an example while preserving the instruction to use the last matching
step before container logs.
- Line 123: Update the workflow classification instruction in the
prow-job-analyzer documentation to use the canonical labels defined by the JSON
enum near the output schema, including the required test-failure stage values.
Ensure the guidance and schema consistently use the same enum values, or
explicitly document how the prose labels map to those canonical values.
- Around line 156-186: The output schema contract must include the RCA fields
consumed by downstream rendering: failure_type, impact, suspect_prs,
recommendation, same_root_cause, and attempt_analyses. Update the documented
output contract near the “Each entry in the output array” definition with these
exact field names and expected shapes, or synchronously update the consumers to
use the revised contract while preserving all RCA and per-attempt details.

In `@plugins/microshift-ci/scripts/validate-rca-output.py`:
- Around line 115-131: Fix the indentation of the causal-chain validation block
under the surrounding else clause, including the for loop and all of its
contents, so it uses the standard four-space nesting required by PEP 8 and
passes Ruff validation. Preserve the existing validation logic in
validate_evidence and the associated error reporting.

In `@plugins/microshift-ci/skills/create-bugs/SKILL.md`:
- Line 67: Update Step 1 in SKILL.md beside the search-bugs.py invocation to
instruct the agent to relay warnings for job files skipped due to invalid JSON
and stop when the script reports “No valid job reports found.” Ensure incomplete
candidate data is not processed silently.
- Line 577: Update Example 6 in the create-bugs skill documentation to use the
exact failure message emitted by search-bugs.py: “No job files found for <source
label> in <WORKDIR>”. Replace the current “Error: No job analysis files found at
<WORKDIR>/jobs/release-4.19-job-*.json” example without changing surrounding
guidance.

---

Outside diff comments:
In `@plugins/microshift-ci/skills/doctor/SKILL.md`:
- Around line 125-128: Append an explicit error-handling directive to Step 2
after the parallel `microshift-ci:prow-job-analyzer` launch instructions.
Specify that failed, timed-out, or tool-error agents must be recorded as failed
and must not block waiting for or processing the remaining agents; continue to
Step 3 once all successful results and failure statuses are collected.
🪄 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: 4eb3d522-5c4e-4248-87e3-dde268cc4d45

📥 Commits

Reviewing files that changed from the base of the PR and between 4d62e01 and 2f85054.

📒 Files selected for processing (18)
  • .claude-plugin/marketplace.json
  • plugins/lvms-ci/.claude-plugin/plugin.json
  • plugins/lvms-ci/skills/doctor/SKILL.md
  • plugins/lvms-ci/skills/prow-job/SKILL.md
  • plugins/microshift-ci/.claude-plugin/plugin.json
  • plugins/microshift-ci/.claude/settings.json
  • plugins/microshift-ci/agents/prow-job-analyzer.md
  • plugins/microshift-ci/agents/references/microshift-ci-primer.md
  • plugins/microshift-ci/scripts/continue-session.sh
  • plugins/microshift-ci/scripts/search-bugs.py
  • plugins/microshift-ci/scripts/validate-rca-output.py
  • plugins/microshift-ci/skills/continue-session/SKILL.md
  • plugins/microshift-ci/skills/create-bugs/SKILL.md
  • plugins/microshift-ci/skills/doctor/SKILL.md
  • plugins/microshift-ci/skills/prow-job/SKILL.md
  • plugins/shared/scripts/aggregate.py
  • plugins/shared/scripts/doctor.sh
  • plugins/shared/scripts/parse.py
🚧 Files skipped from review as they are similar to previous changes (9)
  • plugins/shared/scripts/doctor.sh
  • plugins/microshift-ci/.claude/settings.json
  • plugins/microshift-ci/skills/continue-session/SKILL.md
  • plugins/lvms-ci/skills/doctor/SKILL.md
  • plugins/shared/scripts/aggregate.py
  • plugins/microshift-ci/scripts/continue-session.sh
  • plugins/microshift-ci/agents/references/microshift-ci-primer.md
  • plugins/microshift-ci/skills/prow-job/SKILL.md
  • plugins/microshift-ci/scripts/search-bugs.py

Comment thread plugins/microshift-ci/agents/prow-job-analyzer.md Outdated
Comment thread plugins/microshift-ci/agents/prow-job-analyzer.md
Comment thread plugins/microshift-ci/agents/prow-job-analyzer.md
Comment thread plugins/microshift-ci/scripts/validate-rca-output.py Outdated
Comment thread plugins/microshift-ci/skills/create-bugs/SKILL.md
Comment thread plugins/microshift-ci/skills/create-bugs/SKILL.md Outdated
@pmtk
pmtk force-pushed the prow-job-analyzer-agent-w-hook branch from 2f85054 to 5596844 Compare July 15, 2026 11:14

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

Code review: 5 findings (3 confirmed, 2 plausible). Details in inline comments.

Comment thread plugins/shared/scripts/parse.py Outdated
m = re.search(r'\[.*\]', content, re.DOTALL)
if m:
try:
entries = json.loads(m.group(0))

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.

[correctness — CONFIRMED] Greedy fallback regex silently drops valid data

The fallback regex r'\[.*\]' with re.DOTALL matches from the first [ to the last ] in the entire file content. When a file contains square brackets in prose before the JSON array (e.g., error messages like index out of range [6], markdown links, or log prefixes like [INFO]), the regex captures a superset of the intended JSON. The inner json.loads then fails, and the function silently returns [], dropping all failure data.

Failure scenario: An old-format .txt file contains panic: runtime error: index out of range [6] with length 6 in the prose before the JSON block. The regex matches from [6] through the JSON array's closing ]. json.loads fails on the garbage, function returns [], and the job is silently dropped from the aggregated report.

The old marker-based regex (--- STRUCTURED SUMMARY ---) was reliable for mixed-content files; this replacement is not. Consider either keeping the old marker regex as an additional fallback, or using a non-greedy approach that anchors to a [ at the start of a line: r"^\[.*\]$" with re.MULTILINE | re.DOTALL.

When a job has multiple independent test failures across different scenarios, produce **one entry per failure** in the JSON array. Each entry must be self-contained with all fields populated.
```text
Analyze this prow job:
artifacts_dir: /tmp/microshift-ci-claude-workdir.260710/artifacts/2075422415638237184

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.

[correctness — CONFIRMED] Missing job_url and job_name in agent prompt

The example prompt here passes only artifacts_dir, graphs_dir, and source_dir — but the prow-job-analyzer agent definition marks job_url and job_name as (required) input, and the SubagentStop validator enforces both as non-empty strings.

The skill already has the URL from its <ARGUMENTS> but doesn't forward it. The doctor SKILL.md correctly passes both fields in its version of the same prompt — this is an inconsistency.

Failure scenario: User runs /microshift-ci:prow-job <URL>. Skill downloads artifacts, spawns agent without job_url. Agent must reconstruct from build-log.txt, which may fail for presubmit PR jobs or truncated logs. Validator blocks output if reconstruction fails.

Suggest adding job_url and job_name to the prompt template (and deriving job_name from the URL in step 0).

- `release`: the release branch — extract from job_name (e.g. 4.22 from release-4.22), or from finished.json metadata repos field, or default to "main"
- `remediation`: suggested fix or next step — what should be done to address this failure (~120 chars max). For infrastructure failures, state the infra action (e.g. "retry the job", "rotate AWS credentials"). For product bugs, state the code-level fix direction
- `finished`: the job finish date in YYYY-MM-DD format, extracted from finished.json timestamp field or build log timestamps
- `causal_chain`: array of links from observed symptom toward root cause. Each link: `{"cause": ..., "evidence": ..., "quote": ...}` where `evidence` is the **absolute** file path with a mandatory line number (`/absolute/path:lineNum`; use `:1` for binary files) and `quote` is a short verbatim excerpt from the cited line (empty for binary files). A SubagentStop hook validates that each cited file exists, the line number is in range, and the quote appears on the cited line

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.

[correctness — CONFIRMED] False claim: SubagentStop hook does not exist for lvms-ci

This text states "A SubagentStop hook validates that each cited file exists, the line number is in range, and the quote appears on the cited line" — but no SubagentStop hook or .claude/settings.json was created for the plugins/lvms-ci/ directory. Only plugins/microshift-ci/.claude/settings.json got the hook.

Failure scenario: LVMS prow-job skill produces malformed causal_chain entries (wrong evidence paths, missing quotes). The agent trusts the claimed validation and may produce sloppy citations. No hook catches the errors, and downstream scripts render broken evidence links in reports and Jira bugs.

Either add a matching hook for lvms-ci, or remove this claim from the field description.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hooks cannot be attached to skills, that why I had to convert it to agent first.
Do you want me to work on the "feature parity"? So far I was treating LVMS with "don't want to break it"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I misread the problem. We'll go back to the pretty-please agents for LVMS.
Problem with reusing the script is the delivery: if we want the plugins to be installable, the script needs to belong to the plugin (cannot be in the shared/)

errors.append(f"entry[{index}]: 'infrastructure_failure' must be a boolean, got {type(infra).__name__}")

layer = entry.get("stack_layer")
if not isinstance(layer, str) or layer not in VALID_STACK_LAYERS:

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.

[efficiency — PLAUSIBLE] readlines() loads entire evidence files per citation with no caching

CI build-log.txt files routinely reach 30–100 MB. When multiple causal_chain entries cite the same file, readlines() is called once per citation — reading the same large file repeatedly. Combined with the 30-second hook timeout, this risks timeout on I/O-heavy CI hosts.

Failure scenario: Agent produces 4 causal_chain links citing different lines in the same 50 MB build-log.txt. Hook reads ~200 MB total (4 full reads). On a busy host, sequential I/O exceeds the 30s timeout; hook is killed.

Consider caching file contents by path (a simple dict) or using linecache to read only up to the cited line.

errors.append(f"entry[{index}]: 'causal_chain' must be an array")
else:
errors.append(f"entry[{index}]: 'causal_chain' must be a non-empty array, got null")
elif not chain:

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.

[correctness — PLAUSIBLE] Quote validation checks only the single cited line

The check reads lines[line_no - 1] and tests whether the normalized quote is a substring of that single line. Log lines frequently wrap across multiple lines. When an agent quotes text spanning a line break, the validator rejects it — blocking valid analysis.

Failure scenario: Log has An error occurred (InvalidClientTokenId) when calling\nthe CreateStack operation split across lines 100–101. Agent cites line 100 with quote spanning both lines. Validator checks only line 100, quote not found, blocks the agent despite correct analysis.

Consider checking a small window (e.g., lines line_no-1 through line_no+1 joined) instead of the single line.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's by design. Agent instruction says:

quote is a short verbatim excerpt from the cited line — copied exactly

so it's either contained in the line or it's not. Giving a 3 line window would weaken the validator

@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 `@plugins/shared/scripts/parse.py`:
- Around line 41-56: Update the fallback parsing logic in the JSONDecodeError
branch to iterate backwards over every line-ending closing bracket in each
candidate tail, trying the latest possible closing bracket first. Preserve the
existing candidate-array scan and continue to the next opening bracket only
after all closing-bracket endpoints for the current tail fail, so valid JSON
arrays containing internal lines ending in ] are retained.
🪄 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: fd7f6ff3-b83a-43fb-9b70-06df1a2130d2

📥 Commits

Reviewing files that changed from the base of the PR and between 2f85054 and 4c80310.

📒 Files selected for processing (18)
  • .claude-plugin/marketplace.json
  • plugins/lvms-ci/.claude-plugin/plugin.json
  • plugins/lvms-ci/skills/doctor/SKILL.md
  • plugins/lvms-ci/skills/prow-job/SKILL.md
  • plugins/microshift-ci/.claude-plugin/plugin.json
  • plugins/microshift-ci/.claude/settings.json
  • plugins/microshift-ci/agents/prow-job-analyzer.md
  • plugins/microshift-ci/agents/references/microshift-ci-primer.md
  • plugins/microshift-ci/scripts/continue-session.sh
  • plugins/microshift-ci/scripts/search-bugs.py
  • plugins/microshift-ci/scripts/validate-rca-output.py
  • plugins/microshift-ci/skills/continue-session/SKILL.md
  • plugins/microshift-ci/skills/create-bugs/SKILL.md
  • plugins/microshift-ci/skills/doctor/SKILL.md
  • plugins/microshift-ci/skills/prow-job/SKILL.md
  • plugins/shared/scripts/aggregate.py
  • plugins/shared/scripts/doctor.sh
  • plugins/shared/scripts/parse.py
🚧 Files skipped from review as they are similar to previous changes (9)
  • plugins/microshift-ci/.claude-plugin/plugin.json
  • .claude-plugin/marketplace.json
  • plugins/shared/scripts/doctor.sh
  • plugins/microshift-ci/scripts/continue-session.sh
  • plugins/microshift-ci/scripts/search-bugs.py
  • plugins/microshift-ci/skills/create-bugs/SKILL.md
  • plugins/microshift-ci/skills/prow-job/SKILL.md
  • plugins/shared/scripts/aggregate.py
  • plugins/microshift-ci/skills/continue-session/SKILL.md

Comment on lines 41 to +56
try:
entries = json.loads(m.group(1))
entries = json.loads(content)
except json.JSONDecodeError:
return []
entries = None
for m in reversed(list(re.finditer(r'^\[', content, re.MULTILINE))):
tail = content[m.start():]
m2 = re.search(r'\][ \t]*$', tail, re.MULTILINE)
if not m2:
continue
try:
entries = json.loads(tail[:m2.end()].rstrip())
break
except json.JSONDecodeError:
continue
if entries is None:
return []

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 | 🔴 Critical | ⚡ Quick win

Fix the greedy fallback parser to prevent it from silently dropping valid JSON.

The fallback parser uses re.search to find the first ] at the end of a line within tail. If the generated JSON contains any internal lines ending with a ] (such as "analysis_gaps": []), the regex matches that early bracket, json.loads fails, and the loop moves on to the next ^\[ without ever trying the actual end of the JSON array. This silently discards valid data.

Iterate backwards over all possible closing brackets to ensure the parser evaluates the true end of the JSON array before moving on.

🐛 Proposed fix for the fallback parser
     try:
         entries = json.loads(content)
     except json.JSONDecodeError:
         entries = None
         for m in reversed(list(re.finditer(r'^\[', content, re.MULTILINE))):
             tail = content[m.start():]
-            m2 = re.search(r'\][ \t]*$', tail, re.MULTILINE)
-            if not m2:
-                continue
-            try:
-                entries = json.loads(tail[:m2.end()].rstrip())
-                break
-            except json.JSONDecodeError:
-                continue
+            for m2 in reversed(list(re.finditer(r'\][ \t]*$', tail, re.MULTILINE))):
+                try:
+                    entries = json.loads(tail[:m2.end()].rstrip())
+                    break
+                except json.JSONDecodeError:
+                    continue
+            if entries is not None:
+                break
         if entries is None:
             return []
🤖 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 `@plugins/shared/scripts/parse.py` around lines 41 - 56, Update the fallback
parsing logic in the JSONDecodeError branch to iterate backwards over every
line-ending closing bracket in each candidate tail, trying the latest possible
closing bracket first. Preserve the existing candidate-array scan and continue
to the next opening bracket only after all closing-bracket endpoints for the
current tail fail, so valid JSON arrays containing internal lines ending in ]
are retained.

@ggiguash

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 16, 2026
@openshift-merge-bot
openshift-merge-bot Bot merged commit 07a4fd9 into openshift-eng:main Jul 16, 2026
7 checks passed
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. ready-for-human-review Indicates a PR has been reviewed by automated tools and is ready for human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants