Repository navigation
local-ci-log: an executor on the runner's machine reads the run's log instead of re-running the gate (#137) - #149
Merged
Merged
Conversation
… and reads the failure there, running the gate only without one (#137)
deanbot
marked this pull request as ready for review
November 1, 2026 22:10
…LOG_CUT, so the session reads the failure from the output; no folder access in the README (#137 review)
# Conflicts: # AGENTS.md
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.
A failing
local-cistatus carries only the gate's last line, so the executor'sCI_FAILINGstep for the local runner re-ran the whole gate to read the failure. When the executor runs on the runner's machine, the run's log is already there. Re-running costs a full gate (about 30 minutes on one project) and holds any machine-wide lock the gate takes, so every other run waits. This adds a lookup that prints that log's end, and tells every executor to read the failure there first.What changed
scripts/local-ci-log.mjs --repo owner/repo --pr <n> --sha <sha>finds that head's newest log under~/.agent-loop/local-ci/<owner>-<repo>/, matching the file nameslocal-ci.mjswrites (<pr>-<first 12 of sha>-<time>.log). It prints:LOG <path>;LOG_CUTwhen the log has more than what was printed: earlier lines, or a line over 2000 characters, which is cut with….It prints
NO_LOCAL_LOGwhen there is no such log, the folder isn't there or readable, or the log can't be read. It exits 0 either way.--repois limited to GitHub's name characters, since it becomes part of a folder path.The executor's
CI_FAILINGstep for the local runner (Claude Codereference/signals.md, generic, Kiro):NO_LOCAL_LOG, run<gate>as before.pending) is unchanged.SPEC, "How it meets
gate": running the gate to read a failure is now the fallback, not the only way. AGENTS.md lists the script.Done items
One command gets the log, with no globbing in the skill text and no file read by the session:
local-ci-log.mjs, above.The
CI_FAILINGstep gets the log first, reads the failure from the output, runs only what confirms the fix, and runs<gate>only onNO_LOCAL_LOG:local-ci-log (#137): every executor's CI_FAILING for the local runner runs the lookup first, reads the failure from its LOG output (never the file), and runs the gate only on NO_LOCAL_LOG. It also asserts that the old "run<gate>to read the failure" and "read the log's end" wordings are gone from each executor.No access to the log folder needed:
local-ci-log (#137 review): the plugin README asks for no access to the log folder (the script prints the log).Contract tests:
a head with logs → LOG <the newer run's path> and its lines, indented (two runs of one head), no LOG_CUTa log of 250 lines → LOG, its last 200 lines (51 to 250), then LOG_CUTa log of exactly 200 lines → all of them, no LOG_CUTANSI sequences and control characters are removed, a carriage return keeps what follows it, and a log line that reads like a signal is indenteda line over 2000 characters is cut (…) and gives LOG_CUTa log over 1 MiB → its last 200 lines whole (a partial first line dropped), then LOG_CUTan empty log (a run just started) → LOG <path> aloneNO_LOCAL_LOG: a head with no log, another PR's log for the same sha, no log folder for the repo, a log this user can't reada short sha (7 digits) or upper case finds the same loga PR or sha that is not one, a repo outside GitHub's name characters, a missing or stray argument → exit 1The fake
ghisn't needed: the lookup makes noghcall.SPEC's "How it meets
gate" says this.Calls to judge
LOG_CUTorNO_LOCAL_LOGcan't pass as the script's own line, aspr-poll.mjsindents comment bodies.local-ci.mjs --log:local-ci.mjsrefuses to run outside a runner clone, takes a lock and needs--gate, none of which a read-only lookup should need.--log-dirflag. A runner under another user or on another machine givesNO_LOCAL_LOG, and the executor runs the gate, as today.Known limits
LOG_CUT. The executor then has the end of the run only, and falls back to running the failing step it can name, or the gate.Not verified (the live-check list)
CI_FAILINGfromlocal-ci. It reads the failure from the lookup's output with no permission prompt, runs the one failing test, and doesn't start a full gate.NO_LOCAL_LOGand runs the gate as before.Restart note
Executors need a fresh session: all three executor texts changed. Reviewers and QA need none. Setup need not be re-run:
setup-project.shis unchanged, and its existingnode <plugin root>/scripts/*rule covers the script. No settings entry is needed any more.Closes #137