[typist] Typist: Go Type Consistency Analysis - Duplicate Types & Untyped Usages #32349
Closed
Replies: 1 comment
-
|
This discussion was automatically closed because it expired on 2026-05-16T12:06:08.861Z.
|
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.
-
Typist - Go Type Consistency Analysis
Analysis of repository: github/gh-aw
Executive Summary
A semantic analysis of all non-test Go files under
pkg/(792 source files across 24 sub-packages) identified 3 duplicate type clusters and ~15 high-impact untyped-usage opportunities. The codebase already practices strong typing well for domain constants (e.g.,EngineName,JobName,StepID), so the main consolidation wins are: (a) one true duplicate type (RepositoryFeatures) split across WASM/non-WASM build tags, and (b) a recurring pattern of returning rawmap[string]anyfrom YAML/JSON schema navigation code, which forces 50+ downstream type assertions inpkg/parser/schema_suggestions.goalone.Quick stats
anyusages: ~3,000 across 478 files (most justified by YAML/JSON unmarshaling)map[string]anypatterns: ~1,766Full Analysis Report
Duplicated Type Definitions
Summary Statistics
All three clusters arise from
_wasm.gobuild-tagged variants, which is an idiomatic Go pattern. Only one is a clean consolidation candidate.Cluster 1:
RepositoryFeatures(exact duplicate)Classification: Exact duplicate — identical fields
Occurrences: 2
Impact: Medium — trivial to consolidate; no platform-specific reason for duplication.
Locations:
pkg/workflow/repository_features_validation.go:57pkg/workflow/repository_features_validation_wasm.go:5Recommendation: Move the type to a build-tag-free file (e.g.,
repository_features_types.go) and keep only the platform-specific functions in the_wasm.go/ non-_wasm.gofiles.Cluster 2:
ProgressBar(near-duplicate; platform variant)Classification: Near-duplicate — WASM stub omits one runtime-only field
Occurrences: 2
Impact: Low — intentional platform divergence; consolidation risks coupling WASM to a non-WASM dependency.
Locations:
pkg/console/progress.go:31pkg/console/progress_wasm.go:7Recommendation: Keep as-is, or extract a
ProgressBarinterface withUpdate,Increment, etc. and let each build tag implement it. Only worth doing if the API surface grows.Cluster 3:
SpinnerWrapper(near-duplicate; platform variant)Classification: Near-duplicate — WASM stub is intentionally minimal
Occurrences: 2
Impact: Low — same rationale as
ProgressBar.Locations:
pkg/console/spinner.go:96pkg/console/spinner_wasm.go:10Recommendation: Same as
ProgressBar— introduce an interface only if the consumer surface grows.Untyped Usages
Summary Statistics
anyusages: ~3,000 across 478 files (most are YAML/JSON unmarshaling targets and are appropriate)interface{}usages: 0 in production code (codebase uses the modernanyalias)map[string]anypatterns: ~1,766EngineName,JobName,StepID, etc.)Category 1:
anyin function parameters that always destructure to a known shapeThese functions accept
anypurely so they can be called from a YAML walker, but each one branches over a small, bounded set of input types. Replacing with a typed shim at the call site would eliminate per-call type assertions and document the contract.Example 1
pkg/parser/schema_triggers.go:73func IsLabelOnlyEvent(eventValue any) boolmap[string]anywith atypes []stringfield.Example 2
pkg/parser/schema_triggers.go:117func IsNonConflictingCommandEvent(eventValue any) boolExample 3
pkg/workflow/reactions.go:42func parseReactionValue(value any) (string, error)string | int | int64 | uint64 | float64, all of which yield a string enum.stringor normalize numerics at the YAML boundary before calling.Example 4
pkg/workflow/service_ports.go:153func parsePortSpec(spec any) ([]int, []string)int | uint64 | int64 | float64 | string.intat the parser boundary, then acceptint | stringvia a smallPortSpecinterface or two-overload helper.Example 5
pkg/workflow/safe_outputs_messages_config.go:53func parseMentionsConfig(mentions any) *MentionsConfigbool | map[string]anywith a known field set.MentionsInput(struct withIsBool bool; Object *MentionsObject).Example 6
pkg/parser/import_field_extractor.go:919func validateObjectInput(name string, value any, paramDef map[string]any, importPath string) errorvalue map[string]anydirectly — callers can validate before calling.Category 2:
map[string]anyschema navigation (high-impact)This is the single biggest opportunity in the codebase.
pkg/parser/schema_suggestions.gorepeatedly drills into nestedmap[string]anyvalues, asserting types at each level. There are 15+ assertions in this one file (lines 162, 175, 190, 191, 201, 213, 218, 228, 391, 451, 477, ...).Suggested refactor
Impact sites:
pkg/parser/schema_suggestions.go:175—navigateToSchemaPathpkg/parser/schema_suggestions.go:213—resolveSchemaWithOneOfpkg/parser/schema_suggestions.go:391-651— deep navigation blockBenefit: Eliminates ~50 type assertions; turns runtime errors into compile-time guarantees; clarifies intent.
Category 3: MCP/parser entry points with
anydiscriminatorsExample 1
pkg/parser/mcp.go:255func processBuiltinMCPTool(toolName string, toolValue any, serverFilter string) (*RegistryMCPServerConfig, error)map[string]anywithmodeandgithub-tokenkeys.Example 2
pkg/workflow/compiler_jobs.go:112func (c *Compiler) getCustomJobsDependencies(customJobs map[string]any) []stringCustomJobstruct and usemap[string]CustomJob(ormap[JobName]CustomJob).Example 3
pkg/workflow/permissions_parser.go:244func NewPermissionsParserFromValue(permissionsValue any) *PermissionsParserstring | map[string]any.NewPermissionsParserFromString(s string)andNewPermissionsParserFromMap(m map[string]any).Category 4: Untyped constants
No material findings. The codebase already follows the strong-typing idiom for domain enums. Spot-checked exemplars worth preserving:
pkg/constants/engine_constants.go:11—type EngineName stringwith typed constants ✅pkg/constants/job_constants.go:3—type JobName stringwith typed constants ✅pkg/constants/job_constants.go:31—type StepID stringwith typed constants ✅No
const Timeout = 30-style untyped numerics with semantic meaning were found in core code paths.Refactoring Recommendations (prioritized)
Priority 1 — Consolidate
RepositoryFeaturesWhy: Only true exact duplicate in the codebase; no platform-specific reason to keep two copies.
pkg/workflow/repository_features_types.go(no build tag) with the struct.repository_features_validation_wasm.go.Priority 2 — Introduce a
JSONSchemahelper for schema navigationWhy: Single change that eliminates ~50 type assertions and most of the readability friction in
pkg/parser/schema_suggestions.go.pkg/parser/jsonschema.gowith the wrapper type and accessor methods.navigateToSchemaPath,resolveSchemaWithOneOf, and the deep navigation block to use it.Priority 3 — Type the small parser/workflow entry points
Why: Each call site listed in Category 1 and Category 3 is independently small but together they form a consistent pattern of "accept
any, immediately assert".Apply one at a time; each is a self-contained PR.
Implementation Checklist
RepositoryFeatures(P1)JSONSchemawrapper + migrateschema_suggestions.go(P2)IsLabelOnlyEvent/IsNonConflictingCommandEventparametersparseReactionValue/parseReactionConfigparametersparsePortSpecparameter (normalize numerics at boundary)parseMentionsConfigparameter (discriminated union)validateObjectInputparameterprocessBuiltinMCPToolconfig parametergetCustomJobsDependenciesinput map valuesNewPermissionsParserFromValueinto two typed constructorsProgressBar/SpinnerWrapperinterfaces (skip unless API grows)Caveats
anyusage in this codebase is justified by YAML/JSON unmarshaling boundaries. The recommendations above target only sites where the input shape is bounded and predictable.ProgressBar,SpinnerWrapper) are idiomatic Go build-tag patterns and should not be consolidated without a clear API need.JSONSchemawrapper recommendation does not need to land all at once — it can be introduced and migrated incrementally.Analysis Metadata
pkg/)References:
Beta Was this translation helpful? Give feedback.
All reactions