dedupe committed summary helpers · Entire

dedupe committed summary helpers

27b0e0d·

pfleidi·4w ago·2 files·+2 added/-96 removed

Route legacy summary updates through the session update API and reuse the committed checkpoint reader from attribution code.

This keeps committed read/write behavior centralized without changing the public call sites.

Sessions

854458fe9b0aView transcript

Changes

2

405 unmodified lines

406
407
408
409
409
410
411
412
71 unmodified lines

484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
487
488
489

405 unmodified lines

func (r *attributionResolver) readCheckpointContext(cpID id.CheckpointID, file string) attributionCheckpointContext {
    ctx := attributionCheckpointContext{CheckpointID: cpID.String()}
    summary, err := readAttributionCheckpointSummary(r.ctx, r.store, cpID)
    summary, err := checkpoint.ReadCommittedCheckpoint(r.ctx, r.store, cpID)
    if err != nil && r.fetchOnMiss {
        if fetched, fetchErr := r.fetchCheckpointContext(cpID, file); fetchErr == nil {
            return fetched
        }
    }
    return ctx
}

func readAttributionCheckpointSummary(ctx context.Context, reader committedCheckpointReader, cpID id.CheckpointID) (*checkpoint.CheckpointSummary, error) {
    if err := ctx.Err(); err != nil {
        return nil, err //nolint:wrapcheck // Propagating context cancellation
    }
    summary, err := reader.ReadCheckpoint(ctx, cpID)
    if err != nil {
        return nil, fmt.Errorf("read committed checkpoint: %w", err)
    }
    if summary == nil {
        return nil, checkpoint.ErrCheckpointNotFound
    }
    return summary, nil
}

func enrichAttributionLineWithFetch(ctx context.Context, file string, line *attributionLine, checkpoints map[string]attributionCheckpointContext) error {
    if line == nil || len(line.Candidates) == 0 {
        return nil
    }

Mcmd/entire/cli/attribution.go+1/-15

1349 unmodified lines

1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1353
1354
1355
1356

// UpdateSummary updates the summary field in the latest session's metadata.
// Returns ErrCheckpointNotFound if the checkpoint doesn't exist.
func (s *GitStore) UpdateSummary(ctx context.Context, checkpointID id.CheckpointID, summary *Summary) error {
    if err := ctx.Err(); err != nil {
        return err //nolint:wrapcheck // Propagating context cancellation
    }

// Ensure sessions branch exists
    if err := s.ensureSessionsBranch(ctx); err != nil {
        return fmt.Errorf("failed to ensure sessions branch: %w", err)
    }

// Get branch ref and root tree hash (O(1), no flatten)
    parentHash, rootTreeHash, err := s.getSessionsBranchRef()
    if err != nil {
        return err
    }

// Flatten only the checkpoint subtree
    basePath := checkpointID.Path() + "/"
    checkpointPath := checkpointID.Path()
    entries, err := s.flattenCheckpointEntries(rootTreeHash, checkpointPath)
    if err != nil {
        return err
    }

// Read root CheckpointSummary to find the latest session
    rootMetadataPath := basePath + paths.MetadataFileName
    entry, exists := entries[rootMetadataPath]
    if !exists {
        return ErrCheckpointNotFound
    }

checkpointSummary, err := s.readSummaryFromBlob(entry.Hash)
    if err != nil {
        return fmt.Errorf("failed to read checkpoint summary: %w", err)
    }

// Find the latest session's metadata path (0-based indexing)
    latestIndex := len(checkpointSummary.Sessions) - 1
    sessionMetadataPath := fmt.Sprintf("%s%d/%s", basePath, latestIndex, paths.MetadataFileName)
    sessionEntry, exists := entries[sessionMetadataPath]
    if !exists {
        return fmt.Errorf("session metadata not found at %s", sessionMetadataPath)
    }

// Read and update session metadata
    existingMetadata, err := s.readMetadataFromBlob(sessionEntry.Hash)
    if err != nil {
        return fmt.Errorf("failed to read session metadata: %w", err)
    }

// Update the summary
    existingMetadata.Summary = redactSummary(summary)

// Write updated session metadata
    metadataJSON, err := jsonutil.MarshalIndentWithNewline(existingMetadata, "", "  ")
    if err != nil {
        return fmt.Errorf("failed to marshal metadata: %w", err)
    }
    metadataHash, err := CreateBlobFromContent(s.repo, metadataJSON)
    if err != nil {
        return fmt.Errorf("failed to create metadata blob: %w", err)
    }
    entries[sessionMetadataPath] = object.TreeEntry{
        Name: sessionMetadataPath,
        Mode: filemode.Regular,
        Hash: metadataHash,
    }

// Build checkpoint subtree and splice into root (O(depth) tree surgery)
    newTreeHash, err := s.spliceCheckpointSubtree(ctx, rootTreeHash, checkpointID, basePath, entries)
    if err != nil {
        return err
    }

authorName, authorEmail := GetGitAuthorFromRepo(s.repo)
    commitMsg := fmt.Sprintf("Update summary for checkpoint %s (session: %s)", checkpointID, existingMetadata.SessionID)
    newCommitHash, err := s.createCommit(ctx, newTreeHash, parentHash, commitMsg, authorName, authorEmail)
    if err != nil {
        return err
    }

return s.setPrimaryRef(newCommitHash)
    return s.UpdateSession(ctx, LatestSessionRef(checkpointID), WithSummary(summary))
}

// UpdateCommitted replaces the transcript, prompts, and context for an existing