Skip to content

[refactor] Semantic function clustering analysis: duplicate helpers and mixed concerns #20092

@github-actions

Description

@github-actions

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 (only package 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 functions
  • agent_download.go ← agent file download functions
  • Move resolveWorkflowFile* to workflows.go (which already contains getMarkdownWorkflowFiles())

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, validator
  • runtime_*.go (6 files): Separated by definitions, detection, validation, overrides, step generation, deduplication
  • mcp_config_*.go (7 files): Types, utils, rendering by engine, and validation all separated
  • audit_report_*.go (3 files): Clean collect → analyze → render layering
  • compile_*.go (9 files in pkg/cli): Properly separated by config types, helpers, validation, stats, and batch operations
  • update_entity_helpers.go + close_entity_helpers.go: Excellent use of generics to unify similar entity parsers
  • codemod_yaml_utils.go: Legitimate shared utility serving all 53 codemod transformation files
  • validation_helpers.go, map_helpers.go, git_helpers.go: All appropriately scoped domain helpers

Implementation Checklist

  • Remove truncateSnippet() from pkg/workflow/markdown_security_scanner.go, replace usages with strings.TrimSpace + stringutil.Truncate()
  • Resolve overlap between normalizeWorkflowID() and stringutil.NormalizeWorkflowName() — either consolidate or document the distinction
  • Delete pkg/workflow/compiler_safe_outputs_shared.go and pkg/workflow/compiler_safe_outputs_discussions.go
  • Split pkg/cli/commands.go into 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions