Skip to content

fix: no orphan .tmp copy when the archive rename fails; index archived conversations missing from the index - #201

Open
RoJLD wants to merge 1 commit into
obra:mainfrom
RoJLD:fix/windows-tmp-and-unindexed
Open

RoJLD wants to merge 1 commit into
obra:mainfrom
RoJLD:fix/windows-tmp-and-unindexed

Conversation

@RoJLD

@RoJLD RoJLD commented Nov 4, 2026

Copy link
Copy Markdown

Fixes #199 and #200.

#199: orphan *.jsonl.tmp.<pid> copies on Windows

copyIfNewer (src/sync.ts) copies to a temp file, then calls renameSync over the archive copy. On Windows that rename throws (EPERM/EBUSY) while another process holds the destination open, and the temp file was never removed. One install had accumulated 1,861 of them, about 98 GB, nearly all of them byte-identical to their final file or a prefix of it.

The rename now runs in a try/finally that always removes the temp file. It is retried a few times with a short backoff, then falls back to a direct copyFileSync onto the destination.

#200: archived conversations that are never re-indexed

verifyIndex flags a conversation only when its summary is missing or errored, or when it is already indexed and outdated. A conversation with a real summary and no row in exchanges (lastIndexed === null) fell through both checks. That happens after the database is rebuilt, for sessions that only exist in the archive because Claude Code already cleaned them from ~/.claude/projects.

  • VerificationResult gains unindexed.
  • An empty summary is still the permanent-skip sentinel (fix: sync silently stops summarizing when zero-exchange files queue up #91) and is never reported as unindexed.
  • repairIndex indexes unindexed conversations without calling the summarizer, since their summary already exists. Missing and outdated conversations behave as before.
  • index-cli verify prints Not in index: N and counts it as an issue.

Tests

test/tmp-cleanup-and-unindexed.test.ts:

  • renameSync mocked to throw EPERM: the archive copy is complete and no .tmp is left;
  • a conversation with a summary but no index rows is reported as unindexed (an empty-summary one is not), and repair indexes it without summarizing; a second verify reports nothing.

Both tests fail on main and pass with this change.

On Windows 11 with Node 26, the full suite gives the same 5 failures with and without this change, in file-lock, mcp-install-runner, parser and show. They are unrelated to this PR and already fail on main there.

dist/ is rebuilt for the four changed modules only.

Not included

#198 (tool_call duplication) is closed: ON DELETE CASCADE from #81 already prevents it on v1.6.0.

…d conversations missing from the index

- sync: copyIfNewer always removes its temp file. On Windows, renameSync throws (EPERM/EBUSY)
  while another process holds the destination open; it now retries, then falls back to a direct
  copy, so a failure never leaves a full *.jsonl.tmp.<pid> copy behind (obra#199).
- verify: a conversation that has a real (non-empty, non-errored) summary but no rows in the index
  is reported as `unindexed` (for example after the database was rebuilt, for sessions that only
  exist in the archive). repair indexes it without summarizing it again. `index-cli verify` prints
  the count (obra#200).
- test: tmp-cleanup-and-unindexed.test.ts covers both cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Orphan *.jsonl.tmp.<pid> copies accumulate on Windows when the archive rename fails

1 participant