Repository navigation
A pass skips finished run files without parsing them - #54
Merged
Merged
Conversation
Two cases fail: a large finished run and small finished runs are still read whole by listUnfinishedRuns. Issue: #49
A run whose last complete line is a finished event is skipped after one bounded read from the end of its file. A cut-off or invalid last line, or a finished line longer than the tail, falls back to the full read. Issue: #49
A run file holding only blank lines, or a large file whose last 8192 bytes are all blank, must be listed as unfinished exactly as readRun reads it (state null, or the state of its first line). Red: before the fix the run hung node (the vitest worker printed no result and had to be killed after the 60s alarm did not stop it). Issue: #49
The blank-line step-back called lastIndexOf with a byteOffset of -1 once it reached the first byte, which Buffer reads as counting from the end, so the walk looped forever. With no earlier line it now returns false and the file is read in full. Issue: #49
…shed are read in full Both tests pin existing behavior, so there was no red phase. They kill two mutation survivors: a last line naming finished that is not a valid entry, and a cut-off fragment after a complete finished line, must each force a full read. Issue: #49
rawphp
marked this pull request as ready for review
October 16, 2026 03:49
Author
|
Factory gate: passed (attempt 1, run by the factory in a fresh checkout of the pull request's head
|
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.
Closes #49
Contract
listUnfinishedRunsskips a run whose file's last complete line is afinishedevent by reading at most 8192 bytes from the end of the file, never the whole file. Unfinished runs are reported exactly as before (id,state,confirmed,unreadable,session) in the same order. A file whose last line is cut off, whose last complete line is not JSON or not a valid entry, or whose tail cannot decide (a line longer than the tail, a tail of only blank lines) is read in full as before. No index file or archive directory; theruns/format is unchanged.runs/layout,readProgress, and the other callers ofreadRun(gate.ts,start.ts).vp test run apps/server/src/factory/ledger/listRuns.test.ts→ passAcceptance criteria
listRuns.test.ts"never reads a large finished run whole, and still lists an unfinished sibling" (a > 64 KiB finished file;vi.mock("node:fs")recordsreadFileSynccalls), plus "skips a small finished run, also after a trailing blank line or CRLF".listRuns.test.tscases pass unchanged — every pre-existing case is untouched and green.readSyncat the tail of each run file (read.tslastLineIsFinished); nothing is written.Gate
vp test run apps/server/src/factory→ exit 0 (31 files, 952 tests)vp run --filter t3 typecheck→ exit 0Models
modelsblock in.dw/config.yml, so the roster default was used)Review
lastLineIsFinishedcalledBuffer.lastIndexOfwith offset -1 when the walk reached the start of the tail; a negative offset counts from the end, so a file of only"\n"(or a tail of only blank lines) looped forever and would have hung the pass. Fixed test-first in7d264025c+baee5a7da.cd28e906c: a last line that namesfinishedbut is not a valid entry, and a cut-off fragment after a completefinishedline, both proven to force the full read.test:commit was run in a detached tree atff4348f00(2 failed, 15 passed) and the tip is green. The red for7d264025cwas a hang, reproduced by both reviewers and the maker.cd28e906cpins existing behavior and had no red phase.Isolate
origin/mainwith a clean tree; fast-forwardede4bcce9f6→9e8095616before provisioning.factory:*labels already existed; none created.Lessons
git push -u origin <branch>failed with "src refspec does not match any". Cause: the launch context named the worktree's directory suffix as the branch, but the checked-out branch had a different name. Default: at Isolate rungit branch --show-currentand push that name; never take the branch from the directory or the launch message..factory/, and the test runner's path filter is a substring match, so it collected the copies too. Default:git worktree removethe review tree as soon as the mutating reviewer reports, before any gate or scoped test run from the main worktree.perl -e 'alarm 60; exec ...'did not stop a hung vitest run; only the parent died and the forks lived on. Default: start the run withsetpgrpin its own group and bound it with a wait loop that kills that group by its pid (kill -TERM -- -$pid), which only touches processes the reviewer started.Commits
ff4348f00test: finished runs are skipped by reading only the file's tail— Make slice (red)a264b7b5cfeat: listUnfinishedRuns skips a finished run by its tail— Make slice (green)7d264025ctest: a run file of only blank lines is listed as unfinished— Check cycle 1 (red: hang)baee5a7dafix: lastLineIsFinished stops at a blank line that starts the tail— Check cycle 1 (green)cd28e906ctest: a finished-named invalid line and a cut-off fragment after finished are read in full— Check cycle 2Files
apps/server/src/factory/ledger/read.ts— new exportedlastLineIsFinished(path): lstat guard, one boundedreadSyncat the tail,parseLines-compatible decision;readRununchanged.apps/server/src/factory/ledger/listRuns.ts— calls it beforereadRunand skips the run when true, inside the existing try/catch so IO failures still list the run as unreadable; doc comment updated.apps/server/src/factory/ledger/listRuns.test.ts— the spy and nine new cases; existing cases untouched.