Skip to content

[refactor] Semantic Function Clustering Analysis: Code Organization Opportunities #8742

Description

@github-actions

🔧 Semantic Function Clustering Analysis

Analysis of repository: github/gh-aw-mcpg
Workflow run: §28755174481

Overview

This report analyzes all 149 non-test Go source files across 24 packages in internal/, cataloging 929 functions/methods. The analysis identifies semantic clusters, outliers, and near-duplicate patterns. The codebase is generally well-organized; findings below are refactoring opportunities rather than critical defects.

Analysis Metadata

  • Total Go Files Analyzed: 149 (non-test, in internal/)
  • Total Functions/Methods Cataloged: 929
  • Packages Analyzed: 24
  • Top packages by function count: server (130), config (128), difc (115), logger (107), guard (75)

Identified Issues

1. Parallel sessionSuffix / truncateSessionID Functions

Issue: Two packages independently implement a function to format a session ID for logging.

File Function Behavior
internal/launcher/log_helpers.go sessionSuffix(sessionID string) string Returns " for session '<id>'" or ""
internal/server/log_helpers.go truncateSessionID(sessionID string) string Returns first 8 chars or "(none)"

While the exact output differs, both serve the same purpose: producing a log-safe representation of a session ID. The launcher variant doesn't truncate at all, which may leak full session IDs into logs.

Recommendation: Consolidate into internal/util with a shared FormatSessionIDForLog(sessionID string) string function. This also fixes the missing truncation in the launcher path.

Estimated Impact: Consistent session ID logging across all packages, reduced duplication.


2. Parallel Rate-Limit Reset Parsers

Issue: Two different implementations parse GitHub rate-limit reset times with different input formats.

File Function Input
internal/githubhttp/client.go ParseRateLimitResetHeader(value string) time.Time Unix timestamp header value
internal/server/rate_limit.go parseRateLimitResetFromText(text string) time.Time Free-text body string

The files even have cross-references in comments acknowledging each other's existence — a code smell indicating they should share a home. Both handle the same concern (deriving a time.Time from GitHub rate-limit data).

Recommendation: Consolidate both into internal/githubhttp/ (e.g., a new internal/githubhttp/ratelimit.go), since rate-limit handling is GitHub-specific. The server package can import it.

Estimated Impact: Centralized rate-limit parsing, easier to update when the GitHub API changes.


3. truncateSanitized is a Trivial Alias in logger/rpc_format.go

Issue: internal/logger/rpc_format.go defines:

func truncateSanitized(sanitized string, maxLength int) string {
    return util.Truncate(sanitized, maxLength)
}

This is a one-liner alias for util.Truncate with no added behavior. The sibling truncateAndSanitize is meaningful (chains sanitization + truncation). This alias adds indirection without value.

Recommendation: Remove truncateSanitized and call util.Truncate(sanitized, maxLength) directly at the two call sites.

Estimated Impact: Minor — reduces unnecessary indirection.


4. IsSingularReadTool in difc/evaluator.go — Potential Misplacement

Issue: internal/difc/evaluator.go contains:

func IsSingularReadTool(toolName string) bool {
    return !strings.HasPrefix(toolName, "list_") && !strings.HasPrefix(toolName, "search_")
}

This is a tool-naming convention helper that classifies MCP tool names by name prefix. It doesn't use any DIFC types or labels — it's a pure string classification utility in a file with 18 complex DIFC evaluation functions.

Recommendation: Move to internal/mcp/helpers.go or a new internal/difc/tool_helpers.go to separate it from the core DIFC evaluation logic.

Estimated Impact: Better discoverability — developers looking for tool-naming utilities will find them in the MCP package.


5. CreateHTTPServerForRoutedMode Co-location

Issue: internal/server/routed.go contains CreateHTTPServerForRoutedMode, while internal/server/http_server.go contains CreateHTTPServerForMCP. Both are public HTTP server factory functions that call the same buildMCPHTTPServer helper (defined in http_server.go).

routed.go currently holds only 3 functions, with the server-creation concern mixed with routing logic.

Recommendation: Move CreateHTTPServerForRoutedMode to http_server.go to co-locate all HTTP server factory functions. Leave pure routing logic (route registration, filtered server cache setup) in routed.go.

Estimated Impact: Clearer file responsibility — http_server.go owns all HTTP server creation.


Function Cluster Summary

Well-Organized Clusters ✓

Cluster Files Assessment
Configuration Validation internal/config/validation*.go (8 files) Excellent — single-purpose files, clear naming
DIFC Labels & Evaluation internal/difc/ (8 files) Good separation; minor outlier in Issue #4
Guard System internal/guard/ (9 files) Well-organized by concern (wasm_lifecycle, wasm_parse, wasm_payload, write_sink, noop, registry)
Logger Infrastructure internal/logger/ (13 files) Intentionally verbose; one file per logger type with shared infrastructure
HTTP Utilities internal/httputil/ + server/response_writer.go Good composition — server.responseWriter correctly embeds httputil.BaseResponseWriter

Intentional Patterns (No Action Needed)

  • rejectAuthRequest / rejectHMACRequest: Thin wrappers around rejectRequest — correctly documented as the intended pattern in http_helpers.go.
  • InitFileLogger, InitMarkdownLogger, etc.: 7 separate logger init functions — intentional design for independent loggers dispatched via initLoggerSet.
  • envutil/expand_env_args.go vs config/expand.go: Different expansion concerns (Docker -e flags vs ${VAR} syntax in config JSON) — correct separation.

Refactoring Recommendations by Priority

Priority 1: High Impact

  1. Consolidate session ID formatting (Issue Configure as a Go CLI tool #1)

    • Merge sessionSuffix/truncateSessionID into shared internal/util utility
    • Add truncation to launcher path for security
    • Estimated effort: 1-2 hours
  2. Centralize rate-limit reset parsing (Issue Lpcox/initial implementation #2)

    • Move parseRateLimitResetFromText to internal/githubhttp/
    • Remove cross-package comment references
    • Estimated effort: 1-2 hours

Priority 2: Medium Impact

  1. Remove truncateSanitized alias (Issue Lpcox/initial implementation #3)

    • Replace 2 call sites with util.Truncate directly
    • Estimated effort: 30 minutes
  2. Move IsSingularReadTool to MCP package (Issue Lpcox/add difc #4)

    • Move to internal/mcp/helpers.go
    • Update callers in difc/ and server/
    • Estimated effort: 1 hour
  3. Move CreateHTTPServerForRoutedMode to http_server.go (Issue Updated Dockerfile #5)

    • Co-locate all HTTP server factory functions
    • Estimated effort: 30 minutes

Implementation Checklist

  • Consolidate sessionSuffix/truncateSessionID into shared utility with proper truncation
  • Move rate-limit reset parsing to internal/githubhttp/
  • Remove truncateSanitized alias; call util.Truncate directly
  • Move IsSingularReadTool to internal/mcp/helpers.go
  • Move CreateHTTPServerForRoutedMode to http_server.go
  • Run make agent-finished after each refactor to verify no regressions

References:

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

Generated by Semantic Function Refactoring · 94.9 AIC · ⊞ 8.4K ·

Metadata

Metadata

Assignees

Type

No type

Fields

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