Skip to content

INTR-656 Reduce conversation checkpoint latency as tool outputs - #228

Merged
FarinM merged 3 commits into
mainfrom
intr-656-reduce-conversation-checkpoint-latency-as-tool-outputs
Oct 14, 2026
Merged

FarinM merged 3 commits into
mainfrom
intr-656-reduce-conversation-checkpoint-latency-as-tool-outputs

Conversation

@FarinM

@FarinM FarinM commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Conversation checkpoints staged every stored tool-output file with its own git.add call. Each call reads, updates and rewrites the whole Git index, including for outputs that did not change, so a checkpoint wrote the index once per output and got slower as outputs accumulated, even when the conversation change was one small file. A failed checkpoint was worse: the rollback reset every staged path with resetIndex, which rewrote the index once more per output.

This stages each checkpoint in one index update and makes the rollback touch only what changed:

  • Stage the context files and the tool-output directory in a single git.add, with parallel: false so output files are still read one at a time.
  • On a failed checkpoint, put back the index saved before staging, then walk HEAD's tree once and repair only the entries that differ from HEAD, instead of resetting every path. The saved index is not rewritten when it already matches, which is the common case when staging itself fails on a full disk.
  • The rollback takes the checkpoint's error. HEAD is only read again after an uncertain ref write; any other failure means the ref never moved.
Existing tool outputs Checkpoint before Checkpoint after Failed checkpoint before Failed checkpoint after
100 31 ms 14 ms 72 ms 21 ms
500 269 ms 59 ms 650 ms 90 ms
1,000 858 ms 115 ms 2,069 ms 173 ms
2,000 3,143 ms 227 ms 7,541 ms 343 ms

Index writes per checkpoint drop from one per output plus one to a single write, and a failed checkpoint drops from two per output plus two to three. Measurements are medians of 7 checkpoints per case on macOS arm64 with Bun 1.4.3, comparing the branch's base (e68038756) with 54e4be038. Each repository holds the given number of small tool-output files, and each checkpoint appends one turn to turns.jsonl while the outputs stay unchanged. The failed checkpoint fails at its first flush and includes the rollback. Every output is still read and hashed on each checkpoint, so the remaining cost still grows with the output count; the gain comes from writing the index once instead of once per output.

It also fixes cases where a single failed read silently lost data. The first three already exist on main; the last two are hazards the new staging and rollback would otherwise introduce:

  • isomorphic-git treats an index it fails to read as empty, so one failed read during git.add or git.commit could publish a tree without every other entry. The git file client now turns a failed or empty index read into an error and logs the real cause. A missing index still reads as empty, so new repositories work as before. This covers every isomorphic-git call in the package.
  • The rollback repaired entries with resetIndex, which reads HEAD and its tree again and treats a failed read as a deletion. One failed read could empty the conversation from the index, and the next audit or error commit would publish a tree without it. Repairs now write the oid and mode the walk already read with git.updateIndex, and report any failure.
  • resetIndex also wrote executable and symlink entries back as regular files. Repairs keep HEAD's file mode.
  • isomorphic-git reports a failed directory listing as an empty directory, so staging tool-output as one directory could drop new outputs without an error. A listing failure now fails the checkpoint and names the directory.
  • isomorphic-git reports a failed ref read as a missing ref. Before trusting "no commits yet", the rollback confirms it with reads that keep their error codes, so a failed HEAD read can no longer make it unstage every committed entry.

A tool-output path that is a symlink or a file is now rejected when writing or reading a spill and at checkpoint time, since git.add would stage a symlinked directory as a link without its outputs. The storage format and caller API are unchanged. INTR-661 tracks the same rollback problem in audit, error and mail commits, which still use resetIndex.

Validation: make lint, make build and make test-unit pass (9,205 tests). The storage-isogit suite has 227 tests, including fault injection for each failure above.

isomorphic-git treats an index it fails to read as empty, so one failed
read during staging or a commit could publish a tree that drops every
other entry.
Stage each checkpoint in one index update, and roll a failed one back
without resetting unchanged outputs, so accumulated tool outputs do not
cause repeated full-index rewrites. A symlinked tool-output directory is
rejected because the checkpoint tree must carry the outputs themselves.
resetIndex reads HEAD and its tree again for every path and treats a
failed read as a deletion, so one transient fault during a rollback
could drop committed entries without an error. Writing the oid and mode
the walk already read also keeps executable and symlink entries intact.
@linear

linear Bot commented Oct 14, 2026

Copy link
Copy Markdown

INTR-656

@FarinM FarinM changed the title Intr 656 reduce conversation checkpoint latency as tool outputs INTR-656 Reduce conversation checkpoint latency as tool outputs Oct 14, 2026
@FarinM
FarinM marked this pull request as ready for review October 14, 2026 18:17

@alexanderguy alexanderguy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@FarinM
FarinM merged commit 9ae4714 into main Oct 14, 2026
6 checks passed
@FarinM
FarinM deleted the intr-656-reduce-conversation-checkpoint-latency-as-tool-outputs branch October 14, 2026 22:08
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.

2 participants