-
Notifications
You must be signed in to change notification settings - Fork 333
[refactor] Semantic function clustering analysis: duplicate helpers and mixed concerns #20092
Description
Automated semantic analysis of 545 non-test Go files across 18 packages in pkg/. The overall codebase is well-structured, but a few concrete refactoring opportunities were identified.
Summary
- Total Go files analyzed: 545 (across
pkg/cli,pkg/workflow, and 16 utility packages) - Function clusters identified: 12 major clusters (permissions, runtime, mcp_config, safe_outputs, compile, audit, codemods, etc.)
- Outliers found: 2 confirmed (stub files)
- Duplicates detected: 2 confirmed
- Mixed concerns: 1 confirmed
Identified Issues
1. Duplicate truncateSnippet() vs stringutil.Truncate()
Issue: A private truncateSnippet() function in pkg/workflow/markdown_security_scanner.go reimplements the same truncation logic already available in pkg/stringutil.
truncateSnippet |
stringutil.Truncate |
|
|---|---|---|
| File | pkg/workflow/markdown_security_scanner.go:798 |
pkg/stringutil/stringutil.go:17 |
| Behavior | strings.TrimSpace(s) then truncate with "..." |
Truncate with "...", respects maxLen ≤ 3 edge case |
| Used | 10+ call sites within the same file | Throughout the codebase |
// markdown_security_scanner.go:798 — private duplicate
func truncateSnippet(s string, maxLen int) string {
s = strings.TrimSpace(s)
if len(s) <= maxLen { return s }
return s[:maxLen] + "..."
}
// stringutil/stringutil.go:17 — canonical implementation
func Truncate(s string, maxLen int) string {
if len(s) <= maxLen { return s }
if maxLen <= 3 { return s[:maxLen] }
return s[:maxLen-3] + "..."
}Recommendation: Remove truncateSnippet and replace call sites with strings.TrimSpace inline + stringutil.Truncate(), or add a TrimAndTruncate variant to stringutil.
2. Overlapping normalizeWorkflowID() vs stringutil.NormalizeWorkflowName()
Issue: pkg/cli/commands.go defines a private normalizeWorkflowID() that largely overlaps with the already-public stringutil.NormalizeWorkflowName().
normalizeWorkflowID |
stringutil.NormalizeWorkflowName |
|
|---|---|---|
| File | pkg/cli/commands.go:153 |
pkg/stringutil/identifiers.go:30 |
| Handles paths | Yes (filepath.Base first) |
No (name only) |
Strips .lock.yml |
No | Yes |
| Used at | 8 call sites across pkg/cli |
Throughout pkg/workflow |
// commands.go:153 — handles full paths but not .lock.yml
func normalizeWorkflowID(workflowIDOrPath string) string {
basename := filepath.Base(workflowIDOrPath)
return strings.TrimSuffix(basename, ".md")
}
// stringutil/identifiers.go:30 — handles .lock.yml but expects name only
func NormalizeWorkflowName(name string) string { ... }Recommendation: Extend stringutil.NormalizeWorkflowName to optionally accept paths (calling filepath.Base internally), then replace normalizeWorkflowID across pkg/cli. Or document the distinction explicitly to avoid future confusion.
3. Empty stub files in pkg/workflow
Issue: Two files exist that contain only package declarations and legacy comments, indicating leftover scaffolding after migration.
pkg/workflow/compiler_safe_outputs_shared.go— 1 line (onlypackage workflow)pkg/workflow/compiler_safe_outputs_discussions.go— 6 lines (package declaration + comment explaining the file previously had content but it was removed)
// compiler_safe_outputs_discussions.go
package workflow
// This file previously contained discussion-related step config builders.
// Those functions have been removed as discussions are now handled by the
// safe output handler manager (safe_output_handler_manager.cjs).
// See pkg/workflow/compiler_safe_outputs_core.go for the new implementation.Recommendation: Delete both empty files. The explanatory comment in compiler_safe_outputs_discussions.go can be moved to compiler_safe_outputs_core.go if the context is useful.
4. Mixed concerns in pkg/cli/commands.go
Issue: commands.go acts as a catch-all file containing three unrelated concerns:
| Concern | Functions |
|---|---|
| Version management | SetVersionInfo(), GetVersion() (lines 36–44) |
| Agent file download | downloadAgentFileFromGitHub(), downloadAgentFileViaGHCLI(), patchAgentFileURLs(), isGHCLIAvailable() (lines 47–151) |
| Workflow file resolution | normalizeWorkflowID(), resolveWorkflowFile(), resolveWorkflowFileInDir() (lines 153–228) |
| Workflow creation | NewWorkflow(), createWorkflowTemplate() (lines 229–end) |
Recommendation: Split into purpose-focused files:
version.go← version management functionsagent_download.go← agent file download functions- Move
resolveWorkflowFile*toworkflows.go(which already containsgetMarkdownWorkflowFiles())
Well-Organized Patterns (for reference)
The following areas were analyzed and found to be exemplary — no changes needed:
View well-organized patterns
permissions_*.go(5 files): Clean separation by types, factory, operations, parser, validatorruntime_*.go(6 files): Separated by definitions, detection, validation, overrides, step generation, deduplicationmcp_config_*.go(7 files): Types, utils, rendering by engine, and validation all separatedaudit_report_*.go(3 files): Clean collect → analyze → render layeringcompile_*.go(9 files inpkg/cli): Properly separated by config types, helpers, validation, stats, and batch operationsupdate_entity_helpers.go+close_entity_helpers.go: Excellent use of generics to unify similar entity parserscodemod_yaml_utils.go: Legitimate shared utility serving all 53 codemod transformation filesvalidation_helpers.go,map_helpers.go,git_helpers.go: All appropriately scoped domain helpers
Implementation Checklist
- Remove
truncateSnippet()frompkg/workflow/markdown_security_scanner.go, replace usages withstrings.TrimSpace+stringutil.Truncate() - Resolve overlap between
normalizeWorkflowID()andstringutil.NormalizeWorkflowName()— either consolidate or document the distinction - Delete
pkg/workflow/compiler_safe_outputs_shared.goandpkg/workflow/compiler_safe_outputs_discussions.go - Split
pkg/cli/commands.gointo purpose-focused files (version.go,agent_download.go)
Analysis Metadata
- Total Go files analyzed: 545
- Packages covered:
pkg/cli,pkg/workflow,pkg/stringutil,pkg/sliceutil,pkg/mathutil,pkg/fileutil,pkg/gitutil,pkg/timeutil,pkg/envutil,pkg/repoutil,pkg/types,pkg/constants - Detection method: Serena LSP semantic analysis + naming pattern clustering + cross-package comparison
- Workflow run: §22825681455
References:
Generated by Semantic Function Refactoring · ◷
- expires on Mar 10, 2026, 5:10 PM UTC