feat: add sidecar commit log for session timeline reconstruction#974
feat: add sidecar commit log for session timeline reconstruction#974
Conversation
Record condensed commits in a per-session commits.jsonl sidecar file that accumulates across checkpoints. Each PostCommit appends an entry with the commit hash, subject, checkpoint ID, and timestamp. The log is built in-memory before condensation and passed through WriteCommittedOptions so it lands in the same checkpoint tree (both v1 and v2). After condensation the entry is also persisted to the filesystem so subsequent checkpoints in the session carry the full timeline forward. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 1649e70c9179
There was a problem hiding this comment.
Pull request overview
Adds write-side plumbing for a per-session sidecar commit log (commits.jsonl) so a session’s commit timeline can be reconstructed from any single checkpoint without scanning git history.
Changes:
- Build and include an accumulated
commits.jsonlpayload in the checkpoint tree during PostCommit condensation. - Persist the same JSONL log to
.entire/metadata/<session-id>/commits.jsonlso subsequent checkpoints accumulate prior entries. - Extend checkpoint stores (v1 and v2) to write
WriteCommittedOptions.CommitLoginto the checkpoint tree, and add unit/integration tests for the new log helpers and v1 checkpoint presence.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| cmd/entire/cli/strategy/manual_commit_hooks.go | Builds commit log entry/bytes pre-condensation and appends the new entry to the filesystem after successful condensation. |
| cmd/entire/cli/strategy/manual_commit_condensation.go | Threads pre-built commit log bytes through condensation into WriteCommittedOptions. |
| cmd/entire/cli/strategy/commit_log.go | New helper module to append/read/build commit log JSONL and extract commit subjects. |
| cmd/entire/cli/strategy/commit_log_test.go | Adds unit tests for commit log helpers plus integration coverage for v1 checkpoint tree inclusion/accumulation. |
| cmd/entire/cli/paths/paths.go | Introduces CommitLogFileName = "commits.jsonl". |
| cmd/entire/cli/checkpoint/checkpoint.go | Adds WriteCommittedOptions.CommitLog []byte field (write-side). |
| cmd/entire/cli/checkpoint/committed.go | Writes commits.jsonl into the v1 committed checkpoint session subdirectory when provided. |
| cmd/entire/cli/checkpoint/v2_committed.go | Writes commits.jsonl into the v2 /main session subdirectory when provided. |
| func appendCommitLogEntry(ctx context.Context, sessionID string, entry CommitLogEntry) error { | ||
| sessionDir := paths.SessionMetadataDirFromSessionID(sessionID) | ||
| sessionDirAbs, err := paths.AbsPath(ctx, sessionDir) | ||
| if err != nil { | ||
| return fmt.Errorf("resolving session dir: %w", err) |
There was a problem hiding this comment.
commit_log.go builds filesystem paths from sessionID (via SessionMetadataDirFromSessionID) without validating it here. To avoid path traversal risks and match other call sites (checkpoint stores), validate sessionID with validation.ValidateSessionID in these helpers. Also ensure the session metadata directory exists (os.MkdirAll(sessionDirAbs, ...)) before attempting to OpenFile, otherwise the append will fail if the directory is missing and commit-log accumulation will silently stop.
| // readCommitLog reads all entries from a session's commit log. | ||
| // Returns an empty slice (not an error) if the file does not exist. | ||
| func readCommitLog(ctx context.Context, sessionID string) ([]CommitLogEntry, error) { |
There was a problem hiding this comment.
The readCommitLog docstring says it returns an empty slice when the file doesn’t exist, but the implementation returns a nil slice. Either return an empty slice to match the comment, or update the comment to explicitly say it returns nil.
| // Build commit log entry and full log bytes BEFORE condensation so they | ||
| // are included in the checkpoint tree written by CondenseSession. | ||
| newEntry := CommitLogEntry{ | ||
| Hash: commit.Hash.String(), | ||
| ShortHash: commit.Hash.String()[:7], |
There was a problem hiding this comment.
commitLogBytes is built (including a filesystem read of commits.jsonl) before TransitionAndLog, even though the handler may later decide not to condense this session. Consider deferring buildCommitLog until just before calling condenseAndUpdateState (e.g., inside HandleCondense/HandleCondenseIfFilesTouched) to avoid unnecessary IO/work for sessions that won’t write a checkpoint.
| // Write commit log (session timeline of condensed commits) | ||
| if len(opts.CommitLog) > 0 { | ||
| blobHash, err := CreateBlobFromContent(s.repo, opts.CommitLog) | ||
| if err != nil { | ||
| return filePaths, err |
There was a problem hiding this comment.
This adds a new persisted artifact to the v2 /main checkpoint tree (commits.jsonl) but there doesn’t appear to be any unit coverage asserting it’s written/readable for v2. Please add a v2 store test that sets WriteCommittedOptions.CommitLog and verifies the blob exists at the expected path in the /main ref tree (similar to existing v2 metadata/prompt/compact transcript assertions).
Entire-Checkpoint: 52daa2ddb6d4
Entire-Checkpoint: 1cfa38d5aed9
- Add os.MkdirAll before file open in appendCommitLogEntry to handle missing session metadata directory - Fix readCommitLog docstring (returns nil, not empty slice) - Defer buildCommitLog IO to HandleCondense/HandleCondenseIfFilesTouched so filesystem reads only happen when condensation will proceed - Use 0750 directory permissions per gosec Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 48c34d66a788
Verify CommitLog bytes are written to and readable from both v1 (entire/checkpoints/v1) and v2 (refs/entire/checkpoints/v2/main) checkpoint trees. Also test that empty CommitLog produces no blob. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Entire-Checkpoint: a5ebd5630a65
Summary
Add a sidecar commit log that enables session timeline reconstruction from any checkpoint, without complex cross-referencing or git log scanning.
The problem
Today, if you want to see "what commits happened during this session," you'd need to cross-reference checkpoint IDs across git history, session metadata, and the checkpoint branch. For a UI timeline view — where you pick checkpoint 4 and want to see the full session history including checkpoints 1-3 — this requires expensive backward lookups across potentially weeks of git history.
The approach
Each time PostCommit condenses a session, we append a one-line JSON entry to
.entire/metadata/<session-id>/commits.jsonl:{"hash":"abc123...","short_hash":"abc123d","subject":"Add login","timestamp":"2026-04-16T12:11:06Z","checkpoint_id":"a3b2c4d5e6f7","session_id":"..."}This file accumulates across the session. When checkpoint N is condensed, its
commits.jsonlcontains entries for all N commits — no backward lookup needed. The log is:WriteCommittedOptions.CommitLogWhat this enables (future)
Change-Idtrailers to capture mid-turn commits (without checkpoint trailers) in the timelineWhat this does NOT change
commits.jsonlflows through existingWriteCommittedOptions)Test plan
commits.jsonlpresent in v1 checkpoint tree after PostCommitmise run check(fmt + lint + test:ci + e2e canary) passesNote
Medium Risk
Adds new checkpoint artifacts and hook-time filesystem writes to capture a per-session commit timeline; risk is mainly around correctness of checkpoint tree writes and accumulation behavior across commits (both v1 and v2).
Overview
Adds a sidecar commit timeline log (
commits.jsonl) that accumulates one JSONL entry per condensed commit and is included in the checkpoint’s session directory, enabling reconstruction of the full session commit history from any checkpoint.This threads
CommitLogthroughWriteCommittedOptions, writescommits.jsonlinto both v1 and v2 checkpoint trees, and updates the manual-commitPostCommitpath to (1) build the full log before condensation, and (2) append the new entry to.entire/metadata/<session-id>/commits.jsonlafter a successful condensation. Includes unit/integration tests covering append/read behavior and accumulation across multiple checkpoints.Reviewed by Cursor Bugbot for commit 980eec1. Configure here.