π§ Semantic Function Clustering Analysis
Analysis of repository: github/gh-aw β non-test .go files under pkg/
Executive Summary
I built a cross-file index of every top-level function/method declaration across 1,009 non-test .go files and clustered them by name and signature to surface duplicates and misplaced functions.
Headline: the codebase is already well-organized. The large packages follow a clean one-feature-per-file convention (pkg/cli, 339 files, has zero within-package free-function name collisions; pkg/workflow, 429 files, has none either once build variants are excluded). Nearly every apparent "duplicate" is a legitimate pattern, not a defect:
_wasm.go build-tag variants β e.g. RunGH, ExecGH, findGitRoot, validateDockerImage each appear twice in pkg/workflow only because there is a real impl + a //go:build wasm stub. Correct Go idiom.
- Intentional delegation shims β
SanitizeName, FindClosestMatches, compileSchema appear in pkg/workflow/pkg/parser as thin wrappers that already delegate to a single source of truth (pkg/stringutil, parser.CompileSchema). Consolidation has already happened.
- Standard Go patterns β
run (42Γ, cobra commands), init (5Γ), New (3Γ).
Exactly one genuine, high-confidence consolidation opportunity survived verification, plus a few minor naming-collision notes.
Priority 1 β Duplicated AST helpers across linter analyzers (high confidence)
The pkg/linters/* analyzer packages copy-paste several small AST/type helpers instead of sharing them. This matters because the shared home already exists β pkg/linters/internal/astutil β and is already imported by 41 of 42 analyzer packages. These helpers are simply stragglers that were never migrated.
Verified duplicates (bodies compared, not just names):
| Helper |
Copies |
Locations |
Similarity |
enclosingFuncType(node ast.Node) *ast.FuncType |
3 |
execcommandwithoutcontext, httpnoctx, timesleepnocontext |
byte-identical |
contextContextType(pass *analysis.Pass) types.Type |
3 |
execcommandwithoutcontext, timesleepnocontext, httpnoctx |
identical logic (httpnoctx uses early-continue) |
contextParamName(pass, *ast.FuncType) (string, bool) |
3 |
execcommandwithoutcontext, timesleepnocontext, ctxbackground |
identical (ctxbackground calls a local contextType) |
calledOSFunc(pass, *ast.CallExpr) (*types.Func, bool) |
2 |
osgetenvlibrary, ossetenvlibrary |
byte-identical |
flipOp(op token.Token) token.Token |
2 |
lenstringzero, stringsindexcontains |
byte-identical |
Representative diff β enclosingFuncType is copied verbatim
// pkg/linters/execcommandwithoutcontext/execcommandwithoutcontext.go:141
// pkg/linters/httpnoctx/httpnoctx.go:164
// pkg/linters/timesleepnocontext/timesleepnocontext.go:145
func enclosingFuncType(node ast.Node) *ast.FuncType {
switch fn := node.(type) {
case *ast.FuncDecl:
return fn.Type
case *ast.FuncLit:
return fn.Type
default:
return nil
}
}
Recommendation: promote these five helpers into pkg/linters/internal/astutil (which currently exports IsLocalObject, IsFmtErrorf, Inspector, NodeText, etc.) and delete the per-package copies. contextContextType/contextParamName should be reconciled onto one spelling (ctxbackground uses contextType; the others use contextContextType).
Impact: removes ~5 copy-paste clusters (~10 redundant definitions), single source of truth for context/AST detection, and consistency with the pattern already used by 41 analyzers. Effort: ~1β2 hours; mechanical, covered by existing linter tests.
Priority 2 β Same-name / different-semantics collisions (minor, documentation)
These are not duplicates β same name, different signature and behavior across packages β but they invite confusion when reading code:
| Name |
pkg/parser |
pkg/workflow / pkg/cli |
extractToolsFromFrontmatter |
returns (string, error) |
returns map[string]any |
resolveImportInputPath |
returns (string, bool) |
returns (any, bool) |
hasCopilotRequestsWritePermission |
β |
cli takes map[string]any; workflow takes *WorkflowData (same intent, two layers) |
Recommendation: rename to disambiguate by return contract (e.g. extractToolsString vs extractToolsMap), or add doc comments cross-referencing the sibling. Low priority β no functional issue. The hasCopilotRequestsWritePermission pair is worth checking for shared permission logic that could live in one place.
What was checked and found clean
- Outlier functions in the wrong file: none material. File names in
pkg/cli/pkg/workflow map cleanly to purpose (git_helpers.go, docker_validation.go, schema_utils.go, permissions_operations.go, ...).
- Scattered utility functions: already centralized β
pkg/stringutil, pkg/fileutil, pkg/sliceutil, pkg/setutil, pkg/jsonutil, pkg/timeutil, etc. exist and are used via delegation shims.
- Cross-package free-function duplicates: all resolved to build variants or intentional shims.
Implementation checklist
Analysis metadata
- Non-test
.go files analyzed: 1,009 (pkg/, excluding *_test.go and testdata/)
- Detection method: cross-file function/method name+signature index; duplicate bodies verified by direct comparison; build-tag (
_wasm.go) and delegation-shim false positives filtered out
- Confirmed consolidation clusters: 5 (all in
pkg/linters/*)
- Naming-collision notes: 3
- Analysis date: 2026-07-06
Note: analysis focused on the tractable, high-signal axis (function-name/signature clustering across the full tree). Byte-level near-duplicate detection inside function bodies was not exhaustively run across all 1,009 files; the findings above are the clusters that survived manual verification.
Generated by π§ Semantic Function Refactoring Β· 214.5 AIC Β· β 15.1 AIC Β· β 9.2K Β· β·
π§ Semantic Function Clustering Analysis
Analysis of repository: github/gh-aw β non-test
.gofiles underpkg/Executive Summary
I built a cross-file index of every top-level function/method declaration across 1,009 non-test
.gofiles and clustered them by name and signature to surface duplicates and misplaced functions.Headline: the codebase is already well-organized. The large packages follow a clean one-feature-per-file convention (
pkg/cli, 339 files, has zero within-package free-function name collisions;pkg/workflow, 429 files, has none either once build variants are excluded). Nearly every apparent "duplicate" is a legitimate pattern, not a defect:_wasm.gobuild-tag variants β e.g.RunGH,ExecGH,findGitRoot,validateDockerImageeach appear twice inpkg/workflowonly because there is a real impl + a//go:build wasmstub. Correct Go idiom.SanitizeName,FindClosestMatches,compileSchemaappear inpkg/workflow/pkg/parseras thin wrappers that already delegate to a single source of truth (pkg/stringutil,parser.CompileSchema). Consolidation has already happened.run(42Γ, cobra commands),init(5Γ),New(3Γ).Exactly one genuine, high-confidence consolidation opportunity survived verification, plus a few minor naming-collision notes.
Priority 1 β Duplicated AST helpers across linter analyzers (high confidence)
The
pkg/linters/*analyzer packages copy-paste several small AST/type helpers instead of sharing them. This matters because the shared home already exists βpkg/linters/internal/astutilβ and is already imported by 41 of 42 analyzer packages. These helpers are simply stragglers that were never migrated.Verified duplicates (bodies compared, not just names):
enclosingFuncType(node ast.Node) *ast.FuncTypeexeccommandwithoutcontext,httpnoctx,timesleepnocontextcontextContextType(pass *analysis.Pass) types.Typeexeccommandwithoutcontext,timesleepnocontext,httpnoctxcontinue)contextParamName(pass, *ast.FuncType) (string, bool)execcommandwithoutcontext,timesleepnocontext,ctxbackgroundcontextType)calledOSFunc(pass, *ast.CallExpr) (*types.Func, bool)osgetenvlibrary,ossetenvlibraryflipOp(op token.Token) token.Tokenlenstringzero,stringsindexcontainsRepresentative diff β
enclosingFuncTypeis copied verbatimRecommendation: promote these five helpers into
pkg/linters/internal/astutil(which currently exportsIsLocalObject,IsFmtErrorf,Inspector,NodeText, etc.) and delete the per-package copies.contextContextType/contextParamNameshould be reconciled onto one spelling (ctxbackgroundusescontextType; the others usecontextContextType).Impact: removes ~5 copy-paste clusters (~10 redundant definitions), single source of truth for context/AST detection, and consistency with the pattern already used by 41 analyzers. Effort: ~1β2 hours; mechanical, covered by existing linter tests.
Priority 2 β Same-name / different-semantics collisions (minor, documentation)
These are not duplicates β same name, different signature and behavior across packages β but they invite confusion when reading code:
pkg/parserpkg/workflow/pkg/cliextractToolsFromFrontmatter(string, error)map[string]anyresolveImportInputPath(string, bool)(any, bool)hasCopilotRequestsWritePermissionclitakesmap[string]any;workflowtakes*WorkflowData(same intent, two layers)Recommendation: rename to disambiguate by return contract (e.g.
extractToolsStringvsextractToolsMap), or add doc comments cross-referencing the sibling. Low priority β no functional issue. ThehasCopilotRequestsWritePermissionpair is worth checking for shared permission logic that could live in one place.What was checked and found clean
pkg/cli/pkg/workflowmap cleanly to purpose (git_helpers.go,docker_validation.go,schema_utils.go,permissions_operations.go, ...).pkg/stringutil,pkg/fileutil,pkg/sliceutil,pkg/setutil,pkg/jsonutil,pkg/timeutil, etc. exist and are used via delegation shims.Implementation checklist
enclosingFuncType,contextContextType,contextParamName,calledOSFunc,flipOpintopkg/linters/internal/astutilcontextTypevscontextContextTypenaming inctxbackgroundAnalysis metadata
.gofiles analyzed: 1,009 (pkg/, excluding*_test.goandtestdata/)_wasm.go) and delegation-shim false positives filtered outpkg/linters/*)Note: analysis focused on the tractable, high-signal axis (function-name/signature clustering across the full tree). Byte-level near-duplicate detection inside function bodies was not exhaustively run across all 1,009 files; the findings above are the clusters that survived manual verification.