From 4bdb88b9d9a46c82c2f48d9b2d6da4e4de8ef792 Mon Sep 17 00:00:00 2001 From: Gregory Giguashvili Date: Sat, 13 Jun 2026 09:57:48 +0300 Subject: [PATCH 1/7] Add analyze workflow scripts --- plugins/lvms-ci/scripts/doctor-analyze.js | 1 + .../microshift-ci/scripts/doctor-analyze.js | 1 + plugins/shared/scripts/doctor-analyze.js | 50 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 120000 plugins/lvms-ci/scripts/doctor-analyze.js create mode 120000 plugins/microshift-ci/scripts/doctor-analyze.js create mode 100644 plugins/shared/scripts/doctor-analyze.js diff --git a/plugins/lvms-ci/scripts/doctor-analyze.js b/plugins/lvms-ci/scripts/doctor-analyze.js new file mode 120000 index 00000000..b7a050bd --- /dev/null +++ b/plugins/lvms-ci/scripts/doctor-analyze.js @@ -0,0 +1 @@ +../../shared/scripts/doctor-analyze.js \ No newline at end of file diff --git a/plugins/microshift-ci/scripts/doctor-analyze.js b/plugins/microshift-ci/scripts/doctor-analyze.js new file mode 120000 index 00000000..b7a050bd --- /dev/null +++ b/plugins/microshift-ci/scripts/doctor-analyze.js @@ -0,0 +1 @@ +../../shared/scripts/doctor-analyze.js \ No newline at end of file diff --git a/plugins/shared/scripts/doctor-analyze.js b/plugins/shared/scripts/doctor-analyze.js new file mode 100644 index 00000000..3026f9ca --- /dev/null +++ b/plugins/shared/scripts/doctor-analyze.js @@ -0,0 +1,50 @@ +export const meta = { + name: 'doctor-analyze', + description: 'Analyze CI jobs in parallel via per-job prow-job skill invocations', + phases: [ + { title: 'Analyze', detail: 'Per-job root cause analysis' }, + ], +} + +// args: { +// jobs: [{ artifacts_dir: string, output_path: string, label: string, status?: string }], +// prow_job_skill: string, // e.g. "/lvms-ci:prow-job" or "/microshift-ci:prow-job" +// } + +// Defend against the model passing args as a JSON string instead of an object +const a = typeof args === 'string' ? JSON.parse(args) : args + +phase('Analyze') +const failedJobs = a.jobs.filter(function(job) { + return !job.status || job.status.toUpperCase() === 'FAILURE' +}) +log('Analyzing ' + failedJobs.length + ' jobs in parallel...') + +const results = await parallel(failedJobs.map(function(job) { + return function() { + return agent( + 'Analyze this Prow job and save the report:\n' + + '1. Run ' + a.prow_job_skill + ' ' + job.artifacts_dir + '\n' + + '2. After the analysis completes, save the FULL report output' + + ' (including the --- STRUCTURED SUMMARY --- block) to:\n' + + ' ' + job.output_path + '\n' + + ' Use the Write tool to save the file.' + + ' The file must contain the complete analysis report.', + { label: job.label, phase: 'Analyze' } + ) + } +})) + +const analyzed = results.filter(function(r) { return r !== null }).length +const failed = results.length - analyzed +if (failed > 0) { + log('Analysis complete: ' + analyzed + '/' + results.length + ' jobs analyzed, ' + failed + ' failed') +} else { + log('Analysis complete: all ' + analyzed + ' jobs analyzed') +} + +return { + analyzed: analyzed, + failed: failed, + total: results.length, +} From 1ac3d17fa44747dc09bfe560b19ef0aebedf9c20 Mon Sep 17 00:00:00 2001 From: Gregory Giguashvili Date: Sat, 13 Jun 2026 09:58:05 +0300 Subject: [PATCH 2/7] Update doctor skills to use analyze workflow --- plugins/lvms-ci/skills/doctor/SKILL.md | 45 +++++++++------ plugins/microshift-ci/skills/doctor/SKILL.md | 59 +++++++++++--------- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/plugins/lvms-ci/skills/doctor/SKILL.md b/plugins/lvms-ci/skills/doctor/SKILL.md index c9e929e3..80dd0d3f 100644 --- a/plugins/lvms-ci/skills/doctor/SKILL.md +++ b/plugins/lvms-ci/skills/doctor/SKILL.md @@ -3,7 +3,7 @@ name: lvms-ci:doctor argument-hint: [release1,release2,...] description: Analyze CI for LVMS periodic jobs and produce an HTML summary user-invocable: true -allowed-tools: Skill, Bash, Read, Write, Glob, Grep, Agent +allowed-tools: Skill, Bash, Read, Write, Glob, Grep, Workflow --- # lvms-ci:doctor @@ -65,26 +65,39 @@ Compute once at the start by running `date +%y%m%d` and substituting into the pa - If a release has no failed jobs, its jobs JSON will be an empty array — skip analysis for that release - If a release has an `"error"` field in the JSON summary, data collection failed for that release — report the error to the user but continue with other releases -### Step 2: Analyze Each Job Using /lvms-ci:prow-job +### Step 2: Analyze via Workflow -**Goal**: Get detailed root cause analysis for each failed job using pre-downloaded artifacts. +**Goal**: Run per-job analysis in parallel, orchestrated deterministically by a workflow script. **Actions**: -1. Use the JSON summary output from Step 1 to build agent prompts. Do NOT read the job JSON files into the main conversation — the prepare script already printed all job details (artifacts_dir, build_id, job name) and agents receive artifacts_dir directly in their prompt. -2. For **every** failed job across all releases, launch a separate **Agent** (using the `Agent` tool, NOT the `Skill` tool): +1. Parse the JSON summary from Step 1 to build the workflow arguments. For each release with `jobs > 0`, read its `jobs_file` to get the array of job objects. For each job, create an entry with: + - `artifacts_dir`: from the job's `artifacts_dir` field + - `output_path`: `/jobs/release--job--.txt` where N is the 1-based index within that release + - `label`: `-job-` (e.g., `main-job-3`) + +2. Invoke the Workflow tool: ```text - Agent: subagent_type=general_purpose, prompt="Analyze this Prow job and save the report: - 1. Run /lvms-ci:prow-job - 2. After the analysis completes, save the FULL report output (including the --- STRUCTURED SUMMARY --- block) to: - /jobs/release--job--.txt - Use the Write tool to save the file. The file must contain the complete analysis report." + Workflow( + scriptPath: "plugins/lvms-ci/scripts/doctor-analyze.js", + args: { + jobs: [ ...entries from action 1... ], + prow_job_skill: "/lvms-ci:prow-job" + } + ) ``` -3. Launch **ALL** agents 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. +3. The workflow runs in the background and sends a completion notification when done. Wait for the notification, then proceed to Step 3. Do NOT stop or end your turn between Step 2 and Step 3. + +**CRITICAL — no fallback**: If the Workflow tool call fails for any reason (script error, timeout, API error), STOP and report the error to the user. Do NOT fall back to sequential Agent-based spawning — sequential execution risks hitting the turn timeout. + +The workflow runs all job analyses in parallel — each agent runs the prow-job skill and saves the report. + +**Error Handling**: + +- If individual analysis agents fail, the workflow continues with the remaining jobs +- The workflow returns `{analyzed, failed, total}` — use these for the summary ### Step 3: Finalize — Aggregate and Generate HTML Report @@ -145,13 +158,13 @@ HTML report generated: /report-lvm-operator-ci-doctor.html ## Related Skills -- **lvms-ci:prow-job**: Single job analysis (used by Step 2 agents) +- **lvms-ci:prow-job**: Single job analysis (used by Step 2 workflow agents) ## Notes - **Deterministic scripts** handle: data collection, artifact download, aggregation, HTML generation -- **LLM agents** handle: per-job root cause analysis (Step 2) -- All agents are launched in a single parallel wave +- **LLM agents** handle: per-job root cause analysis (via Step 2 workflow) +- Step 2 uses a Workflow script (`doctor-analyze.js`) that guarantees parallel agent execution via `parallel()` - The `prepare` script downloads all artifacts upfront so prow-job agents use local paths (no redundant downloads) - The `finalize` script runs aggregation and HTML generation in one call - All intermediate files use prescribed filenames in `` — no improvised names diff --git a/plugins/microshift-ci/skills/doctor/SKILL.md b/plugins/microshift-ci/skills/doctor/SKILL.md index a8be5af2..a372de62 100644 --- a/plugins/microshift-ci/skills/doctor/SKILL.md +++ b/plugins/microshift-ci/skills/doctor/SKILL.md @@ -3,7 +3,7 @@ name: microshift-ci:doctor argument-hint: description: Analyze CI for multiple MicroShift releases and produce an HTML summary user-invocable: true -allowed-tools: Skill, Bash, Read, Write, Glob, Grep, Agent +allowed-tools: Skill, Bash, Read, Write, Glob, Grep, Agent, Workflow --- # microshift-ci:doctor @@ -85,38 +85,45 @@ Compute once at the start by running `date +%y%m%d` and substituting into the pa - `4_disk_usage.png` — Disk usage by partition (% fill) 3. If prerequisites are missing (`pcp2json`, `matplotlib`), the script errors and stops. -### Step 2: Analyze Each Job Using /microshift-ci:prow-job +### Step 2: Analyze via Workflow -**Goal**: Get detailed root cause analysis for each failed job using pre-downloaded artifacts. +**Goal**: Run per-job analysis in parallel, orchestrated deterministically by a workflow script. **Actions**: -1. Use the JSON summary output from Step 1 to build agent prompts. Do NOT read the job JSON files into the main conversation — the prepare script already printed all job details (artifacts_dir, build_id, job name) and agents receive artifacts_dir directly in their prompt. -2. For **every** failed job across all releases and PRs, launch a separate **Agent** (using the `Agent` tool, NOT the `Skill` tool). For PR jobs, only launch agents for jobs with FAILURE status. +1. Parse the JSON summary from Step 1 to build the workflow arguments. For each release with `jobs > 0`, read its `jobs_file` to get the array of job objects. For each job, create an entry with: + - `artifacts_dir`: from the job's `artifacts_dir` field + - `output_path`: `/jobs/release--job--.txt` where N is the 1-based index within that release + - `label`: `-job-` (e.g., `4.22-job-3`) - **For release jobs:** +2. For PR jobs (if the summary has `prs.jobs > 0`), read the PR jobs file. For each PR, iterate **all** its jobs and create an entry with: + - `artifacts_dir`: from the job's `artifacts_dir` field + - `output_path`: `/jobs/prs-job--pr-.txt` where `JOB_NAME_SUFFIX` is the job name's last segment after the release identifier + - `label`: `pr-job-` + - `status`: from the job's `status` field (the workflow script filters to FAILURE only) + +3. Invoke the Workflow tool: ```text - Agent: subagent_type=general_purpose, prompt="Analyze this Prow job and save the report: - 1. Run /microshift-ci:prow-job - 2. After the analysis completes, save the FULL report output (including the --- STRUCTURED SUMMARY --- block) to: - /jobs/release--job--.txt - Use the Write tool to save the file. The file must contain the complete analysis report." + Workflow( + scriptPath: "plugins/microshift-ci/scripts/doctor-analyze.js", + args: { + jobs: [ ...entries from actions 1-2... ], + prow_job_skill: "/microshift-ci:prow-job" + } + ) ``` - **For PR jobs:** +4. The workflow runs in the background and sends a completion notification when done. Wait for the notification, then proceed to Step 3. Do NOT stop or end your turn between Step 2 and Step 3. - ```text - Agent: subagent_type=general_purpose, prompt="Analyze this Prow job and save the report: - 1. Run /microshift-ci:prow-job - 2. After the analysis completes, save the FULL report output (including the --- STRUCTURED SUMMARY --- block) to: - /jobs/prs-job--pr-.txt - Use the Write tool to save the file. The file must contain the complete analysis report." - ``` +**CRITICAL — no fallback**: If the Workflow tool call fails for any reason (script error, timeout, API error), STOP and report the error to the user. Do NOT fall back to sequential Agent-based spawning — sequential execution risks hitting the turn timeout. + +The workflow runs all job analyses in parallel — each agent runs the prow-job skill and saves the report. + +**Error Handling**: -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. +- If individual analysis agents fail, the workflow continues with the remaining jobs +- The workflow returns `{analyzed, failed, total}` — use these for the summary ### Step 3: Run Bug Correlation (Dry-Run) @@ -126,7 +133,7 @@ Compute once at the start by running `date +%y%m%d` and substituting into the pa 1. Collect all release versions from `` into a comma-separated list (e.g., `4.19,4.20,4.21,4.22`) 2. Check for rebase PR source identifiers from the PR jobs JSON (e.g., `rebase-release-4.22`). Append them to the source list. -3. Launch a **single** `microshift-ci:create-bugs` **foreground** agent in dry-run mode with all sources: +3. Launch a **single** `microshift-ci:create-bugs` **foreground** agent: ```text Agent: subagent_type=general_purpose, prompt="Run /microshift-ci:create-bugs " @@ -214,16 +221,16 @@ HTML report generated: /report-microshift-ci-doctor.html ## Related Skills -- **microshift-ci:prow-job**: Single job analysis (used by Step 2 agents) +- **microshift-ci:prow-job**: Single job analysis (used by Step 2 workflow agents) - **microshift-ci:create-bugs**: Bug correlation and creation (used in Step 3; can also be run with `--create` after this command) - **microshift-ci:doctor-refresh**: Regenerate the HTML report from existing data (e.g., after `/microshift-ci:create-bugs --create`) ## Notes - **Deterministic scripts** handle: data collection, artifact download, aggregation, HTML generation -- **LLM agents** handle: per-job root cause analysis (Step 2), Jira bug search and open bugs query (Step 3) +- **LLM agents** handle: per-job root cause analysis (Step 2 workflow), Jira bug search and open bugs query (Step 3) - `/microshift-ci:doctor-refresh` regenerates the HTML report from existing data. Use it after `/microshift-ci:create-bugs --create` to include newly created bugs -- Step 2 agents (per-job analysis) are launched in a single parallel wave +- Step 2 uses a Workflow script (`doctor-analyze.js`) that guarantees parallel agent execution via `parallel()` - Step 3 uses a single create-bugs agent with all sources (releases + rebase) comma-separated - The `prepare` script downloads all artifacts upfront so prow-job agents use local paths (no redundant downloads) - The `finalize` script runs aggregation and HTML generation in one call From 93c4df0c4d75677f9bbc97d61390f2c432ac918e Mon Sep 17 00:00:00 2001 From: Gregory Giguashvili Date: Sat, 13 Jun 2026 10:25:04 +0300 Subject: [PATCH 3/7] Script workflow argument preparation --- plugins/lvms-ci/skills/doctor/SKILL.md | 8 ++--- plugins/microshift-ci/skills/doctor/SKILL.md | 18 +++------- plugins/shared/scripts/doctor.sh | 35 ++++++++++++++++++++ 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/plugins/lvms-ci/skills/doctor/SKILL.md b/plugins/lvms-ci/skills/doctor/SKILL.md index 80dd0d3f..589de7df 100644 --- a/plugins/lvms-ci/skills/doctor/SKILL.md +++ b/plugins/lvms-ci/skills/doctor/SKILL.md @@ -71,18 +71,14 @@ Compute once at the start by running `date +%y%m%d` and substituting into the pa **Actions**: -1. Parse the JSON summary from Step 1 to build the workflow arguments. For each release with `jobs > 0`, read its `jobs_file` to get the array of job objects. For each job, create an entry with: - - `artifacts_dir`: from the job's `artifacts_dir` field - - `output_path`: `/jobs/release--job--.txt` where N is the 1-based index within that release - - `label`: `-job-` (e.g., `main-job-3`) - +1. Read `/workflows/analyze-jobs.json` (written by the prepare script in Step 1). If the array is empty, skip to Step 3. 2. Invoke the Workflow tool: ```text Workflow( scriptPath: "plugins/lvms-ci/scripts/doctor-analyze.js", args: { - jobs: [ ...entries from action 1... ], + jobs: , prow_job_skill: "/lvms-ci:prow-job" } ) diff --git a/plugins/microshift-ci/skills/doctor/SKILL.md b/plugins/microshift-ci/skills/doctor/SKILL.md index a372de62..4379edb6 100644 --- a/plugins/microshift-ci/skills/doctor/SKILL.md +++ b/plugins/microshift-ci/skills/doctor/SKILL.md @@ -91,30 +91,20 @@ Compute once at the start by running `date +%y%m%d` and substituting into the pa **Actions**: -1. Parse the JSON summary from Step 1 to build the workflow arguments. For each release with `jobs > 0`, read its `jobs_file` to get the array of job objects. For each job, create an entry with: - - `artifacts_dir`: from the job's `artifacts_dir` field - - `output_path`: `/jobs/release--job--.txt` where N is the 1-based index within that release - - `label`: `-job-` (e.g., `4.22-job-3`) - -2. For PR jobs (if the summary has `prs.jobs > 0`), read the PR jobs file. For each PR, iterate **all** its jobs and create an entry with: - - `artifacts_dir`: from the job's `artifacts_dir` field - - `output_path`: `/jobs/prs-job--pr-.txt` where `JOB_NAME_SUFFIX` is the job name's last segment after the release identifier - - `label`: `pr-job-` - - `status`: from the job's `status` field (the workflow script filters to FAILURE only) - -3. Invoke the Workflow tool: +1. Read `/workflows/analyze-jobs.json` (written by the prepare script in Step 1). If the array is empty, skip to Step 3. +2. Invoke the Workflow tool: ```text Workflow( scriptPath: "plugins/microshift-ci/scripts/doctor-analyze.js", args: { - jobs: [ ...entries from actions 1-2... ], + jobs: , prow_job_skill: "/microshift-ci:prow-job" } ) ``` -4. The workflow runs in the background and sends a completion notification when done. Wait for the notification, then proceed to Step 3. Do NOT stop or end your turn between Step 2 and Step 3. +3. The workflow runs in the background and sends a completion notification when done. Wait for the notification, then proceed to Step 3. Do NOT stop or end your turn between Step 2 and Step 3. **CRITICAL — no fallback**: If the Workflow tool call fails for any reason (script error, timeout, API error), STOP and report the error to the user. Do NOT fall back to sequential Agent-based spawning — sequential execution risks hitting the turn timeout. diff --git a/plugins/shared/scripts/doctor.sh b/plugins/shared/scripts/doctor.sh index 38745965..23e4d48f 100755 --- a/plugins/shared/scripts/doctor.sh +++ b/plugins/shared/scripts/doctor.sh @@ -224,6 +224,41 @@ cmd_prepare() { fi echo "${result}" + + # Build workflow args: map each job to its output path for parallel analysis + mkdir -p "${WORKDIR}/workflows" + local workflow_jobs="[]" + + # Release jobs: no status field (all are already failures from the prepare filter) + for release in "${RELEASES[@]}"; do + release=$(echo "${release}" | xargs) + local jobs_file="${WORKDIR}/jobs/release-${release}-jobs.json" + [[ -f "${jobs_file}" ]] || continue + + workflow_jobs=$(echo "${workflow_jobs}" | jq --arg r "${release}" --arg w "${WORKDIR}" \ + --slurpfile jobs "${jobs_file}" \ + '. + [$jobs[0] | to_entries[] | { + artifacts_dir: .value.artifacts_dir, + output_path: ($w + "/jobs/release-" + $r + "-job-" + ((.key+1)|tostring) + "-" + .value.build_id + ".txt"), + label: ($r + "-job-" + ((.key+1)|tostring)) + }]') + done + + # PR jobs: includes status so consumers can filter by outcome + if [[ -f "${WORKDIR}/jobs/prs-jobs.json" ]]; then + workflow_jobs=$(echo "${workflow_jobs}" | jq --arg w "${WORKDIR}" \ + --slurpfile jobs "${WORKDIR}/jobs/prs-jobs.json" \ + '. + [$jobs[0] | to_entries[] | { + artifacts_dir: .value.artifacts_dir, + output_path: ($w + "/jobs/prs-job-" + ((.key+1)|tostring) + "-pr" + (.value.pr_number|tostring) + "-" + .value.build_id + ".txt"), + label: ("pr" + (.value.pr_number|tostring) + "-job-" + ((.key+1)|tostring)), + status: .value.status + }]') + fi + + # Write the workflow args file + echo "${workflow_jobs}" > "${WORKDIR}/workflows/analyze-jobs.json" + echo "Workflow args written to ${WORKDIR}/workflows/analyze-jobs.json" >&2 } # --------------------------------------------------------------------------- From 058246ed9e093d8124264d1f9a546a57312b516e Mon Sep 17 00:00:00 2001 From: Gregory Giguashvili Date: Sat, 13 Jun 2026 10:44:04 +0300 Subject: [PATCH 4/7] Address Claude review fixes --- plugins/shared/scripts/doctor-analyze.js | 2 +- plugins/shared/scripts/doctor.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/shared/scripts/doctor-analyze.js b/plugins/shared/scripts/doctor-analyze.js index 3026f9ca..d1ab0ecb 100644 --- a/plugins/shared/scripts/doctor-analyze.js +++ b/plugins/shared/scripts/doctor-analyze.js @@ -35,7 +35,7 @@ const results = await parallel(failedJobs.map(function(job) { } })) -const analyzed = results.filter(function(r) { return r !== null }).length +const analyzed = results.filter(function(r) { return r != null }).length const failed = results.length - analyzed if (failed > 0) { log('Analysis complete: ' + analyzed + '/' + results.length + ' jobs analyzed, ' + failed + ' failed') diff --git a/plugins/shared/scripts/doctor.sh b/plugins/shared/scripts/doctor.sh index 23e4d48f..ec54d40a 100755 --- a/plugins/shared/scripts/doctor.sh +++ b/plugins/shared/scripts/doctor.sh @@ -245,7 +245,7 @@ cmd_prepare() { done # PR jobs: includes status so consumers can filter by outcome - if [[ -f "${WORKDIR}/jobs/prs-jobs.json" ]]; then + if ${do_rebase} && [[ -f "${WORKDIR}/jobs/prs-jobs.json" ]]; then workflow_jobs=$(echo "${workflow_jobs}" | jq --arg w "${WORKDIR}" \ --slurpfile jobs "${WORKDIR}/jobs/prs-jobs.json" \ '. + [$jobs[0] | to_entries[] | { From 3491f0a05e3b3216648fdad6e78ad02cdeaa4fdf Mon Sep 17 00:00:00 2001 From: Gregory Giguashvili Date: Sat, 13 Jun 2026 11:37:56 +0300 Subject: [PATCH 5/7] Fix microshift-ci:create-bugs skill call --- plugins/microshift-ci/skills/doctor/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/microshift-ci/skills/doctor/SKILL.md b/plugins/microshift-ci/skills/doctor/SKILL.md index 4379edb6..f7e767b8 100644 --- a/plugins/microshift-ci/skills/doctor/SKILL.md +++ b/plugins/microshift-ci/skills/doctor/SKILL.md @@ -123,7 +123,7 @@ The workflow runs all job analyses in parallel — each agent runs the prow-job 1. Collect all release versions from `` into a comma-separated list (e.g., `4.19,4.20,4.21,4.22`) 2. Check for rebase PR source identifiers from the PR jobs JSON (e.g., `rebase-release-4.22`). Append them to the source list. -3. Launch a **single** `microshift-ci:create-bugs` **foreground** agent: +3. Launch a **single** `microshift-ci:create-bugs` **foreground** agent in dry-run mode with all sources: ```text Agent: subagent_type=general_purpose, prompt="Run /microshift-ci:create-bugs " From 14c86b47366685ca26e24c8d89262143547f03b9 Mon Sep 17 00:00:00 2001 From: Gregory Giguashvili Date: Sun, 14 Jun 2026 12:26:34 +0300 Subject: [PATCH 6/7] Move PR failed job filtering to doctor.sh --- plugins/shared/scripts/doctor-analyze.js | 18 ++++++++++++------ plugins/shared/scripts/doctor.sh | 7 +++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/plugins/shared/scripts/doctor-analyze.js b/plugins/shared/scripts/doctor-analyze.js index d1ab0ecb..88076c03 100644 --- a/plugins/shared/scripts/doctor-analyze.js +++ b/plugins/shared/scripts/doctor-analyze.js @@ -7,20 +7,26 @@ export const meta = { } // args: { -// jobs: [{ artifacts_dir: string, output_path: string, label: string, status?: string }], +// jobs: [{ artifacts_dir: string, output_path: string, label: string }], // prow_job_skill: string, // e.g. "/lvms-ci:prow-job" or "/microshift-ci:prow-job" // } // Defend against the model passing args as a JSON string instead of an object const a = typeof args === 'string' ? JSON.parse(args) : args +if (!a || !Array.isArray(a.jobs)) { + log('ERROR: args.jobs is missing or not an array') + return { analyzed: 0, failed: 0, total: 0, error: 'args.jobs is missing or not an array' } +} +if (!a.prow_job_skill) { + log('ERROR: args.prow_job_skill is missing') + return { analyzed: 0, failed: 0, total: 0, error: 'args.prow_job_skill is missing' } +} + phase('Analyze') -const failedJobs = a.jobs.filter(function(job) { - return !job.status || job.status.toUpperCase() === 'FAILURE' -}) -log('Analyzing ' + failedJobs.length + ' jobs in parallel...') +log('Analyzing ' + a.jobs.length + ' jobs in parallel...') -const results = await parallel(failedJobs.map(function(job) { +const results = await parallel(a.jobs.map(function(job) { return function() { return agent( 'Analyze this Prow job and save the report:\n' + diff --git a/plugins/shared/scripts/doctor.sh b/plugins/shared/scripts/doctor.sh index ec54d40a..ef02fb4b 100755 --- a/plugins/shared/scripts/doctor.sh +++ b/plugins/shared/scripts/doctor.sh @@ -244,15 +244,14 @@ cmd_prepare() { }]') done - # PR jobs: includes status so consumers can filter by outcome + # PR jobs: pre-filter to FAILURE only so the workflow analyzes exactly what's needed if ${do_rebase} && [[ -f "${WORKDIR}/jobs/prs-jobs.json" ]]; then workflow_jobs=$(echo "${workflow_jobs}" | jq --arg w "${WORKDIR}" \ --slurpfile jobs "${WORKDIR}/jobs/prs-jobs.json" \ - '. + [$jobs[0] | to_entries[] | { + '. + [$jobs[0] | to_entries[] | select(.value.status == "FAILURE") | { artifacts_dir: .value.artifacts_dir, output_path: ($w + "/jobs/prs-job-" + ((.key+1)|tostring) + "-pr" + (.value.pr_number|tostring) + "-" + .value.build_id + ".txt"), - label: ("pr" + (.value.pr_number|tostring) + "-job-" + ((.key+1)|tostring)), - status: .value.status + label: ("pr" + (.value.pr_number|tostring) + "-job-" + ((.key+1)|tostring)) }]') fi From 04c2b972d437c7bb1d6a9f043b8132eb85173bb8 Mon Sep 17 00:00:00 2001 From: Gregory Giguashvili Date: Mon, 15 Jun 2026 09:48:08 +0300 Subject: [PATCH 7/7] Make Workflow tool a hard requirement --- plugins/lvms-ci/skills/doctor/SKILL.md | 12 ++++++++++++ plugins/microshift-ci/skills/doctor/SKILL.md | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/plugins/lvms-ci/skills/doctor/SKILL.md b/plugins/lvms-ci/skills/doctor/SKILL.md index 589de7df..163952e8 100644 --- a/plugins/lvms-ci/skills/doctor/SKILL.md +++ b/plugins/lvms-ci/skills/doctor/SKILL.md @@ -33,6 +33,18 @@ Compute once at the start by running `date +%y%m%d` and substituting into the pa ## Implementation Steps +### Step 0: Verify Workflow Tool Availability + +**CRITICAL — hard requirement**: This skill requires the `Workflow` tool. Before proceeding, confirm that `Workflow` is listed in your available tools. If it is NOT available, STOP IMMEDIATELY and report this error to the user: + +```text +ERROR: The Workflow tool is not available in this Claude Code version. +The lvms-ci:doctor skill requires Workflow support (Claude Code 2.2+). +Please upgrade Claude Code and retry. +``` + +Do NOT attempt to work around the missing tool by spawning individual agents, using sequential analysis, or any other fallback. The skill cannot produce correct results without deterministic workflow orchestration. + ### Step 1: Prepare — Collect and Download All Artifacts **Goal**: Deterministically collect all failed jobs and download their artifacts before any LLM analysis. diff --git a/plugins/microshift-ci/skills/doctor/SKILL.md b/plugins/microshift-ci/skills/doctor/SKILL.md index f7e767b8..fa1d80e8 100644 --- a/plugins/microshift-ci/skills/doctor/SKILL.md +++ b/plugins/microshift-ci/skills/doctor/SKILL.md @@ -32,6 +32,18 @@ Compute once at the start by running `date +%y%m%d` and substituting into the pa ## Implementation Steps +### Step 0: Verify Workflow Tool Availability + +**CRITICAL — hard requirement**: This skill requires the `Workflow` tool. Before proceeding, confirm that `Workflow` is listed in your available tools. If it is NOT available, STOP IMMEDIATELY and report this error to the user: + +```text +ERROR: The Workflow tool is not available in this Claude Code version. +The microshift-ci:doctor skill requires Workflow support (Claude Code 2.2+). +Please upgrade Claude Code and retry. +``` + +Do NOT attempt to work around the missing tool by spawning individual agents, using sequential analysis, or any other fallback. The skill cannot produce correct results without deterministic workflow orchestration. + ### Step 1: Prepare — Collect and Download All Artifacts **Goal**: Deterministically collect all failed jobs and download their artifacts before any LLM analysis.