attribution: surface session fallback and unreadable session metadata · Entire
attribution: surface session fallback and unreadable session metadata
cf66e7a→main·
Soph·1mo ago·2 files·+66 added/-0 removed
Two silent-degradation paths in readCheckpointContext gave the user false confidence:
When a blamed file matched none of a checkpoint's sessions (e.g. it was renamed after the checkpoint), session selection silently fell back to the first session and presented its agent/prompt as exact. Track whether the match was by file, and when it was a multi-session fallback set a new SessionFallback flag;
entire whynow prints a "may have been renamed" hint.When a checkpoint's sessions all failed to read (summary present, per-session metadata unreadable), the line kept a confident [AI] tag with blank agent/model/prompt and no indication. Set MetadataMissing in that case so the existing "trailer-level attribution only" hint shows and the why path retries via remote fetch.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
7f9d62c609b2View transcript
Changes
2
cmd/entire/cli
Mattribution.go+30
Mattribution_test.go+36
65 unmodified lines
```
```go
package attribution
type fileAttributionResult struct {
Lines []lineAttribution `json:"lines"`
}
type lineAttribution struct {
Prompt string `json:"prompt,omitempty"`
Intent string `json:"intent,omitempty"`
MetadataMissing bool `json:"metadata_missing,omitempty"`
SessionFallback bool `json:"session_fallback,omitempty"`
Content string `json:"content"`
Candidates []attributionCandidate `json:"candidates,omitempty"`
}
Tests
TestAttributionFlagsSessionFallbackForUnmatchedFile
func TestAttributionFlagsSessionFallbackForUnmatchedFile(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "aab2c3d4e5f6", checkpoint.WriteCommittedOptions{
SessionID: "session-one-12345678",
Prompts: []string{"Edit the first file."},
FilesTouched: []string{"old_name.py"},
Agent: agent.AgentTypeClaudeCode,
CheckpointsCount: 1,
})
}
TestRunGitBlameWrapsExecError
func TestRunGitBlameWrapsExecError(t *testing.T) {
repoRoot := newAttributionRepo(t)
}