Skip to content

feat: add sidecar commit log for session timeline reconstruction#974

Draft
Soph wants to merge 5 commits intomainfrom
soph/experiment-tombstones
Draft

feat: add sidecar commit log for session timeline reconstruction#974
Soph wants to merge 5 commits intomainfrom
soph/experiment-tombstones

Conversation

@Soph
Copy link
Copy Markdown
Collaborator

@Soph Soph commented Apr 17, 2026

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.jsonl contains entries for all N commits — no backward lookup needed. The log is:

  • Built in-memory before condensation so it's included in the checkpoint tree it belongs to (not written too late)
  • Persisted to filesystem after condensation so the next checkpoint picks up the full timeline
  • Written to both v1 and v2 checkpoint trees via WriteCommittedOptions.CommitLog

What this enables (future)

  • Session timeline UI: Read one checkpoint → render full commit history with expandable details
  • Orphaned checkpoint detection: "There was a checkpoint here, but it was rebased away"
  • Foundation for Phase 2: Adding Change-Id trailers to capture mid-turn commits (without checkpoint trailers) in the timeline

What this does NOT change

  • No new git trailers
  • No changes to SaveStep, condensation logic, or session state machine
  • No tree-building changes (commits.jsonl flows through existing WriteCommittedOptions)
  • No consumers yet — this is write-side plumbing

Test plan

  • Unit tests: append/read round-trip, nonexistent file handling, commit subject extraction
  • Integration test: commits.jsonl present in v1 checkpoint tree after PostCommit
  • Integration test: second checkpoint contains entries for both commits (accumulation)
  • mise run check (fmt + lint + test:ci + e2e canary) passes

Note

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 CommitLog through WriteCommittedOptions, writes commits.jsonl into both v1 and v2 checkpoint trees, and updates the manual-commit PostCommit path to (1) build the full log before condensation, and (2) append the new entry to .entire/metadata/<session-id>/commits.jsonl after 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.

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
Copilot AI review requested due to automatic review settings April 17, 2026 08:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.jsonl payload in the checkpoint tree during PostCommit condensation.
  • Persist the same JSONL log to .entire/metadata/<session-id>/commits.jsonl so subsequent checkpoints accumulate prior entries.
  • Extend checkpoint stores (v1 and v2) to write WriteCommittedOptions.CommitLog into 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.

Comment on lines +29 to +33
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)
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +58
// 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) {
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +1289 to +1293
// 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],
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +417 to +421
// 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
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

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).

Copilot uses AI. Check for mistakes.
Soph and others added 4 commits April 17, 2026 17:40
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants