fix(prod): follow both Windows log files and survive truncation - #559
Open
RonenMars wants to merge 1 commit into
Open
fix(prod): follow both Windows log files and survive truncation#559RonenMars wants to merge 1 commit into
RonenMars wants to merge 1 commit into
Conversation
Get-Content -Wait cannot back `prod logs` on Windows: given several paths it blocks inside the first file's read loop and never opens the second, so stderr — the one stream a crashed boot leaves anything in — was never shown. It also keeps its offset across truncation, so `prod logs --clear` and the boot log-cap left the follower parked past EOF, alive-looking and permanently silent; the replacement poll loop resets the offset when a file shrinks, which is what -F gives POSIX. Sets $ErrorActionPreference = 'Stop' for the seed reads so an unreadable path exits non-zero instead of powershell.exe reporting success with no output, while the poll body still swallows its own errors because a file vanishing mid-follow is precisely what -F is for. Guards Repair-LaunchCmd's `Get-Command node` lookup, which under ErrorActionPreference = Stop aborted the entire deploy with a raw CommandNotFoundException on exactly the pre-redirection installs it exists to heal. Repairs three assertions that could not fail: a whole-file toContain that Invoke-Setup's identical line satisfied, a getLogPaths()/logPaths() comparison of a function against itself, and a bare node:child_process mock that blanked execFileSync so detectConflictingAgents() returned [] unconditionally. Corrects ROADMAP's claim that CI covers the Windows redirection — test:smoke runs an explicit eight-file list including neither of these tests, and no job executes launch.cmd — and repoints two stale %TEMP%\threadbase.err references at the real log paths.
RonenMars
force-pushed
the
fix/windows-prod-logs-followups
branch
from
August 13, 2026 13:05
bd4a204 to
2eb19df
Compare
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.
Follow-ups to #520 and #523.
The bug
prod logshad on WindowsGet-Content -Waitcannot back a two-file follow. Given several paths it blocks inside the first file's read loop and never opens the second — not even to print its seed lines. On the defaultprod logs(stdout + stderr) that hid stderr entirely, which is the one stream a crashed boot leaves anything in.It also cannot recover from truncation.
-Fwas chosen on POSIX precisely becauseprod logs --clearand the boot log-cap both empty these files; a-Waitfollower keeps its stored offset, sits past the new EOF, and silently never prints again — alive-looking and permanently useless.windowsFollowScript()replaces it with an explicit poll loop that resets a file's offset when it shrinks.$ErrorActionPreference = 'Stop'covers the seed reads, so an unreadable path exits non-zero instead of powershell.exe's default "non-terminating error, exit 0" — whichrunProdLogswould otherwise report as success with no output. The poll body deliberately swallows its own errors instead: a file vanishing mid-follow is what-Fis for and must not kill the follower.A deploy that aborted on the installs it exists to heal
Repair-LaunchCmd'sGet-Command nodewas unguarded. UnderErrorActionPreference = Stopa missing node aborts the entire deploy with a rawCommandNotFoundExceptionrather than a readable message — and the>>condition above it makes that path fire on every install predating the redirection, which is exactly the population this function exists to repair.Three assertions that could not fail
Each of these was green while the thing it claimed to lock was broken:
deploy-windows-scriptasserted with a whole-filetoContain.Invoke-Setupcarries its own identical$logsDir = ...line, so the test passed even with the launcher's copy deleted — which would build the redirect targets fromJoin-Path $null. Now scoped toGet-LaunchCmdLines.expect(getLogPaths()).toEqual(logPaths())compared a function to itself: task-scheduler'sgetLogPathsisreturn logPaths(). Replaced with assertions on the shape the launcher actually depends on.prod-commandsused a barevi.mock("node:child_process")factory, which blanks every other export.conflict-check.tsimportsexecFileSyncfrom there and calls it inside try/catch, so an undefinedexecFileSyncthrewTypeError, was swallowed, and madedetectConflictingAgents()return[]unconditionally — everyprod doctorcase below was asserting against a detector that could not detect anything. Now spreadsimportActual.Docs
The ROADMAP paragraph is a rebase resolution rather than my original text, and the difference matters.
This branch was cut before #527. It claimed CI does not cover the Windows redirection because
test:smokeran an explicit eight-file allowlist containing neither affected test — true when written, false now: #527 (2026-08-11) replaced that allowlist with the whole suite on both platforms, andmainalready carried a correction saying so. That correction is kept intact here rather than overwritten.What this PR adds to it:
lifecycle/prod-commands.test.tsalongsidedeploy-windows-script.test.ts, and a note that the PowerShell follow loop incli/prod.tsis exercised by nothing at all —Get-Contentand file-share semantics only exist at runtime on Windows.Two stale
%TEMP%\threadbase.errreferences now point at~/.threadbase/logs/stderr.log, which is whatprod logs --errors-onlyreads.Verification
tsc --noEmitclean;biome checkclean across 378 files, re-run after the rebase ontomain.The behaviour this changes is Windows-only and, as above, unreachable by CI — the follow loop needs a real Windows box. A manual verification script covering both-files-followed, truncation recovery,
--errors-only, and theRepair-LaunchCmdguard is ready to run and has not been run yet. The three test repairs are verifiable anywhere.