Repository navigation
fix(decompile): repair a torn journal on Windows before resuming - #10527
Plastic-time wants to merge 2 commits into
Conversation
Windows opens an O_APPEND handle with FILE_APPEND_DATA only, so ftruncate through the journal's append handle fails with EPERM and every resume after an interrupted write was refused. Truncate through a separate write handle first, then open the append handle.
[Medium impact] The PR appears safe to merge. SummaryRepairs torn journals through a separate write handle before opening the append handle. This avoids the Windows restriction on truncating append-only handles.
Reviews (1) · Last reviewed commit: "docs(decompile): say why the journal ope..." · Reviewed by Greptile |
Codex Review Summary: ❌ FailedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
Summary
On Windows,
decompile_allwithresume: truerefused every export whose journal ended with a torn line. That is what an interrupted export leaves behind, so an interrupted export on Windows could not be resumed. The resume now drops the torn line and continues, as it already did on Linux and macOS.Fixes #10521
Problem and expected behavior
openResumedJournalopened the journal withO_WRONLY | O_APPENDand then calledtruncate(committedBytes)on that handle. On Windows, libuv opens anO_APPENDhandle withFILE_APPEND_DATAinstead ofFILE_WRITE_DATA, andSetEndOfFileneeds write-data access. The truncate failed withEPERM, and the resume returnedinvalid_request: "The decompile journal could not be repaired after an interrupted write."A minimal check on the same machine:
Change and scope
truncateJournalopens a separateO_WRONLY | O_NOFOLLOWhandle withoutO_APPEND, truncates, and closes it throughresources.ownFile. A failed truncate or close keeps the existing "could not be repaired" error.src/application/decompileDirectory/truncates, and no othersrc/file opens withO_APPEND.Contribution scope: ordinary fix within existing boundaries; maintainer scope decision not applicable.
Contract and boundary impact
Semantic owner and earliest changed stage:
openResumedJournalinexportTree.ts.Contribution scope fit and linked maintainer decision: not applicable.
CLI and MCP/tool-catalog contract: none.
Provider, bridge, target-format, or platform compatibility: Windows resume now works; Linux and macOS behavior is unchanged.
Evidence, artifact, provenance, or reconstruction contract: none.
Target selection, authority, upstream behavior, and cleanup details: the extra handle is owned and closed like the read handle in
readJournalBytes.Generated metadata, package, or installation impact: none.
Read existing files or captured data.
Change process memory, registers, files, or configuration. (the export's own journal, as before)
Evidence and regression coverage
src/application/decompileDirectory/decompileAll.test.tsalready cover this and fail on Windows: "resumes after a torn final journal line and keeps the journal parseable" and "repairs an invalid UTF-8 tail outside the committed journal". CI runs them only on Linux, where they pass.src/application/decompileDirectory/on main 9e24b36: 3 failed / 73 passed. With this change: 1 failed / 75 passed.EPERMfromsymlink).decompileAlland the real filesystem with a fake provider.Validation performed
Windows 11 Home 10.0.26200 x64, Node 24.22.1, base 9e24b36.
npx vitest run src/application/decompileDirectory/on main source: 3 failed / 73 passed.EPERMabove).npm run check:fast: passed (typecheck, lint)Compatibility, safety, and release
O_NOFOLLOWflag as the other journal opens.Author readiness
Human owner: @Plastic-time
Before merge
type(scope): outcome.