attribution: collapse duplicate candidate/context structs into one type · Entire
attribution: collapse duplicate candidate/context structs into one type
0326b95→main
Soph·1mo ago·1 file·+10 added/-21 removed
attributionCandidate and attributionCheckpointContext declared identical field lists with identical JSON tags, kept in sync only by a candidateFromContext() cast. Adding a field meant editing both. Alias attributionCandidate to attributionCheckpointContext so there is one definition, and drop the now-noop conversion helper.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
91b11a441843View transcript
[?
Attribution Bugs and Refactoring in CLIClaude Code·Opus 4.8[1m]·1 step](/content/gh/entireio/cli/session/d7c3cef2-8708-4e89-a62c-82d2933a3246#timeline-91b11a441843/index.html)
Changes
1
cmd/entire/cli
Mattribution.go+10/-21
69 unmodified lines
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
73
74
75
76
77
78
79
80
81
6 unmodified lines
88
89
90
91
92
93
94
95
263 unmodified lines
359
360
361
366
362
363
364
365
109 unmodified lines
475
476
477
482
478
479
480
481
559 unmodified lines
1041
1042
1043
1048
1049
1050
1051
1052
1053
1054
1044
1045
1046
69 unmodified lines
Candidates []attributionCandidate `json:"candidates,omitempty"`
}
type attributionCandidate struct {
CheckpointID string `json:"checkpoint_id"`
SessionID string `json:"session_id,omitempty"`
Agent string `json:"agent,omitempty"`
Model string `json:"model,omitempty"`
Prompt string `json:"prompt,omitempty"`
Intent string `json:"intent,omitempty"`
FilesTouched []string `json:"files_touched,omitempty"`
MetadataMissing bool `json:"metadata_missing,omitempty"`
Mixed bool `json:"mixed,omitempty"`
}
// attributionCheckpointContext is the resolved metadata for one checkpoint as
// it applies to a file: the agent/session that produced the file's lines plus
// the prompt and intent behind them. The same shape is used two ways — as a
// per-line candidate (one line may map to several checkpoints) and as the
// deduplicated per-file checkpoint map — so attributionCandidate aliases it
// rather than duplicating the fields.
type attributionCheckpointContext struct {
CheckpointID string `json:"checkpoint_id"`
SessionID string `json:"session_id,omitempty"`
6 unmodified lines
Mixed bool `json:"mixed,omitempty"`
}
type attributionCandidate = attributionCheckpointContext
type fileAttributionResult struct {
File string `json:"file"`
Lines []attributionLine `json:"lines"`
263 unmodified lines
var candidates []attributionCandidate
for _, cpID := range cpIDs {
candidates = append(candidates, candidateFromContext(r.checkpointContext(cpID, file)))
candidates = append(candidates, r.checkpointContext(cpID, file))
}
preferred := preferredAttributionCandidate(candidates, file)
109 unmodified lines
}
cpCtx := resolver.checkpointContext(cpID, file)
checkpoints[cpCtx.CheckpointID] = cpCtx
candidates = append(candidates, candidateFromContext(cpCtx))
candidates = append(candidates, cpCtx)
}
preferred := preferredAttributionCandidate(candidates, file)
applyPreferredToLine(line, preferred)
559 unmodified lines
}
}
// candidateFromContext projects the resolved checkpoint context onto a
// per-line candidate. The two structs carry the same fields, so this is a
// direct conversion — if they ever diverge, this stops compiling.
func candidateFromContext(ctx attributionCheckpointContext) attributionCandidate {
return attributionCandidate(ctx)
}
// applyPreferredToLine copies the preferred candidate's metadata onto the line.
// It does not touch line.Authorship; callers decide how Mixed maps to authorship.
func applyPreferredToLine(line *attributionLine, preferred *attributionCandidate) {
Mcmd/entire/cli/attribution.go+10/-21