Semantic Function Clustering Analysis
Analysis of repository: github/gh-aw — scoped to pkg/stats and pkg/stringutil (non-test Go files).
Executive Summary
The analyzed slice is small and, on the whole, well organized. Files in pkg/stringutil are already partitioned by feature (ansi.go, fuzzy_match.go, identifiers.go, pat_validation.go, sanitize.go, urls.go) and pkg/stats/statvar.go is a single cohesive type. One genuine low-risk duplicate was found, plus two minor organizational observations. No large-scale refactor is warranted.
- Files analyzed: 8 (7 in
stringutil, 1 in stats)
- Functions/methods cataloged: ~35
- Verified duplicates: 1 (inline ASCII-alphanumeric rune check)
- Outliers (wrong file): 0 clear cases; 2 mild grouping suggestions
- Detection method: symbol inventory + naming-cluster analysis + pattern grep
1. Duplicate: inline ASCII-alphanumeric rune check (Priority 1 — low effort)
Two functions in sanitize.go open-code the identical ASCII alphanumeric test:
pkg/stringutil/sanitize.go:220 — inside SanitizeIdentifierName
pkg/stringutil/sanitize.go:326 — inside SanitizeForFilename
// line 220 (SanitizeIdentifierName)
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_' {
// line 326 (SanitizeForFilename)
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '-' || r == '_' || r == '.' {
Recommendation: extract a small unexported helper in sanitize.go and reuse it in both call sites:
func isASCIIAlphanumeric(r rune) bool {
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9')
}
Then the checks become isASCIIAlphanumeric(r) || r == '_' and isASCIIAlphanumeric(r) || r == '-' || r == '_' || r == '.'. Purely mechanical, behavior-preserving; existing tests cover both functions.
Impact: single source of truth for the character-class definition; easier to keep the two sanitizers consistent.
2. Minor: whitespace helpers could cluster (Priority 3 — optional)
stringutil.go is the catch-all file and currently mixes several unrelated concerns:
NormalizeWhitespace (stringutil.go:34) and NormalizeLeadingWhitespace (stringutil.go:97) — whitespace normalization
Truncate (stringutil.go:20), FormatList (stringutil.go:77) — formatting
ParseVersionValue (stringutil.go:54) — type-to-string conversion
IsPositiveInteger (stringutil.go:150) — validation
The two Normalize*Whitespace functions form a natural pair and could move to a whitespace.go file if this catch-all grows. Not urgent — at the current size a single utility file is idiomatic. Flagging only so it is on the radar as the file expands.
3. Confirmed good organization (no action)
- PAT cluster (
pat_validation.go): ClassifyPAT, ValidateCopilotPAT, GetPATTypeDescription + PATType methods — cohesive, correctly isolated.
- ANSI cluster (
ansi.go): StripANSI + skip*/is*CSIChar helpers — cohesive.
- Identifier/path cluster (
identifiers.go): NormalizeWorkflowName, MarkdownToLockFile, LockFileToMarkdown, NormalizeSafeOutputIdentifier — cohesive.
- Sanitize cluster (
sanitize.go): SanitizeParameterName/SanitizePythonVariableName already delegate to a shared SanitizeIdentifierName — good existing reuse.
- stats (
statvar.go): single StatVar type with focused methods — no issues.
Implementation Checklist
Analysis Metadata
- Scope:
pkg/stats, pkg/stringutil (precomputed slice)
- Duplicates detected: 1
- Outliers: 0 clear
- Analysis date: 2026-07-23
Generated by 🔧 Semantic Function Refactoring · sonnet46 113.5 AIC · ⌖ 10 AIC · ⊞ 9.5K · ◷
Semantic Function Clustering Analysis
Analysis of repository: github/gh-aw — scoped to
pkg/statsandpkg/stringutil(non-test Go files).Executive Summary
The analyzed slice is small and, on the whole, well organized. Files in
pkg/stringutilare already partitioned by feature (ansi.go,fuzzy_match.go,identifiers.go,pat_validation.go,sanitize.go,urls.go) andpkg/stats/statvar.gois a single cohesive type. One genuine low-risk duplicate was found, plus two minor organizational observations. No large-scale refactor is warranted.stringutil, 1 instats)1. Duplicate: inline ASCII-alphanumeric rune check (Priority 1 — low effort)
Two functions in
sanitize.goopen-code the identical ASCII alphanumeric test:pkg/stringutil/sanitize.go:220— insideSanitizeIdentifierNamepkg/stringutil/sanitize.go:326— insideSanitizeForFilenameRecommendation: extract a small unexported helper in
sanitize.goand reuse it in both call sites:Then the checks become
isASCIIAlphanumeric(r) || r == '_'andisASCIIAlphanumeric(r) || r == '-' || r == '_' || r == '.'. Purely mechanical, behavior-preserving; existing tests cover both functions.Impact: single source of truth for the character-class definition; easier to keep the two sanitizers consistent.
2. Minor: whitespace helpers could cluster (Priority 3 — optional)
stringutil.gois the catch-all file and currently mixes several unrelated concerns:NormalizeWhitespace(stringutil.go:34) andNormalizeLeadingWhitespace(stringutil.go:97) — whitespace normalizationTruncate(stringutil.go:20),FormatList(stringutil.go:77) — formattingParseVersionValue(stringutil.go:54) — type-to-string conversionIsPositiveInteger(stringutil.go:150) — validationThe two
Normalize*Whitespacefunctions form a natural pair and could move to awhitespace.gofile if this catch-all grows. Not urgent — at the current size a single utility file is idiomatic. Flagging only so it is on the radar as the file expands.3. Confirmed good organization (no action)
pat_validation.go):ClassifyPAT,ValidateCopilotPAT,GetPATTypeDescription+PATTypemethods — cohesive, correctly isolated.ansi.go):StripANSI+skip*/is*CSICharhelpers — cohesive.identifiers.go):NormalizeWorkflowName,MarkdownToLockFile,LockFileToMarkdown,NormalizeSafeOutputIdentifier— cohesive.sanitize.go):SanitizeParameterName/SanitizePythonVariableNamealready delegate to a sharedSanitizeIdentifierName— good existing reuse.statvar.go): singleStatVartype with focused methods — no issues.Implementation Checklist
isASCIIAlphanumerichelper insanitize.goand update lines 220 and 326pkg/stringutiltests to confirm no behavior changestringutil.gogrowsAnalysis Metadata
pkg/stats,pkg/stringutil(precomputed slice)