Watch CI with a script instead of a polling loop - #846
Merged
Conversation
The CI watcher was told to poll for check runs every thirty seconds. A foreground sleep does not run in this harness and the agent has no timer, so the interval it was asked for was one it could not take. The documented way out was gh pr checks --watch, and gh was not installed, so that path was dead too. gh is now a hard dependency rather than an alternative offered where it happens to exist. Watching is a single blocking --watch call, and the exit code distinguishes a failure from a watch cut short before the round finished, which would otherwise burn a fix attempt on a run that was merely still going. Failure diagnosis reads the failing job's log through gh run view --log-failed rather than scraping check run annotations. Annotations carry compiler diagnostics well and test failures poorly, and the report this agent writes is the only thing the implementer gets. gh carries its own credential, separate from the MCP server's, so the agent checks gh auth status first and names the missing login rather than failing part way through with an authentication error. crypter-triage-review named gh pr comment as the only way to answer a finding with no thread, which was unreachable for the same reason. It now names the MCP equivalent alongside it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An unauthenticated gh pr checks exits 4, which was outside the set of exit codes the watcher was given. Left undocumented it reads as a non-zero exit and therefore as a failing build, which sends the implementer looking for a defect that is not there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Waiting, reading exit codes, finding failing runs and cutting a log down to the part that explains itself are all deterministic, and they were written as prose for an agent to follow. Prose cannot be run, so the mistakes in it only surfaced when a run went wrong: a polling interval the harness cannot take, an exit code that reads as a failing build when it means nobody logged in, an instruction to read the tail of a log whose last fifty lines are cleanup. ci-status.sh does that half and can be tested. Exit codes separate a CI failure from the three setup problems that otherwise look like one. On a failure it prints the window of log ending at the runner's ##[error] marker, which turns a 1100-line dump into roughly sixty lines containing the cause. The agent keeps the half that needs judgement: reading back from the symptom to the cause, reading the branch's version of the code the failure names, deciding whether it is a defect, a wrong test or the plan itself being wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two skills offered a bare gh call as an alternative to the MCP server for posting a review and commenting on a pull request. The MCP server does both, so those were discretionary CLI invocations with nothing to recommend them. The watcher's remaining direct call was fetching a fuller copy of a log the script had already downloaded. The script now keeps each failing job's log and prints its path, so reading further means opening a file rather than going back to the network. Nothing outside ci-status.sh invokes gh now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The CI watcher was told to poll
get_check_runsevery thirty seconds. A foregroundsleepdoes not run in this harness and the agent has no timer, so the interval it was asked for was one it could not take. The documented alternative wasgh pr checks --watch, andghwas not installed, so that path was dead as well.The mechanical half of watching CI now lives in
.claude/scripts/ci-status.sh: it waits for checks to conclude, reports the outcome as an exit code, and on a failure prints the part of the log that explains it. The agent keeps the half that needs judgement — reading back from the symptom to the cause, reading the branch's version of the code the failure names, and deciding whether it is a defect, a wrong test, or the plan itself being wrong.Exit codes separate a CI failure from the three setup problems that otherwise look like one:
0passed,1failed,3no checks ever started,4ghnot authenticated,8still pending when the watch ended. Reporting any of the last three as a failure sends an implementer hunting for a defect that does not exist.crypter-triage-reviewnamedgh pr commentas the sole way to answer a finding with no thread, unreachable for the same reasonghwas. It now namesadd_issue_commentalongside it.Things worth knowing as a reviewer:
ghinstalled and authenticated. It carries its own credential, separate from the one the MCP server holds.gh run view --log-failedreturns roughly 1100 lines for a single failed job, mostly checkout and cleanup noise, and the failure is not at the tail. The script prints a window ending at the runner's##[error]marker, which brings it down to about sixty lines. The marker itself is the symptom — the cause sits above it — and the agent is told so explicitly.Analyze (csharp)andAnalyze (javascript)as separate rows. The matrix only expands when it runs; a docs-only diff reports one unexpandedAnalyze.Verified against this repository with
gh 2.87.3: exit 0 on a green pull request (#845), exit 0 with skipped checks (#846), exit 4 unauthenticated, exit 64 on bad arguments and on an unknown pull request, the failing-run query against a commit with two failed workflows, and the log extraction against a real 1149-line failure log — where it surfaced the root cause, a Node version mismatch, that the##[error]line did not mention.