Documentation
¶
Overview ¶
Package reporting assembles per-file scores into aggregate attribution results. It is a pure domain package with no infrastructure dependencies.
Index ¶
- func AILines(fs *FileScoreInput) int
- func AssembleCheckpointNotes(pipelineNote string) []string
- func AssembleCommitNotes(pipelineNote string, cr CommitResult) []string
- func CommitEvidence(files []FileAttributionOutput) (level string, fallbackCount int)
- func EvidenceExplanation(level string, fallbackCount int) string
- func IsFallbackEvidence(c EvidenceClass) bool
- func RenderDiagnosticNote(in DiagnosticsInput) string
- type AggregateResult
- type CheckpointDiagnostics
- type CheckpointResult
- type CheckpointResultInput
- type CommitResult
- type CommitResultInput
- type DiagnosticsInput
- type EventStatsInput
- type EvidenceClass
- type FileAttributionOutput
- type FileChangeOutput
- type FileScoreInput
- type MatchStatsInput
- type ProviderAttribution
- type TouchOrigin
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AILines ¶
func AILines(fs *FileScoreInput) int
AILines returns the total AI lines (exact + formatted + modified) for a single file score input. ProviderOnlyLines is deliberately excluded; callers that need the full provider-touched count read ProviderOnlyLines directly.
func AssembleCheckpointNotes ¶ added in v0.3.4
AssembleCheckpointNotes is the checkpoint-only equivalent of AssembleCommitNotes. Checkpoint attribution has no line-level scoring, no fallback count, and no per-file evidence classes, so the result is just the pipeline-state note wrapped in a slice (or nil when empty). Kept as a named helper so the CLI's call sites do not sprout ad-hoc "wrap a string in a slice" code.
func AssembleCommitNotes ¶ added in v0.3.4
func AssembleCommitNotes(pipelineNote string, cr CommitResult) []string
AssembleCommitNotes builds the combined notes bundle for a commit attribution. The pipeline-state note (if non-empty) leads; factual notes derived from the commit result (weaker fallback signals, carry-forward, deletion inference) follow.
Used by both the CLI's attribution-display command and the push payload builder so both surfaces emit the same bundle. The wire shape is `notes []string`; the CLI display iterates the same slice and formats it as a bulleted list.
func CommitEvidence ¶ added in v0.2.3
func CommitEvidence(files []FileAttributionOutput) (level string, fallbackCount int)
CommitEvidence computes the evidence level, score, and fallback count from per-file evidence using a weighted formula.
Line-evidence score (0-1): LineScore = (1.00*Exact + 0.85*Normalized + 0.55*Modified) / max(1, AILines) File-evidence penalty (0-1): FallbackPenalty = (0.18*Tdt + 0.18*Tpd + 0.30*Tpc + 0.25*CF + 0.35*D) / max(1, AIFiles)
Tool-delta and provider touches use the same weight. Combined score: Score = clamp(LineScore - FallbackPenalty, 0, 1)
Buckets:
High: Score >= 0.75 Medium: 0.45 <= Score < 0.75 Low: Score < 0.45
Thresholds may be tuned as the evaluation corpus grows.
Fallback bucket selection walks AllEvidence (not PrimaryEvidence) so a file with line-level evidence plus weaker corroboration (e.g. modified + provider_touch) still contributes to the penalty term. Each file counts at most once toward fallbackCount and toward at most one of tpd/tpc/cf/del, picking the strongest fallback class present in AllEvidence.
func EvidenceExplanation ¶ added in v0.2.3
EvidenceExplanation describes an evidence level.
func IsFallbackEvidence ¶ added in v0.3.9
func IsFallbackEvidence(c EvidenceClass) bool
IsFallbackEvidence reports whether an evidence class indicates the file's attribution required a non-line-level signal. Fallback classes pull commit-level strength down via the penalty term in CommitEvidence.
func RenderDiagnosticNote ¶
func RenderDiagnosticNote(in DiagnosticsInput) string
RenderDiagnosticNote produces a human-readable diagnostic note explaining why a particular AI percentage was computed. When AI% is 0 it identifies which pipeline stage had no data. When AI% > 0 and non-exact matches contributed, it breaks down the match tiers.
Types ¶
type AggregateResult ¶
type AggregateResult struct {
Percent float64
TotalLines int
AILines int
ExactLines int // tier 1: exact trimmed match
ModifiedLines int // tier 0 with hunk overlap
FormattedLines int // tier 2: whitespace-normalized match
ProviderOnlyLines int // provider-touch only, excluded from headline
FilesTouched int // unique files in the diff
Providers []ProviderAttribution
}
AggregateResult contains the full attribution breakdown produced by AggregatePercent. The Percent field is the headline number; the remaining fields support richer commit trailers and diagnostics.
ProviderOnlyLines is the count of lines attributed by provider-touch alone (no line-level evidence). Reported here for sidecar rendering; deliberately not included in AILines or Percent.
func AggregatePercent ¶
func AggregatePercent(scores []FileScoreInput, providerModel map[string]string, filesTouched int) AggregateResult
AggregatePercent reduces per-file scores into a single AggregateResult with provider breakdown sorted by AI lines (descending), then name.
Provider-only lines are tracked separately and excluded from the headline Percent. The provider breakdown carries them on a distinct field (ProviderOnlyLines) so a consumer rendering the breakdown can show line-level and provider-only counts side by side without conflating evidence strengths.
type CheckpointDiagnostics ¶
type CheckpointDiagnostics struct {
EventsConsidered int
EventsAssistant int
PayloadsLoaded int
AIToolEvents int
Notes []string
}
CheckpointDiagnostics holds event stats and diagnostic notes for checkpoint-only blame results. Notes carries the pipeline-state message wrapped as a slice so the shape matches the commit-path AttributionDiagnostics - both CLI display and push paths iterate the same slice.
type CheckpointResult ¶
type CheckpointResult struct {
CheckpointID string
FilesAITouched int
FilesTotal int
FilesEdited []FileChangeOutput
Diagnostics CheckpointDiagnostics
}
CheckpointResult is the attribution result for a checkpoint without a linked commit. It reports AI activity but has no line-level scores.
func BuildCheckpointResult ¶
func BuildCheckpointResult(in CheckpointResultInput) CheckpointResult
BuildCheckpointResult assembles a checkpoint-only attribution result. Checkpoint blame has no diff and no line-level scoring - it reports which files were touched by AI and event-level diagnostics.
type CheckpointResultInput ¶
type CheckpointResultInput struct {
CheckpointID string
TouchedFiles map[string]bool // AI-touched file paths
EventStats EventStatsInput // for diagnostics
}
CheckpointResultInput holds the narrow inputs for assembling a checkpoint-only attribution result (no diff, no line-level scoring).
type CommitResult ¶
type CommitResult struct {
AIExactLines int
AIFormattedLines int
AIModifiedLines int
AIProviderOnlyLines int // provider-touch only, excluded from headline
// Tool-delta subsets of the exact and formatted totals.
AIDeltaExactLines int
AIDeltaFormattedLines int
AILines int // exact + formatted + modified
HumanLines int
TotalLines int
AIPercentage float64 // (exact + formatted + modified) / total * 100
FilesAITouched int
FilesTotal int // created + edited (excludes deleted)
FilesCreated []FileChangeOutput
FilesEdited []FileChangeOutput
FilesDeleted []FileChangeOutput
Files []FileAttributionOutput
ProviderDetails []ProviderAttribution
Evidence string // evidence-strength level: "High", "Medium", "Low"
FallbackCount int // number of AI-attributed files with provider-touch or weaker evidence
}
CommitResult is the full attribution breakdown for a single commit, produced by BuildCommitResult.
AIProviderOnlyLines is reported separately and not summed into AILines or AIPercentage. Callers that want a "files touched by AI but without line-level evidence" sidecar read from here.
func BuildCommitResult ¶
func BuildCommitResult(in CommitResultInput) CommitResult
BuildCommitResult assembles a full commit attribution result from scored file data, diff metadata, and candidate metadata. It builds per-file attribution rows, headline totals, file change lists, and provider details.
type CommitResultInput ¶
type CommitResultInput struct {
FileScores []FileScoreInput // one per diff file, in diff order
FilesCreated []string // paths created (from /dev/null)
FilesDeleted []string // paths deleted (to /dev/null)
TouchedFiles map[string]bool // AI-touched file paths (for AI flag on file changes)
ProviderModels map[string]string // provider -> model
FileProviders map[string][]string // file -> providers sorted desc by matched line count
FileTouchOrigins map[string]TouchOrigin // per-file touch provenance (for evidence classification)
CarryForwardFiles map[string]bool // files attributed via carry-forward
}
CommitResultInput holds the narrow inputs needed to assemble a full commit attribution result from scored data and diff metadata.
FileProviders carries the ordered list of providers involved in each AI-attributed file. Ordering is by matched line count when line-level evidence exists (the dominant provider leads), and by provider-touch evidence (or the single fallback provider) when the file only has provider-touch signal. A file edited by Claude (150 lines) and Codex (2 lines) produces FileProviders[path] = ["claude_code", "codex"]; a provider-touch-only file produces a single-element slice from ProviderTouchedFiles. Empty or missing means human-only file or unknown.
type DiagnosticsInput ¶
type DiagnosticsInput struct {
EventStats EventStatsInput
MatchStats MatchStatsInput
AIPercent float64
}
DiagnosticsInput combines event stats, match stats, and the computed AI percentage for rendering the diagnostic note.
type EventStatsInput ¶
type EventStatsInput struct {
EventsConsidered int
EventsAssistant int
PayloadsLoaded int
AIToolEvents int
}
EventStatsInput carries event-processing counters into reporting.
type EvidenceClass ¶ added in v0.2.3
type EvidenceClass string
EvidenceClass describes how a file's AI attribution was determined. Internal taxonomy for the evaluation harness and detailed diagnostics. User-facing output uses factual notes rather than exposing raw classes.
const ( EvidenceExact EvidenceClass = "exact" // trimmed exact line match EvidenceNormalized EvidenceClass = "normalized" // whitespace-normalized match EvidenceModified EvidenceClass = "modified" // overlap-based modified attribution EvidenceToolDeltaTouch EvidenceClass = "tool_delta_touch" // tool delta without line evidence EvidenceProviderTouch EvidenceClass = "provider_touch" // explicit file-edit tool event from provider EvidenceProviderCoarse EvidenceClass = "provider_coarse" // session-level linkage without direct file-edit event EvidenceCarryForward EvidenceClass = "carry_forward" // attributed from previous checkpoint window EvidenceDeletion EvidenceClass = "deletion" // inferred from bash rm / provider deletion EvidenceNone EvidenceClass = "none" // no AI evidence (human file) )
func CollectFileEvidence ¶ added in v0.2.3
func CollectFileEvidence(fs FileScoreInput, touch TouchOrigin, isCarryForward bool) []EvidenceClass
CollectFileEvidence returns all evidence classes that contributed to a file's attribution. Used by the evaluation harness to track which evidence paths were active, not just which one won.
func ResolveFileEvidence ¶ added in v0.2.3
func ResolveFileEvidence(fs FileScoreInput, touch TouchOrigin, isCarryForward bool) EvidenceClass
ResolveFileEvidence determines the primary evidence class for a file based on its scored lines, touch origin, and carry-forward status. Returns the highest-quality evidence class that applies.
Line-level evidence (exact / formatted / modified) wins when present. Otherwise the function falls through to touch-based classes; ProviderOnlyLines > 0 with a TouchOriginProviderEdit resolves to EvidenceProviderTouch, which is the canonical shape for Cursor / Copilot / Gemini / Kiro that report file edits without line-level payload.
type FileAttributionOutput ¶
type FileAttributionOutput struct {
Path string
AIExactLines int
AIFormattedLines int
AIModifiedLines int
AIProviderOnlyLines int
// Tool-delta subsets of AIExactLines and AIFormattedLines.
AIDeltaExactLines int
AIDeltaFormattedLines int
HumanLines int
TotalLines int
DeletedNonBlank int
AIPercent float64 // (exact + formatted + modified) / total * 100
PrimaryEvidence EvidenceClass // highest-quality evidence for display
AllEvidence []EvidenceClass // all contributing evidence classes (for evaluation)
// Providers mirrors FileChangeOutput.Providers for the per-file detail row.
// Empty means the file is human-only or the provider is unknown.
Providers []string
}
FileAttributionOutput holds per-file attribution scores in the commit result.
AIProviderOnlyLines is rendered alongside the line-level counts but is excluded from AIPercent. PrimaryEvidence will be EvidenceProviderTouch (or EvidenceProviderCoarse) for files whose only AI evidence is provider-only.
type FileChangeOutput ¶
type FileChangeOutput struct {
Path string
AI bool
// Providers lists the providers involved in this file. Ordering is by
// matched line count when available, then provider-touch evidence or fallback.
Providers []string
}
FileChangeOutput records whether a file change was performed by AI.
type FileScoreInput ¶
type FileScoreInput struct {
Path string
TotalLines int
ExactLines int
FormattedLines int
ModifiedLines int
ProviderOnlyLines int
HumanLines int
ProviderLines map[string]int // provider -> line-level AI lines
ProviderOnlyLinesByProvider map[string]int // provider -> provider-only lines
DeletedNonBlank int // deleted non-blank lines (display only, not attributed)
// DeltaExactLines and DeltaFormattedLines are the subsets backed by tool deltas.
DeltaExactLines int
DeltaFormattedLines int
}
FileScoreInput is the narrow input shape for a single file's score data.
ProviderOnlyLines counts lines from provider-only files (the AI session touched the file but no line-level payload exists). Excluded from the headline AI% sum on purpose; surfaced separately so callers can render it as a sidecar metric.
ProviderLines and ProviderOnlyLinesByProvider are the per-provider counterparts of ExactLines+FormattedLines+ ModifiedLines and ProviderOnlyLines respectively. They split cleanly so a consumer rendering the per-provider breakdown can say "claude: N line-level, cursor: M provider-only" instead of conflating the two.
type MatchStatsInput ¶
type MatchStatsInput struct {
ExactMatches int
NormalizedMatches int
ModifiedMatches int
ProviderOnlyMatches int
}
MatchStatsInput carries match counters from scoring into reporting.
type ProviderAttribution ¶
type ProviderAttribution struct {
Provider string
Model string // empty if unknown
AILines int // line-level evidence: exact + formatted + modified
ProviderOnlyLines int // provider-touch only; excluded from headline
}
ProviderAttribution holds per-provider AI line counts.
AILines covers line-level evidence only (exact + formatted + modified) to stay consistent with the commit-level headline AILines / Percent. ProviderOnlyLines holds the provider-touch- only sidecar so consumers can render "N AI lines (M more provider-touched)" per agent without conflating the two evidence strengths.
type TouchOrigin ¶ added in v0.2.3
type TouchOrigin string
TouchOrigin describes how a file entered the AI-touched set. The orchestrator derives this from the candidates produced by the events package.
const ( TouchOriginProviderEdit TouchOrigin = "provider_edit" // explicit file-edit tool event (Cursor, Kiro, etc.) TouchOriginLineLevel TouchOrigin = "line_level" // Claude Edit/Write with payload content TouchOriginToolDelta TouchOrigin = "tool_delta" // verified tool-window capture TouchOriginDeletion TouchOrigin = "deletion" // bash rm or provider deletion event TouchOriginCoarse TouchOrigin = "coarse" // session-level linkage only )