reporting

package
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package reporting assembles per-file scores into aggregate attribution results. It is a pure domain package with no infrastructure dependencies.

Index

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

func AssembleCheckpointNotes(pipelineNote string) []string

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

func EvidenceExplanation(level string, fallbackCount int) string

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
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL