api/checkpoint: add CompactTranscriptStart marker to session metadata · Entire
api/checkpoint: add CompactTranscriptStart marker to session metadata
ed36714 → main
Add CompactTranscriptStart *int (compact_transcript_start) plus a GetCompactTranscriptStart accessor. transcript.jsonl now stores the full compacted session, so this marks where a checkpoint's slice begins: compactLines[CompactTranscriptStart:].
A pointer is used so "absent" (a legacy checkpoint whose transcript.jsonl holds only its delta, read from line 0) is distinguishable from 0 (a full file whose first checkpoint starts at the beginning).
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
Changes
2
api/checkpoint
Mmetadata.go +24/-1
- Mmetadata_test.go +57/-1
320 unmodified lines
// Transcript position at checkpoint start - tracks what was added during this checkpoint
TranscriptIdentifierAtStart string `json:"transcript_identifier_at_start,omitempty"` // Last identifier when checkpoint started (UUID for Claude, message ID for Gemini)
CheckpointTranscriptStart int `json:"checkpoint_transcript_start,omitempty"` // Transcript line offset at start of this checkpoint's data
CheckpointTranscriptStart int `json:"checkpoint_transcript_start,omitempty"` // Raw transcript (full.jsonl) line offset at start of this checkpoint's data
// Deprecated: Use CheckpointTranscriptStart instead. Written for backward compatibility with older CLI versions.
TranscriptLinesAtStart int `json:"transcript_lines_at_start,omitempty"`
// CompactTranscriptStart is the line offset in the compact transcript.jsonl
// at which this checkpoint's data begins. transcript.jsonl stores the full
// compacted session (each checkpoint is self-contained), so readers segment
// this checkpoint's slice as compactLines[CompactTranscriptStart:].
//
// A nil pointer marks a legacy checkpoint whose transcript.jsonl holds only
// this checkpoint's delta (CLI versions before the full-compact-transcript
// change), which is read as-is from line 0. A pointer is used so that "absent"
// (legacy delta file) is distinguishable from 0 (full file, first checkpoint).
CompactTranscriptStart *int `json:"compact_transcript_start,omitempty"`
// Token usage for this checkpoint
TokenUsage *types.TokenUsage `json:"token_usage,omitempty"`
return m.TranscriptLinesAtStart
}
// GetCompactTranscriptStart returns the line offset in transcript.jsonl at which
// this checkpoint's data begins, and whether the offset was recorded. ok=false
// means a legacy checkpoint whose transcript.jsonl holds only this checkpoint's
delta (read it from line 0); ok=true with offset 0 means the full-compact file
// whose first checkpoint starts at the beginning.
func (m Metadata) GetCompactTranscriptStart() (offset int, ok bool) {
if m.CompactTranscriptStart == nil {
return 0, false
}
return *m.CompactTranscriptStart, true
}
// SessionFilePaths contains the absolute paths to session files from the git tree root.
// Paths include the full checkpoint path prefix (e.g., "/a1/b2c3d4e5f6/1/metadata.json").
// Used in CheckpointSummary.Sessions to map session IDs to their file locations.
package checkpoint
import "testing"
import (
"encoding/json"
"strings"
"testing"
)
func TestImportedFlagsOnSummaryAndInfo(t *testing.T) {
t.Parallel()
}
func TestGetCompactTranscriptStart(t *testing.T) {
t.Parallel()
// nil pointer = legacy checkpoint whose transcript.jsonl holds only the delta.
if offset, ok := (Metadata{}).GetCompactTranscriptStart(); ok || offset != 0 {
t.Fatalf("nil: got (%d, %v), want (0, false)", offset, ok)
}
// Pointer to 0 = full compact file whose first checkpoint starts at line 0.
// Must be distinguishable from the nil (legacy) case above.
zero := 0
if offset, ok := (Metadata{CompactTranscriptStart: &zero}).GetCompactTranscriptStart(); !ok || offset != 0 {
t.Fatalf("&0: got (%d, %v), want (0, true)", offset, ok)
}
five := 5
if offset, ok := (Metadata{CompactTranscriptStart: &five}).GetCompactTranscriptStart(); !ok || offset != 5 {
t.Fatalf("&5: got (%d, %v), want (5, true)", offset, ok)
}
}
func TestCompactTranscriptStart_JSONRoundTrip(t *testing.T) {
t.Parallel()
// nil is omitted entirely, so legacy readers see no field.
b, err := json.Marshal(Metadata{})
if err != nil {
t.Fatalf("marshal: %v", err)
}
if strings.Contains(string(b), "compact_transcript_start") {
t.Fatalf("nil pointer should be omitted, got: %s", b)
}
// A set value (including 0) round-trips and stays distinguishable from absent.
zero := 0
b, err = json.Marshal(Metadata{CompactTranscriptStart: &zero})
if err != nil {
t.Fatalf("marshal: %v", err)
}
if !strings.Contains(string(b), `"compact_transcript_start":0`) {
t.Fatalf("expected explicit 0 in JSON, got: %s", b)
}
var got Metadata
if err := json.Unmarshal(b, &got); err != nil {
t.Fatalf("unmarshal: %v", err)
}
if offset, ok := got.GetCompactTranscriptStart(); !ok || offset != 0 {
t.Fatalf("round-trip: got (%d, %v), want (0, true)", offset, ok)
}
}