Documentation
¶
Overview ¶
Package compare provides structural and semantic code comparison between repositories.
Comparison works at multiple levels:
- Symbols: matched by name, signature, and semantic similarity
- Metrics: quantitative measures of code quality and complexity
- Architecture: LLM-powered insights into design patterns and gaps
Index ¶
- Constants
- func BuildCompareContext(matches []SymbolMatch, metricsA, metricsB RepoMetrics, query string) string
- func BuildCompareContextV2(matches []SymbolMatch, metricsA, metricsB RepoMetrics, query string, ...) string
- func CollectChurn(ctx context.Context, root string, since time.Duration) (map[string]ChurnStats, error)
- func ComputeGrade(m RepoMetrics) string
- func DetectFrameworks(imports []string, language string) []string
- func ExtractRoutes(ctx context.Context, root string, snap *RepoSnapshot) []routes.Route
- func FileComplexityFromSnapshot(snap *RepoSnapshot) map[string]float64
- func GradeScore(m RepoMetrics) float64
- func IsCompiledArtifact(filePath string) bool
- func SubScoreSum(m RepoMetrics) float64
- func ToGumTree(node *sitter.Node, source []byte) *gum.Tree
- type APIDelta
- type APIDiff
- type APISymbol
- type ArchMetrics
- type ArchitectureInsight
- type ChurnStats
- type CircularDep
- type CompareInput
- type CompareResult
- type CoupledPair
- type CoverageGap
- type CrossLangMatch
- type CrossLangReport
- type DataflowStats
- type DiffStats
- type DiffSummary
- type EmbeddingClassifier
- type FreshnessStats
- type GodPackage
- type HotspotFile
- type ImportCategory
- type ImportDiff
- type LLMAnalysis
- type LLMClassifier
- type MagicNumberEntry
- type MatchBreakdown
- type MatchType
- type OutlierFunc
- type Outliers
- type QualityAspect
- type QualityIndicators
- type Recommendation
- type RelStats
- type RepoMetrics
- type RepoSnapshot
- type RouteDiff
- type SARIFArtifact
- type SARIFDriver
- type SARIFLocation
- type SARIFMessage
- type SARIFPhysical
- type SARIFRegion
- type SARIFReport
- type SARIFResult
- type SARIFRule
- type SARIFRuleConfig
- type SARIFRun
- type SARIFTool
- type SnapshotFile
- type SnapshotOpts
- type SymbolMatch
- type VerdictResult
Constants ¶
const HintApproxArchMetrics = "Architecture metrics are approximate (derived from in-memory call graph). " +
"Run the `code_graph` tool with the same repo path for full analysis including call depth."
HintApproxArchMetrics is the caveat attached to ArchMetrics results derived from an in-memory call graph rather than the full Apache AGE graph. MaxCallDepth, InterfaceRatio, and CommunityCount are not computed by the fallback.
Variables ¶
This section is empty.
Functions ¶
func BuildCompareContext ¶
func BuildCompareContext(matches []SymbolMatch, metricsA, metricsB RepoMetrics, query string) string
BuildCompareContext assembles structured text context for the LLM (no hotspots).
func BuildCompareContextV2 ¶
func BuildCompareContextV2(matches []SymbolMatch, metricsA, metricsB RepoMetrics, query string, hotspotsA, hotspotsB []HotspotFile, relStatsA, relStatsB *RelStats, freshnessA, freshnessB *FreshnessStats, dataflowA, dataflowB *DataflowStats, apiDiff *APIDiff, routeDiff *RouteDiff, archA, archB *ArchMetrics) string
BuildCompareContextV2 assembles structured text context for the LLM, including hotspot and type hierarchy data.
Sections:
- ## Query — the user's question
- ## Metrics — JSON comparison of aggregate quality metrics
- ## Maintenance Hotspots — high-churn x high-complexity files (if any)
- ## Type Hierarchy — relationship stats (extends/implements/embeds) per repo
- ## Matched Symbols (side-by-side) — non-gap pairs up to maxMatchedPairs
- ## Coverage Gaps — symbols absent from one side, up to maxGapSymbols
Content is truncated once the cumulative output exceeds maxContextChars.
func CollectChurn ¶
func CollectChurn(ctx context.Context, root string, since time.Duration) (map[string]ChurnStats, error)
CollectChurn runs git log --numstat on the given repo root and returns churn statistics per file (relative paths).
`since` bounds the history window (e.g. 90*24*time.Hour); pass 0 for all history. Returns nil map and nil error for non-git directories.
func ComputeGrade ¶
func ComputeGrade(m RepoMetrics) string
ComputeGrade returns a letter grade (A+ through F) for the given metrics.
func DetectFrameworks ¶
DetectFrameworks returns a sorted list of framework names detected from the given import paths for the specified language.
func ExtractRoutes ¶
ExtractRoutes walks the snapshot files, reads each source file, and extracts HTTP routes using the registered route matchers. Only files whose language matches snap.Language are processed. The root parameter is the absolute path to the repository root used to build absolute file paths from RelPath. Context cancellation is respected between files.
func FileComplexityFromSnapshot ¶
func FileComplexityFromSnapshot(snap *RepoSnapshot) map[string]float64
FileComplexityFromSnapshot computes average cyclomatic complexity per file from the snapshot's symbols. Keys are relative paths (root prefix stripped) to match git churn output from CollectChurn.
func GradeScore ¶
func GradeScore(m RepoMetrics) float64
GradeScore computes a quality score in [0, 100] from RepoMetrics. Higher is better. Uses 14 sub-scores with weights summing to 1.0.
func IsCompiledArtifact ¶
IsCompiledArtifact returns true when filePath looks like a build output that should be excluded from coupling and other source-level analyses.
The implementation lives in internal/artifactfilter (stdlib-only leaf) so that packages like internal/federate can import just that leaf without pulling in compare's heavy transitive closure.
func SubScoreSum ¶
func SubScoreSum(m RepoMetrics) float64
SubScoreSum returns the total score from sub-scores (should equal GradeScore). Exported for drift-guard tests.
Types ¶
type APIDiff ¶
type APIDiff struct {
Common int
OnlyACount int
OnlyBCount int
ChangedSig int
OnlyA []APISymbol
OnlyB []APISymbol
Changed []APIDelta
}
APIDiff is the result of comparing two API surfaces.
func ComputeAPIDiff ¶
ComputeAPIDiff compares two API surfaces and returns a structured diff. Symbols are matched by (name, kind) key. Matched symbols with different signatures are counted as changed. Lists are truncated to maxAPIDiffItems.
type APISymbol ¶
APISymbol represents a single exported symbol in a repository's public API surface.
type ArchMetrics ¶
type ArchMetrics struct {
PackageCount int `json:"packageCount"`
CommunityCount int `json:"communityCount"`
CrossPkgCallRatio float64 `json:"crossPkgCallRatio"`
MaxCallDepth int `json:"maxCallDepth"`
InterfaceRatio float64 `json:"interfaceRatio"`
GodPackages []GodPackage `json:"godPackages,omitempty"`
CircularDeps []CircularDep `json:"circularDeps,omitempty"`
// NotIndexed is set when the code graph has no packages for this repo,
// meaning code_graph tool was never called with this repo path. Call
// code_graph with the same repo first to populate the graph.
NotIndexed bool `json:"notIndexed,omitempty"`
// Approximate is set when metrics were derived from an in-memory call graph
// rather than the full Apache AGE graph. MaxCallDepth, InterfaceRatio, and
// CommunityCount are not computed in the approximate path and must not be
// presented as real measurements.
Approximate bool `json:"approximate,omitempty"`
Hint string `json:"hint,omitempty"`
}
ArchMetrics holds architectural metrics derived from the code graph.
func CollectArchMetrics ¶
CollectArchMetrics queries the Apache AGE code graph for architectural metrics. Each sub-query is non-fatal: failures are logged and skipped. When the graph is absent (NotIndexed), it falls back to FallbackArchMetrics to derive PackageCount and CrossPkgCallRatio from an in-memory call graph.
func FallbackArchMetrics ¶ added in v1.22.0
func FallbackArchMetrics(ctx context.Context, root string) *ArchMetrics
FallbackArchMetrics builds an in-memory call graph with a 10-second timeout and derives PackageCount and CrossPkgCallRatio from it. It is called when CollectArchMetrics returns NotIndexed (AGE graph absent or repo not yet indexed).
MaxCallDepth, InterfaceRatio, and CommunityCount are not computed here — they are too expensive without the persistent graph store. Callers must set HintApproxArchMetrics on the returned struct to indicate the metrics are approximate.
Returns nil when root is empty or when BuildFromRepo fails (caller should fall back to NotIndexed=true in that case).
type ArchitectureInsight ¶
type ArchitectureInsight struct {
Insight string `json:"insight"`
Source string `json:"source"`
Example string `json:"example,omitempty"`
Benefit string `json:"benefit"`
}
ArchitectureInsight captures a design pattern or architectural observation.
type ChurnStats ¶
type ChurnStats struct {
// Commits is the number of commits that touched this file.
Commits int `json:"commits"`
// Additions is the total lines added across all commits.
Additions int `json:"additions"`
// Deletions is the total lines deleted across all commits.
Deletions int `json:"deletions"`
}
ChurnStats holds change frequency data for a single file.
func (ChurnStats) ChurnScore ¶
func (c ChurnStats) ChurnScore() float64
ChurnScore returns a weighted churn score as defined by Omen: sum(1.0 + (additions + deletions) / 100.0) per commit.
type CircularDep ¶
CircularDep represents a circular dependency between two packages.
type CompareInput ¶
type CompareInput struct {
RootA string
RootB string
Query string
Opts SnapshotOpts
OxCodes *oxcodes.Client
EmbedClient *embed.Client // nil = skip semantic matching
GraphStore *codegraph.Store // nil = skip architecture graph analysis
}
CompareInput is the input for CompareRepos.
type CompareResult ¶
type CompareResult struct {
RepoA string `json:"repo_a"`
RepoB string `json:"repo_b"`
Query string `json:"query"`
MetricsA RepoMetrics `json:"metrics_a"`
MetricsB RepoMetrics `json:"metrics_b"`
Analysis LLMAnalysis `json:"analysis"`
MatchedSymbols int `json:"matched_symbols"`
UnmatchedA int `json:"unmatched_a"`
UnmatchedB int `json:"unmatched_b"`
MatchBreakdown MatchBreakdown `json:"match_breakdown"`
ImportDiff ImportDiff `json:"import_diff"`
DiffStats *DiffStats `json:"diff_stats,omitempty"`
HotspotsA []HotspotFile `json:"hotspots_a,omitempty"`
HotspotsB []HotspotFile `json:"hotspots_b,omitempty"`
RelStatsA *RelStats `json:"rel_stats_a,omitempty"`
RelStatsB *RelStats `json:"rel_stats_b,omitempty"`
QualityA *QualityIndicators `json:"quality_a,omitempty"`
QualityB *QualityIndicators `json:"quality_b,omitempty"`
FreshnessA *FreshnessStats `json:"freshness_a,omitempty"`
FreshnessB *FreshnessStats `json:"freshness_b,omitempty"`
DataflowA *DataflowStats `json:"dataflow_a,omitempty"`
DataflowB *DataflowStats `json:"dataflow_b,omitempty"`
APIDiffResult *APIDiff `json:"api_diff,omitempty"`
RouteDiffResult *RouteDiff `json:"route_diff,omitempty"`
CouplingA []CoupledPair `json:"coupling_a,omitempty"`
CouplingB []CoupledPair `json:"coupling_b,omitempty"`
ArchMetricsA *ArchMetrics `json:"arch_metrics_a,omitempty"`
ArchMetricsB *ArchMetrics `json:"arch_metrics_b,omitempty"`
CrossLangReport *CrossLangReport `json:"cross_lang_report,omitempty"`
}
CompareResult contains the full structured output of a code comparison.
func CompareRepos ¶
func CompareRepos(ctx context.Context, input CompareInput, llmClient llm.Completer) (*CompareResult, error)
CompareRepos orchestrates a full comparison between two repositories. llmClient must be non-nil; pass llm.NoOp{} when LLM is not configured. NoOp.Complete returns ErrLLMUnavailable which runLLMAnalysis treats as a fallback (deterministic comparison still runs in full).
type CoupledPair ¶
type CoupledPair struct {
FileA string `json:"fileA"`
FileB string `json:"fileB"`
CoChanges int `json:"coChanges"`
Ratio float64 `json:"ratio"` // coChanges / max(changesA, changesB)
}
CoupledPair represents two files that frequently change together in git history.
func CollectCoupling ¶
func CollectCoupling(ctx context.Context, root string, minCoChanges int) []CoupledPair
CollectCoupling analyzes git log to find files that frequently change together. Returns pairs with at least minCoChanges co-occurrences, sorted by frequency desc. Looks at the last year of history. Returns nil if git is unavailable.
type CoverageGap ¶
type CoverageGap struct {
MissingIn string `json:"missingIn"`
Feature string `json:"feature"`
LocationB string `json:"locationB,omitempty"`
Importance string `json:"importance"`
}
CoverageGap identifies a feature present in one repo but absent in the other.
type CrossLangMatch ¶
type CrossLangMatch struct {
NameA string `json:"nameA"`
NameB string `json:"nameB"`
FileA string `json:"fileA"`
FileB string `json:"fileB"`
Similarity float64 `json:"similarity"`
}
CrossLangMatch describes a semantic match between symbols in different languages.
type CrossLangReport ¶
type CrossLangReport struct {
LanguageA string `json:"languageA"`
LanguageB string `json:"languageB"`
SemanticMatches int `json:"semanticMatches"`
TopMatches []CrossLangMatch `json:"topMatches,omitempty"`
}
CrossLangReport summarizes cross-language comparison findings.
func BuildCrossLangReport ¶
func BuildCrossLangReport(matches []SymbolMatch, langA, langB string) *CrossLangReport
BuildCrossLangReport creates a cross-language report from symbol matches. Returns nil if both repos use the same language.
type DataflowStats ¶
type DataflowStats struct {
DeadStores int `json:"deadStores"`
UnusedVars int `json:"unusedVars"`
TotalFindings int `json:"totalFindings"`
FilesAnalyzed int `json:"filesAnalyzed"`
}
DataflowStats holds dead code and data flow findings from ox-codes.
func GatherDataflow ¶
func GatherDataflow(ctx context.Context, client *oxcodes.Client, root, language string) *DataflowStats
GatherDataflow runs ox-codes dataflow analysis on a repo.
type DiffStats ¶
type DiffStats struct {
ModifiedWithDiff int `json:"modifiedWithDiff"`
TotalInserts int `json:"totalInserts"`
TotalDeletes int `json:"totalDeletes"`
TotalUpdates int `json:"totalUpdates"`
TotalMoves int `json:"totalMoves"`
}
DiffStats aggregates AST diff statistics across all modified matches.
type DiffSummary ¶
type DiffSummary struct {
// TotalChanges is the total number of edit actions in the diff script.
TotalChanges int `json:"totalChanges"`
// Inserts is the count of insert (single node) and insert-tree actions.
Inserts int `json:"inserts"`
// Deletes is the count of delete (single node) and delete-tree actions.
Deletes int `json:"deletes"`
// Updates is the count of update (value change) actions.
Updates int `json:"updates"`
// Moves is the count of move (reorder) actions.
Moves int `json:"moves"`
// Changes is a list of human-readable change descriptions (max maxDiffChanges).
Changes []string `json:"changes,omitempty"`
}
DiffSummary holds the result of a structural AST diff between two symbol bodies.
func ComputeASTDiff ¶
func ComputeASTDiff(bodyA, bodyB, language string) *DiffSummary
ComputeASTDiff parses two symbol bodies using tree-sitter for the given language, computes a GumTree edit script, and returns a DiffSummary. Returns nil if either body is empty, the language is unsupported, or bodies are too large.
type EmbeddingClassifier ¶
type EmbeddingClassifier struct {
// contains filtered or unexported fields
}
EmbeddingClassifier implements LLMClassifier using vector similarity.
func NewEmbeddingClassifier ¶
func NewEmbeddingClassifier(ctx context.Context, client *embed.Client) *EmbeddingClassifier
NewEmbeddingClassifier creates a classifier using the given embedding client.
func (*EmbeddingClassifier) ClassifySymbols ¶
func (c *EmbeddingClassifier) ClassifySymbols(a, b []*parser.Symbol) ([]SymbolMatch, error)
ClassifySymbols finds semantic matches between unmatched symbols using embeddings.
type FreshnessStats ¶
type FreshnessStats struct {
DepFreshnessRatio float64 `json:"depFreshnessRatio"`
VulnSecurityRatio float64 `json:"vulnSecurityRatio"`
TotalDeps int `json:"totalDeps"`
OutdatedDeps int `json:"outdatedDeps"`
VulnDeps int `json:"vulnDeps"`
}
FreshnessStats holds dependency freshness and vulnerability data.
func CollectFreshness ¶
CollectFreshness checks dependency freshness and vulnerabilities for a repo. Returns nil if no manifests found. depRatio and vulnRatio contain the ratios.
type GodPackage ¶
GodPackage represents a package with many importers (high coupling).
type HotspotFile ¶
type HotspotFile struct {
File string `json:"file"`
Score float64 `json:"score"`
Churn int `json:"churn"`
Complexity float64 `json:"complexity"`
Risk string `json:"risk"` // "critical", "high", "moderate"
}
HotspotFile is a file identified as a maintenance risk (high churn x high complexity).
func ComputeHotspots ¶
func ComputeHotspots(churn map[string]ChurnStats, fileComplexity map[string]float64) []HotspotFile
ComputeHotspots combines churn data and per-file complexity to find maintenance hotspots. Uses the Omen formula: score = percentile(churn) x percentile(complexity).
type ImportCategory ¶
type ImportCategory string
ImportCategory classifies an import path.
const ( // ImportStdlib marks standard library imports. ImportStdlib ImportCategory = "stdlib" // ImportInternal marks project-relative (internal) imports. ImportInternal ImportCategory = "internal" // ImportExternal marks third-party/external imports. ImportExternal ImportCategory = "external" )
func CategorizeImport ¶
func CategorizeImport(imp, language string) ImportCategory
CategorizeImport classifies an import path as stdlib, internal, or external for the given language.
type ImportDiff ¶
type ImportDiff struct {
CommonCount int `json:"commonCount"`
OnlyACount int `json:"onlyACount"`
OnlyBCount int `json:"onlyBCount"`
OnlyA []string `json:"onlyA,omitempty"`
OnlyB []string `json:"onlyB,omitempty"`
FrameworksA []string `json:"frameworksA,omitempty"`
FrameworksB []string `json:"frameworksB,omitempty"`
StdlibA int `json:"stdlibA"`
StdlibB int `json:"stdlibB"`
ExternalA int `json:"externalA"`
ExternalB int `json:"externalB"`
}
ImportDiff captures the difference between two import sets.
func ComputeImportDiff ¶
func ComputeImportDiff(importsA, importsB []string, language string) ImportDiff
ComputeImportDiff computes the set difference between two import lists. The language parameter is used for categorization and framework detection.
type LLMAnalysis ¶
type LLMAnalysis struct {
Quality []QualityAspect `json:"quality"`
Gaps []CoverageGap `json:"gaps"`
Architecture []ArchitectureInsight `json:"architecture"`
Recommendations []string `json:"recommendations"`
Verdict VerdictResult `json:"verdict"`
}
LLMAnalysis holds the structured output from LLM-powered comparison.
type LLMClassifier ¶
type LLMClassifier interface {
ClassifySymbols(a, b []*parser.Symbol) ([]SymbolMatch, error)
}
LLMClassifier is a consumer-defined interface for semantic symbol pairing. It is called as a last resort after exact and fuzzy matching are exhausted.
type MagicNumberEntry ¶
MagicNumberEntry describes a single function containing magic numbers.
func CollectMagicNumbers ¶
func CollectMagicNumbers(snap *RepoSnapshot) []MagicNumberEntry
CollectMagicNumbers returns all functions/methods that contain magic numbers. Test files are excluded. Results are sorted by count descending.
type MatchBreakdown ¶
type MatchBreakdown struct {
Exact int `json:"exact"`
Modified int `json:"modified"`
Fuzzy int `json:"fuzzy"`
Renamed int `json:"renamed"`
Semantic int `json:"semantic"`
Moved int `json:"moved"`
}
MatchBreakdown counts matches by type for structured reporting.
type MatchType ¶
type MatchType string
MatchType describes how two symbols were matched.
const ( // MatchExact means the symbols have the same name and kind and identical body. MatchExact MatchType = "exact" // MatchModified means the symbols have the same name and kind but different body. MatchModified MatchType = "modified" // MatchRenamed means the symbols have different names but same signature and/or body hash. MatchRenamed MatchType = "renamed" // MatchFuzzy means the symbols have similar names or signatures. MatchFuzzy MatchType = "fuzzy" // MatchSemantic means the symbols serve the same purpose (LLM-determined). MatchSemantic MatchType = "semantic" // MatchMoved means the symbol has the same name, kind, and body but resides // in a different file or package. Indicates code reorganization without logic change. MatchMoved MatchType = "moved" // MatchGap means the symbol has no counterpart in the other repository. MatchGap MatchType = "gap" )
type OutlierFunc ¶
OutlierFunc identifies a single function that holds a maximum metric value.
type Outliers ¶
type Outliers struct {
MaxCyclomatic OutlierFunc
MaxCognitive OutlierFunc
MaxFuncLines OutlierFunc
MaxNesting OutlierFunc
MaxMagicNumbers OutlierFunc
}
Outliers holds the worst-offending function for each key metric.
func CollectOutliers ¶
func CollectOutliers(snap *RepoSnapshot) Outliers
CollectOutliers iterates snapshot symbols and records which function holds each maximum metric value. File paths are stripped of the root prefix to produce relative paths (same pattern as FileComplexityFromSnapshot).
type QualityAspect ¶
type QualityAspect struct {
Aspect string `json:"aspect"`
Winner string `json:"winner"`
Reason string `json:"reason"`
SnippetA string `json:"snippetA,omitempty"`
SnippetB string `json:"snippetB,omitempty"`
}
QualityAspect describes a qualitative comparison point between two repos.
type QualityIndicators ¶
type QualityIndicators struct {
TodoCount int `json:"todo_count"`
ErrorPatterns int `json:"error_patterns"` // unhandled errors
PanicCount int `json:"panic_count"` // panic() calls
MagicNumbers int `json:"magic_numbers"`
}
QualityIndicators summarizes code quality signals from ox-codes.
func GatherQualityIndicators ¶
func GatherQualityIndicators(ctx context.Context, client *oxcodes.Client, root, language string) *QualityIndicators
GatherQualityIndicators runs ox-codes scoped searches to assess code quality. All searches run in parallel for speed.
type Recommendation ¶
type Recommendation struct {
Priority int
Potential int // estimated score points recoverable
Area string
Message string
}
Recommendation is a single actionable improvement suggestion.
func ComputeRecommendations ¶
func ComputeRecommendations(m RepoMetrics, out Outliers, maxItems int) []Recommendation
ComputeRecommendations identifies the weakest scoring areas and returns actionable recommendations sorted by potential score impact (descending). maxItems limits the number of returned recommendations (0 = unlimited).
type RelStats ¶
type RelStats struct {
Total int `json:"total"`
Extends int `json:"extends"`
Implements int `json:"implements"`
Embeds int `json:"embeds"`
UniqueSubjects int `json:"uniqueSubjects"`
}
RelStats summarizes type relationship counts for a repository.
func ComputeRelStats ¶
func ComputeRelStats(rels []parser.TypeRelationship) *RelStats
ComputeRelStats computes relationship statistics from extracted relationships. Returns nil if no relationships exist.
type RepoMetrics ¶
type RepoMetrics struct {
Files int `json:"files"`
TotalLines int `json:"totalLines"`
AvgFuncLines float64 `json:"avgFuncLines"`
MaxFuncLines int `json:"maxFuncLines"`
AvgComplexity float64 `json:"avgComplexity"`
MaxComplexity int `json:"maxComplexity"`
TestRatio float64 `json:"testRatio"`
DocRatio float64 `json:"docRatio"`
ErrorHandlingRatio float64 `json:"errorHandlingRatio"`
Interfaces int `json:"interfaces"`
ExternalDeps int `json:"externalDeps"`
Grade string `json:"grade"`
// New metrics for smarter scoring.
AvgCognitiveComplexity float64 `json:"avgCognitiveComplexity"`
MaxCognitiveComplexity int `json:"maxCognitiveComplexity"`
AvgNestingDepth float64 `json:"avgNestingDepth"`
MaxNestingDepth int `json:"maxNestingDepth"`
LargeFileRatio float64 `json:"largeFileRatio"`
DuplicationRatio float64 `json:"duplicationRatio"`
MagicNumberRatio float64 `json:"magicNumberRatio"`
AvgParamCount float64 `json:"avgParamCount"`
MaxParamCount int `json:"maxParamCount"`
Score float64 `json:"score"`
SemanticDupRatio float64 `json:"semanticDupRatio,omitempty"` // fraction of functions in semantic dup groups
DepFreshnessRatio float64 `json:"depFreshnessRatio,omitempty"` // fraction of deps that are up-to-date
VulnSecurityRatio float64 `json:"vulnSecurityRatio,omitempty"` // fraction of deps with no known vulns
TotalDeps int `json:"totalDeps,omitempty"` // number of external dependencies scanned; 0 means no manifests found (N/A)
// DepsScanned is true when a dependency freshness scan was attempted (regardless of
// whether it found any deps). When false, the dep-freshness and vulnerability
// sub-scores fall back to the legacy penalty path (same behaviour as before PR #250),
// so lightweight paths like explore that skip the freshness scan are not affected.
DepsScanned bool `json:"depsScanned,omitempty"`
// DeadCodeCandidates is the count of functions with CE dead-code probability >= 0.25.
// Populated from code_dead_code_scores when code_graph snapshot is available.
DeadCodeCandidates int `json:"deadCodeCandidates,omitempty"`
DeadCodeTopNames []string `json:"deadCodeTopNames,omitempty"` // up to 3 top candidates
}
RepoMetrics holds aggregate quality and complexity metrics for a repo.
func ComputeMetrics ¶
func ComputeMetrics(snap *RepoSnapshot) RepoMetrics
ComputeMetrics derives aggregate quality metrics from a RepoSnapshot.
The snapshot must already have Symbols and Imports populated; FileCount and TotalLines are copied verbatim. Test-file detection is based on Symbol.File paths (unique files seen across all symbols).
type RepoSnapshot ¶
type RepoSnapshot struct {
// Name is the repository name or slug.
Name string `json:"name"`
// Root is the absolute local path to the repository.
Root string `json:"root"`
// FocusMode is "content" when the fallback content filter was used
// instead of path-based focus. Empty means path-based or no focus.
FocusMode string `json:"focusMode,omitempty"`
// Language is the dominant programming language.
Language string `json:"language"`
// Symbols is all symbols extracted from the repository.
Symbols []*parser.Symbol `json:"symbols,omitempty"`
// Imports is the flat list of all unique import paths used.
Imports []string `json:"imports,omitempty"`
// Files holds per-file metadata.
Files []SnapshotFile `json:"files,omitempty"`
// FileCount is the total number of source files.
FileCount int `json:"fileCount"`
// TotalLines is the approximate total lines of code.
TotalLines int `json:"totalLines"`
// Rels holds type relationships extracted from the repository.
Rels []parser.TypeRelationship `json:"rels,omitempty"`
// Partial is true when one or more ingested files could not be read during
// snapshotting (e.g. the source tree was deleted out from under the walk, or
// a per-file context cancellation cut the parse short). When set, the derived
// metrics (Files, TotalLines, TestRatio, Symbols) under-count the real repo
// and MUST NOT be presented as a complete result. See DroppedReadError /
// DroppedCtxCancel for the per-reason breakdown.
Partial bool `json:"partial,omitempty"`
// DroppedReadError counts files that were enumerated by ingest but failed
// os.ReadFile at parse time (vanished file / permission flip / truncated
// tree). This is the dominant signal of a use-after-delete race on a shared
// clone dir.
DroppedReadError int `json:"droppedReadError,omitempty"`
// DroppedCtxCancel counts files skipped because the snapshot context was
// cancelled before the parse worker reached them (timeout / caller abort).
DroppedCtxCancel int `json:"droppedCtxCancel,omitempty"`
}
RepoSnapshot is a parsed, summarized view of a repository ready for comparison.
func BuildSnapshot ¶
func BuildSnapshot(ctx context.Context, root string, opts SnapshotOpts) (*RepoSnapshot, error)
BuildSnapshot ingests and parses a repository, returning a RepoSnapshot suitable for structural comparison.
Steps:
- Ingest the repository tree filtered by opts.Focus / opts.Language.
- Parse all files in parallel (worker pool of runtime.NumCPU goroutines).
- Aggregate symbols, unique imports, per-file entries, and line counts.
type RouteDiff ¶
type RouteDiff struct {
Common int `json:"common"`
OnlyACount int `json:"onlyACount"`
OnlyBCount int `json:"onlyBCount"`
OnlyA []routes.Route `json:"onlyA,omitempty"`
OnlyB []routes.Route `json:"onlyB,omitempty"`
}
RouteDiff summarises the difference between two sets of HTTP routes.
func ComputeRouteDiff ¶
ComputeRouteDiff compares two route slices and returns a RouteDiff. Routes are matched by method + normalised path; handler names are ignored.
type SARIFArtifact ¶
type SARIFArtifact struct {
URI string `json:"uri"`
}
SARIFArtifact holds the URI of the artifact.
type SARIFDriver ¶
type SARIFDriver struct {
Name string `json:"name"`
Version string `json:"version"`
Rules []SARIFRule `json:"rules,omitempty"`
}
SARIFDriver is the tool driver metadata.
type SARIFLocation ¶
type SARIFLocation struct {
PhysicalLocation SARIFPhysical `json:"physicalLocation"`
}
SARIFLocation identifies where a result was found.
type SARIFMessage ¶
type SARIFMessage struct {
Text string `json:"text"`
}
SARIFMessage holds a plain-text message.
type SARIFPhysical ¶
type SARIFPhysical struct {
ArtifactLocation SARIFArtifact `json:"artifactLocation"`
Region *SARIFRegion `json:"region,omitempty"`
}
SARIFPhysical identifies a file and optional region.
type SARIFRegion ¶
type SARIFRegion struct {
StartLine int `json:"startLine"`
}
SARIFRegion specifies a location within an artifact.
type SARIFReport ¶
type SARIFReport struct {
Schema string `json:"$schema"`
Version string `json:"version"`
Runs []SARIFRun `json:"runs"`
}
SARIFReport is a minimal SARIF v2.1.0 report.
func BuildSARIF ¶
func BuildSARIF( repoName string, metrics RepoMetrics, quality *QualityIndicators, dataflow *DataflowStats, hotspots []HotspotFile, outliers Outliers, ) *SARIFReport
BuildSARIF converts code health findings into a SARIF v2.1.0 report.
type SARIFResult ¶
type SARIFResult struct {
RuleID string `json:"ruleId"`
Level string `json:"level"` // "error", "warning", "note"
Message SARIFMessage `json:"message"`
Locations []SARIFLocation `json:"locations,omitempty"`
}
SARIFResult is a single finding produced by the tool.
type SARIFRule ¶
type SARIFRule struct {
ID string `json:"id"`
ShortDescription SARIFMessage `json:"shortDescription"`
DefaultConfig *SARIFRuleConfig `json:"defaultConfiguration,omitempty"`
}
SARIFRule describes a rule that can produce results.
type SARIFRuleConfig ¶
type SARIFRuleConfig struct {
Level string `json:"level"` // "error", "warning", "note"
}
SARIFRuleConfig holds the default severity for a rule.
type SARIFRun ¶
type SARIFRun struct {
Tool SARIFTool `json:"tool"`
Results []SARIFResult `json:"results"`
}
SARIFRun is a single analysis run.
type SARIFTool ¶
type SARIFTool struct {
Driver SARIFDriver `json:"driver"`
}
SARIFTool describes the analysis tool.
type SnapshotFile ¶
type SnapshotFile struct {
RelPath string `json:"relPath"`
Language string `json:"language"`
Lines int `json:"lines"`
Symbols []*parser.Symbol `json:"symbols,omitempty"`
Imports []string `json:"imports,omitempty"`
}
SnapshotFile holds parsed metadata for a single source file within a repo snapshot.
type SnapshotOpts ¶
type SnapshotOpts struct {
// Focus limits ingestion to files under this subdirectory or matching this
// glob pattern. Empty means process the entire repository.
Focus string
// Language limits ingestion to files of this programming language.
// Empty means accept all supported languages.
Language string
}
SnapshotOpts controls what gets ingested and parsed when building a snapshot.
type SymbolMatch ¶
type SymbolMatch struct {
SymbolA *parser.Symbol `json:"symbolA,omitempty"`
SymbolB *parser.Symbol `json:"symbolB,omitempty"`
MatchType MatchType `json:"matchType"`
Category string `json:"category"`
Score float64 `json:"score"`
Diff *DiffSummary `json:"diff,omitempty"`
}
SymbolMatch pairs a symbol from repo A with its counterpart in repo B. If one side is nil, the symbol exists only in the other repository.
func MatchSymbols ¶
func MatchSymbols(symbolsA, symbolsB []*parser.Symbol, classifier LLMClassifier) []SymbolMatch
MatchSymbols aligns symbols from two repositories using four passes:
- Exact: match by identical name and kind (score 1.0).
- Fuzzy: match by name similarity >= fuzzyThreshold, same kind (score = similarity).
- Signature: match by identical/similar signature + body hash (catches renames).
- Semantic: delegate remaining unmatched pairs to classifier (if non-nil).
Symbols with no counterpart become gap entries (SymbolA or SymbolB is nil).
func (SymbolMatch) IsGap ¶
func (m SymbolMatch) IsGap() bool
IsGap returns true if the symbol is present in only one repository (or neither).
func (SymbolMatch) MissingIn ¶
func (m SymbolMatch) MissingIn() string
MissingIn returns "repo_a" if the symbol is missing from repo A, "repo_b" if missing from repo B, or "" if the symbol exists in both (or neither).
type VerdictResult ¶
type VerdictResult struct {
CanReplace string `json:"canReplace"` // "yes", "partial", "no"
Reason string `json:"reason"`
Blockers []string `json:"blockers,omitempty"`
}
VerdictResult is the structured "can replace?" assessment.
Source Files
¶
- apisurf.go
- archgraph.go
- archgraph_calldepth.go
- archgraph_fallback.go
- archgraph_queries.go
- artifact_filter.go
- astconv.go
- astdiff.go
- churn.go
- churn_cache.go
- compare.go
- complexity.go
- context.go
- context_sections.go
- context_writers.go
- coupling.go
- coupling_cache.go
- crosslang.go
- enrich.go
- freshness.go
- grade.go
- hotspot.go
- importcat.go
- importcat_cpp.go
- importcat_data.go
- importdiff.go
- llm.go
- magic_parse.go
- match.go
- metrics.go
- metrics_file.go
- metrics_func.go
- metrics_func_helpers.go
- metrics_magic.go
- outliers.go
- prefilter.go
- quality.go
- recommend.go
- relstats.go
- routediff.go
- sarif.go
- semantic.go
- snapshot.go
- strutil.go
- types.go