cleanup: track archived sessions in multi-session checkpoints · Entire

cleanup: track archived sessions in multi-session checkpoints

4314a63→main·

pfleidi·1mo ago·2 files·+62 added/-0 removed

ListOrphanedSessionStates previously indexed only cp.SessionID (the most-recent session of a multi-session checkpoint). Archived sessions whose IDs appear in cp.SessionIDs but not cp.SessionID were treated as having no checkpoints and could be flagged for deletion if their shadow branch had already been condensed.

Track every session ID the checkpoint contributed to, so condensed sessions stay reachable to the orphan check.

Sessions

df56ed33e7ecView transcript

Changes

2

529 unmodified lines

530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588

529 unmodified lines

}

assert.True(t, flagged, "session must be flagged orphaned: mirror is unset, so topology read returns no checkpoints")

// Archived sessions of a multi-session condensed checkpoint must not be
// flagged as orphaned: their IDs appear in cp.SessionIDs even though
// cp.SessionID is the most-recent session.
func TestListOrphanedSessionStates_MultiSessionArchivedNotOrphaned(t *testing.T) {

dir := t.TempDir()
testutil.InitRepo(t, dir)
testutil.WriteFile(t, dir, "f.txt", "init")
testutil.GitAdd(t, dir, "f.txt")
testutil.GitCommit(t, dir, "init")

t.Chdir(dir)

repo, err := git.PlainOpen(dir)
require.NoError(t, err)

cpID := id.MustCheckpointID("c3d4e5f6a1b2")
const archivedSessionID = "archived-session"
const latestSessionID = "latest-session"

// Two sequential writes with the same checkpoint ID produce a multi-session
// checkpoint: the second write archives the first session under <sharded>/0
// and lists both IDs in SessionIDs.
store := checkpoint.NewGitStore(repo)
for _, sid := range []string{archivedSessionID, latestSessionID} {
    require.NoError(t, store.WriteCommitted(t.Context(), checkpoint.WriteCommittedOptions{
        CheckpointID: cpID,
        SessionID:    sid,
        Strategy:     "manual-commit",
        Transcript:   redact.AlreadyRedacted([]byte("transcript\n")),
        Prompts:      []string{"prompt-" + sid},
        AuthorName:   "Test",
        AuthorEmail:  "test@test.com",
    }))
}

staleStart := time.Now().Add(-(sessionGracePeriod + time.Minute))
for _, sid := range []string{archivedSessionID, latestSessionID} {
    require.NoError(t, SaveSessionState(t.Context(), &SessionState{
        SessionID:  sid,
        BaseCommit: "0000000000000000000000000000000000000000",
        StartedAt:  staleStart,
        StepCount:  1,
    }))
}

orphans, err := ListOrphanedSessionStates(t.Context())
require.NoError(t, err)

for _, item := range orphans {
    assert.NotEqual(t, archivedSessionID, item.ID,
        "archived session in multi-session checkpoint must not be flagged orphaned")
    assert.NotEqual(t, latestSessionID, item.ID,
        "latest session in multi-session checkpoint must not be flagged orphaned")
}
}

Mcmd/entire/cli/strategy/clean_test.go+56

174 unmodified lines

175
176
177
178
179
180
181
182
183
184
185
186
187

174 unmodified lines

checkpoints, listErr := cpStore.ListCommitted(ctx)
if listErr == nil {
    for _, cp := range checkpoints {
        // cp.SessionID is the most-recent session in a multi-session checkpoint;
        // cp.SessionIDs lists every session that contributed. Track all of them so
        // archived sessions of condensed checkpoints aren't flagged as orphaned.
        sessionsWithCheckpoints[cp.SessionID] = true
        for _, sid := range cp.SessionIDs {
            sessionsWithCheckpoints[sid] = true
        }
    }
}

Mcmd/entire/cli/strategy/cleanup.go+6