feat(verify-pr): prefetch CI check-run outcomes into sandbox input - #302
Conversation
In the CI-dispatched (sandbox) verify-pr path the CI Status check had no data — no gh CLI or egress in the sandbox — so it degraded to WARN "CI status could not be retrieved" (PR RHEcosystemAppEng#301, TC-6192). Extend the split-trust prefetch so the pre_script fetches the PR head-SHA CI check-run outcomes on the trusted runner and embeds them in the sandbox bundle; correctness.md Check 1 reads them in sandbox mode and keeps the `gh` on-demand path for interactive mode. - pre-verify-pr.sh: prefetch repos/<repo>/commits/<sha>/check-runs into check-runs.json, reduced to name/status/conclusion/details_url - pre_verify_pr.py: build_github_bundle embeds github.check_runs (defaults to []); _github_from_dir reads check-runs.json - verify-pr-input.schema.json: add required github.check_runs (github is additionalProperties:false, so the new key must be declared) - correctness.md: Check 1 sandbox-mode branch reads pre-fetched check-runs; 1b notes failure logs are unavailable in the sandbox - dispatch-template.md, SKILL.md Step 0.7: document github.check_runs - test_pre_verify_pr.py: cover check_runs in the bundle and transform E2E re-verification on a live dispatched PR (PASS on green, FAIL on red) is deferred to a CI run. Implements TC-6257 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Assisted-by: Claude Code
Reviewer's GuideThe PR extends the trusted-runner prefetch pipeline with head-SHA CI check-run metadata, makes sandbox CI verification evaluate that embedded data without GitHub access, retains on-demand gh behavior interactively, and updates the schema, documentation, and tests for the new required bundle field. Sequence diagram for prefetched CI status in sandbox verificationsequenceDiagram
participant Runner as Trusted runner
participant GitHub as GitHub API
participant Bundle as Sandbox input bundle
participant Sandbox as Sandbox verifier
participant Correctness as Correctness Check 1
Runner->>GitHub: check-runs for COMMIT_SHA
GitHub-->>Runner: name, status, conclusion, details_url
Runner->>Bundle: build_github_bundle(check_runs)
Bundle->>Sandbox: github.check_runs
Sandbox->>Correctness: CI Status input
Correctness->>Correctness: Map conclusions to PASS, WARN, or FAIL
Correctness-->>Sandbox: CI verdict
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 3 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="plugins/sdlc-workflow/scripts/pre-verify-pr.sh" line_range="191" />
<code_context>
+# before dispatch. Reduced to the fields the verdict needs (name/status/conclusion
+# and details_url for the failure-log link) to keep the bundle small. A PR with no
+# checks yields an empty array — consistent with the reviews/comments empties.
+gh api --paginate --slurp "repos/${PR_REPO}/commits/${COMMIT_SHA}/check-runs" \
+ | jq '[.[].check_runs[] | {name, status, conclusion, details_url}]' > "${PRE_OUTPUT_DIR}/check-runs.json"
echo "GitHub read bundle prefetched to ${PRE_OUTPUT_DIR}"
</code_context>
<issue_to_address>
**issue (bug_risk):** The prefetch includes every check run returned for the commit, including superseded failed runs from workflow reruns, and Check 1 treats any failed entry as a CI failure. A commit with a failed first run followed by a successful rerun is therefore reported as FAIL even though the current check result is passing.
**Triggers:** When a workflow or check is rerun for the same head SHA after an earlier failure.
**Suggested fix:** Select only the current/latest check run for each check identity, or use an API/result representation that matches the PR's effective check status rather than all historical runs.
```suggestion
| jq '[.[].check_runs[]] | group_by(.name) | map(max_by(.id) | {name, status, conclusion, details_url})' > "${PRE_OUTPUT_DIR}/check-runs.json"
```
</issue_to_address>
### Comment 2
<location path="plugins/sdlc-workflow/skills/verify-pr/correctness.md" line_range="44-45" />
<code_context>
+pre-fetched check-run outcomes from the CI Status input (each entry has `name`,
+`status`, `conclusion`, `details_url`). Map each entry to a status:
+
+- `conclusion` of `success`/`neutral`/`skipped` → pass
+- `conclusion` of `failure`/`timed_out`/`cancelled`/`action_required` → failed
+- `status` not `completed` (i.e. `queued`/`in_progress`) → pending
+- an empty check-runs list → no checks configured (treat as pass; note it in the
+ evidence)
+
</code_context>
<issue_to_address>
**issue (bug_risk):** The sandbox mapping does not define the GitHub check conclusions `startup_failure` or `stale`, even though both are valid completed check-run conclusions that indicate a check did not pass. Those entries receive no specified verdict and can be omitted from the failed-check path, allowing CI Status to be reported as PASS or otherwise misclassified.
**Triggers:** When a check run completes with `startup_failure` or `stale`.
**Suggested fix:** Explicitly classify all non-success terminal conclusions, including `startup_failure` and `stale`, as failed; treat only the documented pass conclusions as passing.
```suggestion
- `status` of `completed` with `conclusion` of `success`/`neutral`/`skipped` → pass
- `status` of `completed` with any other `conclusion` → failed
```
</issue_to_address>
### Comment 3
<location path="plugins/sdlc-workflow/skills/verify-pr/correctness.md" line_range="66-69" />
<code_context>
-For each failed CI check, fetch the failure logs:
+**Sandbox mode:** the failure logs cannot be fetched — there is no `gh` CLI or
+network egress. Skip the `gh run view`/`gh run list` commands below and derive the
+failure analysis in step 1c from the PR diff plus the failed check's `name`,
+`conclusion`, and `details_url` from the pre-fetched CI Status input. Still emit the
+`create-sub-task` action (step 1d); include the `details_url` so a human can open
+the full log.
+
+**Interactive mode:** for each failed CI check, fetch the failure logs:
</code_context>
<issue_to_address>
**issue:** Sandbox Check 1b says to derive failure analysis without logs, but the unchanged Check 1c instructions still require analyzing the failure log to identify the specific failure and root error. In sandbox mode no log exists, so the sub-agent is given contradictory instructions and cannot satisfy the required evidence format from the prefetched fields alone.
**Triggers:** When a prefetched check is failed in sandbox mode.
**Suggested fix:** Add an explicit sandbox branch to Check 1c that requires only diff-based analysis and the check metadata, and removes the log-specific requirements for that mode.
</issue_to_address>Sourcery assessment
Needs a human reviewer. 3 findings to address first, and if the prefetched check-run data is incomplete or mapped incorrectly, the sandbox could report the wrong CI verdict and create an unnecessary verification sub-task or miss a failed check. Reverting stops the behavior, but any sub-task or verdict produced before the revert would need manual correction.
Blocking findings: plugins/sdlc-workflow/scripts/pre-verify-pr.sh:191, plugins/sdlc-workflow/skills/verify-pr/correctness.md:45, plugins/sdlc-workflow/skills/verify-pr/correctness.md:69
| # and details_url for the failure-log link) to keep the bundle small. A PR with no | ||
| # checks yields an empty array — consistent with the reviews/comments empties. | ||
| gh api --paginate --slurp "repos/${PR_REPO}/commits/${COMMIT_SHA}/check-runs" \ | ||
| | jq '[.[].check_runs[] | {name, status, conclusion, details_url}]' > "${PRE_OUTPUT_DIR}/check-runs.json" |
There was a problem hiding this comment.
issue (bug_risk): The prefetch includes every check run returned for the commit, including superseded failed runs from workflow reruns, and Check 1 treats any failed entry as a CI failure. A commit with a failed first run followed by a successful rerun is therefore reported as FAIL even though the current check result is passing.
Triggers: When a workflow or check is rerun for the same head SHA after an earlier failure.
Suggested fix: Select only the current/latest check run for each check identity, or use an API/result representation that matches the PR's effective check status rather than all historical runs.
| | jq '[.[].check_runs[] | {name, status, conclusion, details_url}]' > "${PRE_OUTPUT_DIR}/check-runs.json" | |
| | jq '[.[].check_runs[]] | group_by(.name) | map(max_by(.id) | {name, status, conclusion, details_url})' > "${PRE_OUTPUT_DIR}/check-runs.json" |
| - `conclusion` of `success`/`neutral`/`skipped` → pass | ||
| - `conclusion` of `failure`/`timed_out`/`cancelled`/`action_required` → failed |
There was a problem hiding this comment.
issue (bug_risk): The sandbox mapping does not define the GitHub check conclusions startup_failure or stale, even though both are valid completed check-run conclusions that indicate a check did not pass. Those entries receive no specified verdict and can be omitted from the failed-check path, allowing CI Status to be reported as PASS or otherwise misclassified.
Triggers: When a check run completes with startup_failure or stale.
Suggested fix: Explicitly classify all non-success terminal conclusions, including startup_failure and stale, as failed; treat only the documented pass conclusions as passing.
| - `conclusion` of `success`/`neutral`/`skipped` → pass | |
| - `conclusion` of `failure`/`timed_out`/`cancelled`/`action_required` → failed | |
| - `status` of `completed` with `conclusion` of `success`/`neutral`/`skipped` → pass | |
| - `status` of `completed` with any other `conclusion` → failed |
The CI-status prefetch gives the sandbox check-run outcomes, but on a FAIL correctness.md Check 1b still had no failure logs to analyse: the sandbox has no gh CLI or egress to run `gh run view --log-failed`, so it inferred the what/why/fix from the diff alone. Extend the split-trust prefetch to capture the logs too. The pre_script (on the trusted runner, where GH_TOKEN lives) extracts the distinct GitHub Actions run IDs from each FAILED check-run's details_url and concatenates their `gh run view --log-failed` output into a single check-run-logs.txt, mounted read-only beside verify-pr-input.json. host_files mounts single files only and the failed set is dynamic, so one combined file is used rather than per-check paths. The file is always created (empty when nothing failed) so its mount is never missing; the bundle carries only its sandbox path (github.check_run_logs_path, "" when empty), never the log text — so the large content stays out of the schema and off the sub-agent's context until Check 1b Reads it on a FAIL. The wait-for-checks job (fullsend-verify-pr.yml) guarantees terminal conclusions before dispatch, so a failed check's log is complete and fetchable at that point. Non-Actions checks (no actions/runs URL) are skipped; 1b falls back to the diff + details_url for those. Interactive mode is unchanged (fetches via gh on demand). - pre-verify-pr.sh: extract failed Actions run IDs (deduped) and pack their --log-failed output into check-run-logs.txt; always create the file - pre_verify_pr.py: build_github_bundle gains check_run_logs_path (default ""); _github_from_dir emits the mounted sandbox path when the log file is non-empty - verify-pr-input.schema.json: add required github.check_run_logs_path (string) - .fullsend/harness/verify-pr.yaml: mount check-run-logs.txt (optional) - correctness.md / dispatch-template.md / SKILL.md: Check 1b reads the prefetched log file via the CI Failure Logs input on a FAIL; document the new key - test_pre_verify_pr.py: cover the new bundle field and the path derivation (present/empty/absent) TC-6257 Assisted-by: Claude Code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The split-trust prefetch children (pre-verify-pr.sh, correctness.md, SKILL.md, dispatch-template.md, verify-pr-input.schema.json) added in 14b8be6/fa3f4b7d only take effect in a CI-dispatched run when the URL-pinned harness base advances to a commit that contains them. The base file bytes are unchanged (sha256 3c9dc221…), so only the pinned commit moves a9099de → fa3f4b7; `fullsend lock` refreezes all 11 children (notably pre-verify-pr.sh) at fa3f4b7. Without this the sandbox keeps running the pre-TC-6257 pinned skill, whose bundle carries no github.check_runs — CI Status falls back to the WARN "unavailable in sandbox" path instead of sourcing prefetched data. Assisted-by: Claude Code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI Status is now sourced from prefetched github.check_runs, and on a CI failure Correctness Check 1b reads the prefetched check-run-logs.txt. Proven live via CI dispatch on vehicle PR RHEcosystemAppEng#303 / Jira TC-6266: - post-re-pin run 35075966985 sourced CI Status from prefetched check_runs (data the pre-TC-6257 sandbox could not obtain); - vehicle-only red commit 8865e11 (canary test) → verify-pr 35077404421 reported CI Status FAIL and Check 1b surfaced the runtime-computed, log-only canary cc08a78a24bc66f6 (never a literal in the diff), auto-creating CI-failure sub-task TC-6271. Also documents that the harness base re-pin is load-bearing (the pinned children must advance to a commit containing the prefetch code) and supersedes the TC-6192 "CI status unavailable in sandbox" caveat. Assisted-by: Claude Code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
59ed61d
into
RHEcosystemAppEng:verify-pr-fullsend
Summary
In the CI-dispatched (sandbox) verify-pr path the CI Status check had no data to work from — the sandbox has no
ghCLI and no network egress — so it degraded toWARN "CI status could not be retrieved in sandbox mode"(observed on PR #301 during the TC-6192 E2E acceptance run). This defeats the TC-6180 premise that verify-pr consumes the CI result as input data.This extends the existing split-trust prefetch: the
pre_script(on the trusted runner, whereGH_TOKENand the head SHA live) fetches the PR head-SHA CI check-run outcomes and embeds them in the sandbox input bundle.correctness.mdCheck 1 reads them in sandbox mode; interactive mode keeps fetching viaghon demand.Changes
pre-verify-pr.sh— prefetchrepos/<repo>/commits/<COMMIT_SHA>/check-runsintocheck-runs.json, reduced toname/status/conclusion/details_url.pre_verify_pr.py—build_github_bundleembedsgithub.check_runs(defaults to[]);_github_from_dirreadscheck-runs.json.verify-pr-input.schema.json— add requiredgithub.check_runs. Thegithubobject isadditionalProperties:false, so the new key must be declared or Step 0.7 validation rejects the bundle. (Out of the task's Files-to-Modify list but required for the feature; approved.)correctness.md— Check 1 sandbox-mode branch reads pre-fetched check-runs and maps conclusions to PASS/WARN/FAIL; 1b documents that failure logs are unavailable in the sandbox (analysis derived from diff + check name/conclusion,details_urlcarried into the sub-task).dispatch-template.md,SKILL.mdStep 0.7 — document thegithub.check_runskey.test_pre_verify_pr.py— covercheck_runsin the bundle, the transform, the CLI dir path, and the empty-default.Data passed from CI
Only outcome metadata per check-run —
name,status,conclusion,details_url— not the failure logs (kept out to keep the bundle small; the sandbox cannot fetch them anyway).Verification
python3 -m pytest plugins/sdlc-workflow/scripts/ -q→ 144 passeduvx skillsaw→ 0 errorsclaude plugin validate plugins/sdlc-workflow→ passedDeferred: E2E re-verification on a live dispatched PR (CI Status = PASS on a green PR, FAIL on a red PR, both sourced from prefetched data) and the coupled
fullsend.mdacceptance note — both await a live CI dispatch run.Implements TC-6257
🤖 Generated with Claude Code
Summary by Sourcery
Enable sandbox verify-pr to evaluate CI status and investigate failures using trusted-runner-prefetched GitHub data.
New Features:
Bug Fixes:
Enhancements:
Deployment:
Documentation:
Tests: