[sergo] Sergo Report: errorf-anti-pattern-revisit-and-map-set-standardization - 2026-04-03 #24376
Closed
Replies: 1 comment
-
|
This discussion has been marked as outdated by Sergo - Serena Go Expert. A newer discussion is available at Discussion #24572. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Date: 2026-04-03
Strategy: errorf-anti-pattern-revisit-and-map-set-standardization
Run ID: §23960763553
Success Score: 7/10
Executive Summary
Today's Sergo run combined a revisit of the previously-identified
fmt.Errorf("%s", str)anti-pattern (cached, 50%) with a new exploration of set-map standardization issues across the codebase (new, 50%). Thefmt.Errorfanti-pattern has grown from 6 to 10 locations since the last audit (2026-04-02), indicating new code is adopting the pattern without correction. On the new side, a pervasivemap[T]bool-as-set pattern (202 instances) versus only 7 idiomaticmap[T]struct{}instances reveals a deep inconsistency in Go idiom usage — including in exported API types. A bonus finding: thesliceutil.Containswrapper function has become redundant now that the codebase overwhelmingly usesslices.Containsdirectly.🛠️ Serena Tools Update
Tools Snapshot
Tool Capabilities Used Today
search_for_pattern— regex search across Go files (partial; connection issues)📊 Strategy Selection
Cached Reuse Component (50%)
Previous Strategy Adapted: errors-new-anti-pattern-and-interface-assertions (2026-04-02, score: 8/10)
fmt.Errorf("%s", str)anti-pattern was well-defined, actionable, and — crucially — unfixed. Revisiting it revealed the issue grew.run_workflow_validation.go(new file) andtemplate_injection_validation.goto coverage.run_workflow_validation.go:269,template_injection_validation.go:305,dangerous_permissions_validation.go:96,workflow_errors.go:261.New Exploration Component (50%)
Novel Approach: Set-map idiom audit + stdlib redundancy analysis
map[T]boolvsmap[T]struct{}— confirmed with 202:7 ratio.pkg/cli/,pkg/workflow/,pkg/parser/,pkg/agentdrain/sliceutil.Contains— 7 remaining uses vs 67 directslices.ContainscallsCombined Strategy Rationale
The two components complement each other by targeting consistency gaps: one at the error-creation level (wrong constructor), one at the data-structure level (wrong type for sets). Both are low-risk, high-readability improvements that share a common root cause: patterns established before idiomatic alternatives were clear, now propagating as copy-paste without correction.
🔍 Analysis Execution
Codebase Context
pkg/workflow/,pkg/cli/,pkg/parser/,pkg/agentdrain/Findings Summary
📋 Detailed Findings
High Priority:
fmt.Errorf("%s", str)anti-pattern — grew from 6 → 10 locationsThe
fmt.Errorf("%s", str)pattern is an anti-pattern for constructing errors from pre-built strings. It should beerrors.New(str)because:fmt.Errorfparses the format string at runtime — unnecessary work when there's no interpolationerrors.Newis semantically clear: "create a new error from this message"fmt.Errorfwith no%wand no substitutionAll 10 locations (4 new since last audit):
pkg/cli/run_workflow_execution.gopkg/workflow/tools_validation.gopkg/workflow/engine_validation.gopkg/workflow/runtime_validation.gopkg/workflow/permissions_validation.gopkg/workflow/engine_definition.gopkg/cli/run_workflow_validation.gopkg/workflow/template_injection_validation.gopkg/workflow/dangerous_permissions_validation.gopkg/workflow/workflow_errors.goMedium Priority:
map[T]boolused as sets — 202 instances vs 7 idiomaticmap[T]struct{}The codebase systematically uses
map[T]boolwhere only= trueis ever assigned — the semantic of a set, not a boolean flag map. The idiomatic Go set type ismap[T]struct{}because:struct{}is zero-size — no memory allocation per value (saves 1 byte per entry)= false(which would be meaningless in a set)Key locations by priority:
Exported API types (highest impact):
pkg/cli/engine_secrets.go:47—ExistingSecrets map[string]boolinEngineSecretConfigstructpkg/cli/tool_graph.go:32—Tools map[string]boolinToolGraphstructInternal types:
pkg/workflow/compiler_types.go:78,423—actionPinWarnings map[string]boolpkg/agentdrain/mask.go:53—excludedlocal variableLocal variables (pure sets):
pkg/cli/tokens_bootstrap.go:86,pkg/cli/trial_runner.go:146,pkg/cli/add_interactive_orchestrator.go:42pkg/parser/include_expander.go:19pkg/cli/compile_workflow_processor.go:162,pkg/cli/gateway_logs.go:921pkg/cli/compile_batch_operations.go:134,pkg/cli/generate_action_metadata_command.go:203,235,265All 202 map[T]bool locations (partial view)
There are 202
map[T]boolinstances in production Go files. The grep shows them distributed acrosspkg/cli/(majority),pkg/workflow/, andpkg/agentdrain/. Migrating all at once is impractical; the task focuses on the exported types first.Low Priority:
sliceutil.Contains— redundant wrapper overslices.ContainsUsage: 7 calls to
sliceutil.Containsvs 67 direct calls toslices.Contains. The wrapper adds zero value and creates decision overhead: "should I use sliceutil or slices?" The answer has beenslicesin 90% of new code since Go 1.21+. The wrapper predatesslicesbeing in stdlib.Locations using the wrapper:
pkg/cli/mcp_permissions.go:92pkg/cli/logs_github_api.go:286pkg/workflow/compiler_activation_job.go:111,114,438,554,557✅ Improvement Tasks Generated
Task 1: Replace
fmt.Errorf("%s", str)witherrors.New(str)across 10 locationsIssue Type: Error Construction Anti-Pattern
Problem: Ten locations in
pkg/cli/andpkg/workflow/usefmt.Errorf("%s", str)to wrap a pre-built string into an error. This is semantically equivalent toerrors.New(str)but adds unnecessary format-string parsing overhead and is flagged by Go linters. The issue grew from 6 → 10 locations between 2026-04-02 and today, suggesting new code is copying the pattern without correction.Location(s):
pkg/cli/run_workflow_execution.go:210pkg/cli/run_workflow_validation.go:269(new)pkg/workflow/tools_validation.go:358pkg/workflow/template_injection_validation.go:305(new)pkg/workflow/engine_validation.go:79pkg/workflow/runtime_validation.go:91pkg/workflow/dangerous_permissions_validation.go:96(new)pkg/workflow/permissions_validation.go:346pkg/workflow/workflow_errors.go:261(new)pkg/workflow/engine_definition.go:280Impact:
pkg/cli/andpkg/workflow/Before:
After:
Validation:
import "errors"is present in each file (add if missing; remove"fmt"if it becomes unused)go vet ./...to confirm no linter regressionsEstimated Effort: Small (10 one-line changes, possibly 1-2 import updates per file)
Task 2: Migrate exported
map[T]boolsets tomap[T]struct{}Issue Type: Type Idiom Inconsistency
Problem: Two exported struct fields use
map[string]boolas sets (keys only ever set totrue, value never used as a real boolean). Usingmap[T]struct{}is the Go idiom for sets: the zero-size value makes intent explicit and prevents the= falsefootgun. With 202map[T]boolvs 7map[T]struct{}in the codebase, the exported types are the highest-priority fix because they form the public API and influence how consumers write code.Location(s):
pkg/cli/engine_secrets.go:47—ExistingSecrets map[string]boolinEngineSecretConfigpkg/cli/tool_graph.go:32—Tools map[string]boolinToolGraphpkg/workflow/compiler_types.go:78—actionPinWarnings map[string]boolpkg/workflow/compiler_types.go:423—ActionPinWarnings map[string]boolImpact:
map[k] = struct{}{}instead ofmap[k] = true, and presence checks_, ok := map[k]instead ofif map[k]Before:
After:
Validation:
ExistingSecrets[...] = true→ExistingSecrets[...] = struct{}{}if ExistingSecrets[k]→if _, ok := ExistingSecrets[k]; oktype StringSet = map[string]struct{}if the pattern repeats enoughEstimated Effort: Medium (4 type changes + 10-20 call-site updates)
Task 3: Deprecate and inline
sliceutil.ContainswrapperIssue Type: Redundant Abstraction
Problem:
sliceutil.Contains(slice, item)is a one-line wrapper overslices.Contains(slice, item)from the Go standard library. It predates Go 1.21'sslicespackage. Today, 90% ofContainscalls (67/74) useslices.Containsdirectly; only 7 use the wrapper. The wrapper creates unnecessary API surface and forces callers to decide which to import. Removing it standardizes the codebase on the stdlib function.Location(s):
pkg/sliceutil/sliceutil.go— Remove theContainsfunctionpkg/cli/mcp_permissions.go:92— Update importpkg/cli/logs_github_api.go:286— Update importpkg/workflow/compiler_activation_job.go:111,114,438,554,557— Update import (5 call sites in one file)Impact:
Before:
After:
Validation:
slices.ContainsContainsfunction frompkg/sliceutil/sliceutil.go"slices"import fromsliceutil.goif no other functions use itgo build ./...and existing testsEstimated Effort: Small (7 one-line replacements + 1 function deletion)
📈 Success Metrics
This Run
Reasoning for Score
📊 Historical Context
Strategy Performance
Cumulative Statistics
🎯 Recommendations
Immediate Actions
fmt.Errorf("%s", str)→errors.New(str)— 10 locations, pure find-replace, zero risk. The fact this grew from 6→10 suggests a comment in a validation file might be triggering the copy.map[T]struct{}— Start withEngineSecretConfig.ExistingSecretsandToolGraph.Toolsas they affect the public API.sliceutil.Containswrapper — 7 easy replacements to eliminate an unnecessary wrapper.Long-term Improvements
fmt.Errorfanti-patterns — Three of seven Sergo runs have surfaced error-construction issues. Consider adding a custom linter rule (e.g.,golangci-lintwithperfsprintor a customgo/analysispass) to blockfmt.Errorf("%s", ...)at PR time.map[T]boolprevalence — With 202 instances, a codebase-wide migration would be substantial. Consider ago vetcustom check orstaticcheckrule to flag newmap[T]booldeclarations in PR reviews.🔄 Next Run Preview
Suggested Focus Areas
var _ Interface = (*Struct)(nil)) were identified in the 2026-03-31 and 2026-04-02 runs but not yet implemented. Revisiting this could verify whether they were added.http.Clientinstances without explicitTimeoutfields,Transportsettings, or context propagation in thepkg/parser/remote_fetch.go(898 LOC, largest parser file).Strategy Evolution
Today's run confirmed that revisiting unfixed cached findings has value (finding grew from 6→10). Future runs should include a "regression check" component: verify whether previously-reported high-priority findings were addressed between runs, and re-report with updated scope if not.
References:
Beta Was this translation helpful? Give feedback.
All reactions