fix(coding-agent): repair incomplete session JSONL tails - #959
Conversation
|
@snimu This is ready for review. It repairs incomplete JSONL tails atomically before a resumed append while preserving valid unterminated records, read-only open behavior, retry safety, metadata, and branched sessions. Independent review is clean. All required CI checks pass at |
|
Thank you for the report and proposed work. This root cause is now covered by maintainer-owned stacked PR #1160, authored independently from We did not inspect or reuse this PR's diff, branch, commits, implementation code, or tests; its public description/comments were used only as a bug report. To keep one review surface, this PR is superseded by #1160 and is being closed. The complete review stack is #1158–#1165. It is being left unmerged for human review after CI and review-bot findings are cleared. |
What changed
getFileRecovery().Why
The session loaders either accepted a complete final JSON record without a newline or skipped an incomplete final fragment.
SessionManagerthen treated the file as flushed, so the next fast-path append started at the existing EOF and concatenated the new entry with those terminal bytes.Impact
Resuming and writing to an interrupted session now preserves all earlier valid records and allows the next entry to round-trip. Catalog, export, and other read-only opens do not modify session files. Repair uses same-directory atomic replacement and preserves the existing file metadata and symlink target behavior.
Checks
npx tsx ../../node_modules/vitest/dist/cli.js --run test/suite/regressions/928-jsonl-tail-repair.test.tsnpm run checkFixes #928
Note
Fix incomplete JSONL tail repair in
SessionManagerto prevent bad concatenation on resumerepairUnterminatedSessionTailwhich either appends a newline (if the final record is valid JSON) or truncates the file to discard an incomplete record.replaceFileAtomically, writing to a temp file in the same directory then renaming, preserving prior file ownership and mode.needsTailRepairflag so the next persist triggers a rewrite rather than concatenating onto a broken tail.getFileRecovery()accessor onSessionManagerexposing details of the last repair performed (action, original size, repaired size, discarded bytes).Macroscope summarized a7d7490.