Repository navigation
[typist] Typist: Go type consistency findings in pkg/ (duplicate types & untyped constants) #73177
Closed
Replies: 1 comment
|
This discussion was automatically closed because it expired on 2026-10-31T11:34:24.984Z.
|
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
Scanned 1,798 non-test
.gofiles underpkg/(1,848 type definitions collected via Serena semantic analysis). The codebase has already fully migrated off bareinterface{}in production code — only 2 occurrences remain, both inside comments — so the untyped-usage opportunity is narrower than usual: it's a handful of string-constant clusters that behave like unenforced enums, not rawinterface{}/anymisuse (the ~22,700anyusages found are overwhelmingly legitimate, mirroring genuinely polymorphic GitHub Actions/YAML schema fields such ason:,needs:,permissions:).On the duplication side, an initial automated clustering pass over 1,848 types surfaced several same-named types; after manual verification, 3 are genuine structural duplicates/near-duplicates worth consolidating, and 5 independently-reinvented "Finding/Diagnostic" shapes across different static-analysis subsystems stand out as the highest-value consolidation target. Several other same-name matches (e.g.
ValidationError,LogParser,SourceLocation) turned out on inspection to be unrelated types that merely share a name, and are called out below as false positives rather than real duplication.Full Analysis Report
Duplicated Type Definitions
Summary Statistics
StepID)runtimeImportReference,graderManifestEntry)ValidationError(interface vs. struct),LogParser(generic func type vs. interface),SourceLocation(completely unrelated field sets — name-only collision)Cluster 1:
StepID— Exact DuplicateImpact: Low-Medium — two unrelated
stringtypes share a name and shape; nothing stops a value typed for one package being silently reused where the other is expected.Locations:
pkg/constants/job_constants.go:31—type StepID string(plus aString()method)pkg/workflow/actions/ids.go:9—type StepID string(declared alongside siblingJobID/OutputName)Recommendation: Pick one canonical
StepID(likelypkg/workflow/actions, since it already groupsJobID/StepID/OutputNameas a family) and have the other package import/alias it instead of redeclaring.Estimated effort: ~1 hour. Benefit: removes a confusing same-name/same-shape type that could mask an accidental cross-package mix-up.
Cluster 2:
runtimeImportReference— Near DuplicateImpact: Low (both unexported, package-local) but a clear case of copy-paste drift.
Locations:
pkg/parser/frontmatter_hash.go:569—struct { path string; startLine int; endLine int }pkg/workflow/runtime_import_validation.go:38—struct { importPath string; startLine int; endLine int }Identical shape (one string + two ints describing a source-line span for an import reference); only the first field's name differs (
pathvsimportPath).Recommendation: Factor into one small shared type (e.g. in
pkg/parseror a tiny shared helper package both already depend on) and havepkg/workflowconsume it.Estimated effort: ~1 hour.
Cluster 3:
graderManifestEntry— Near DuplicateImpact: Medium — this is a schema used both at compile time and at audit/report time; if one copy gains a field the other doesn't, the manifest format can silently diverge between the two.
Locations:
pkg/cli/audit_report_graders.go:67—ID, Name, Unit, Direction, Thresholdpkg/workflow/compiler_yaml_graders.go:13—ID, Name, Description, Source, Enabled, Unit, Direction, ThresholdThe
cliversion is a strict subset of theworkflowversion's fields.Recommendation: Define the richer
workflowshape once in a shared location and havepkg/cli/audit_report_graders.goembed it (or import it directly) rather than redeclaring a trimmed-down copy.Estimated effort: 2-3 hours (touches both packages' JSON (de)serialization call sites). Benefit: single source of truth for the grader manifest schema.
Cluster 4: The "Finding/Diagnostic" shape, reinvented 5 times (Semantic Duplicates)
Impact: Medium-High — this is the biggest real opportunity found. Five different packages each independently define a "located static-analysis result" type, with no shared base:
pkg/scanfindings/scanfindings.go:107Finding—RuleID, Severity, Message, File, Line, Column(+Context)pkg/workflow/taint/taint.go:43Finding—RuleID, Site, Sourcespkg/workflow/gradershell/check.go:14Finding—Line, Messagepkg/workflow/actionslanguageservice/workflow.go:49Diagnostic—File, Line, Column, Messagepkg/workflow/lint/lint.go:62Diagnostic—RuleID, ThreatRuleID, Severity, Path, Line, MessageAll five represent a rule violation located in a file, and the common fields (
Line/Messagein all five;File/Path,RuleID,Severityin most) have already started drifting — only 2 of the 5 carry aSeverity, and the location field is named inconsistently (FilevsPath).Recommendation: Introduce one small shared
Location{File, Line, Column}andBaseFinding{RuleID, Severity, Message, Location}(a natural home is the existingpkg/scanfindingspackage), and have the other four embed it while keeping their package-specific extra fields (Site/Sourcesfor taint,ThreatRuleIDfor lint). This does not force a single universal type — it just stops the common quad (RuleID/location/Message) from being retyped five times.Estimated effort: 4-6 hours (touches 5 packages and their call sites). Benefit: new fields (e.g. an "end line" or a normalized
Severityenum) get added once instead of being forgotten in 4 of 5 places.Lower-confidence notes (same name, likely intentionally separate — not recommended for merging, flagged for awareness only):
lint.Rulevstaint.Rule: same name, but one is a whole-ASTCheck(Input) ([]Diagnostic, error)function and the other is a dataflow source/sink/filter predicate set — different analysis paradigms, probably correct to keep separate.workflow.Job/workflow.Workflowvsactions.Job/actions.Workflow: the former is the compiler's flat emission model (plain strings), the latter is a richer typed AST-like model (JobID,Expression,Step) used by the generic Actions-YAML tooling inpkg/workflow/actions. Likely correct to keep as two layers, but the identical naming under the samepkg/workflow/*tree is a readability risk worth a doc comment pointing each at the other.pkg/cli/logs_models.go(MissingToolReport/MissingToolSummary,MissingDataReport/MissingDataSummary,MCPFailureReport/MCPFailureSummary) looked like duplicates at a glance but are actually a consistent, deliberate detail-vs-aggregate pattern — not flagged as an issue.Untyped Usages
Summary Statistics
interface{}usages in non-testpkg/code: 2, both inside comments (pkg/cli/mcp_schema.go:121,pkg/workflow/behavior_defined_engine.go:917) — production code has fully migrated to theanyalias.anyusages: ~22,700 occurrences across 1,557 of 1,798 files — the overwhelming majority are legitimate generic handling of YAML/JSON-decoded workflow frontmatter and GitHub Actions schema fields that are themselves polymorphic (map[string]any,[]any), plus explicitly-documented generic numeric/string conversion helpers (pkg/typeutil/convert.go). Per the what-to-skip guidance, these are not flagged.Category 1: Job-output name constants acting as an unenforced enum
Impact: Low-Medium — 10 of these constants are consumed as plain
stringby 3 call sites (pkg/workflow/known_needs_expressions.go,pkg/workflow/compiler_pre_activation_job.go,pkg/workflow/compiler_activation_outputs.go), so an arbitrary string literal is accepted anywhere one of these is expected.Location:
pkg/constants/job_constants.go:326-337Suggested fix:
Estimated effort: 1-2 hours.
Category 2: Mismatch-reason string constants
Impact: Low.
Location:
pkg/cli/token_usage_types.go:309-311Three mutually-exclusive reason codes, indistinguishable at the type level from the unrelated event-name constants declared two lines below them.
Suggested fix:
type ModelMismatchReason string, applied to all three.Estimated effort: <1 hour.
Category 3: Auth-method string constants
Impact: Low (package-private, only 2 values) — included as a clean, minimal example of the pattern.
Location:
pkg/cli/add_interactive_engine.go:238-239Compared via
==against a plain-stringwizard selection at lines 291, 324 and 331.Suggested fix:
type authMethod string, typing the wizard value accordingly so a typo'd literal can't silently fail the comparison.Estimated effort: <1 hour.
Note on things intentionally not flagged: struct fields explicitly typed
anyfor documented polymorphism were checked and excluded, e.g.observabilityImportEndpoint.Headers any(pkg/parser/import_observability.go:18, commented as kept as any so the workflow package can later normalise both supported forms),On any/Needs anyinpkg/cli/list_workflows_command.goandpkg/cli/runner_guard_activation_gate.go(mirroring GitHub Actions' own polymorphicon:/needs:schema), and the registry/auditmap[string]anymetadata bags — all correctly generic, not refactor candidates.Refactoring Recommendations
Priority 1: Medium-High — Unify the "Finding/Diagnostic" family
Recommendation: Introduce a shared
Location/BaseFindingtype inpkg/scanfindingsand havetaint.Finding,gradershell.Finding,actionslanguageservice.Diagnostic, andlint.Diagnosticembed it.Estimated effort: 4-6 hours. Impact: stops the same 5 fields from drifting independently across 5 static-analysis subsystems.
Priority 2: Medium — Single source of truth for the grader manifest entry
Recommendation: Keep one
graderManifestEntrydefinition (the richerpkg/workflow/compiler_yaml_graders.goversion) and havepkg/cli/audit_report_graders.goreuse it instead of redeclaring a subset.Estimated effort: 2-3 hours.
Priority 3: Low — Remove the
StepID/runtimeImportReferenceduplicatesRecommendation: Consolidate
StepIDinto one package (pkg/workflow/actionsis the natural home) and factorruntimeImportReferenceinto one shared struct.Estimated effort: ~2 hours combined.
Priority 4: Low — Add semantic types to the 3 constant clusters identified
Recommendation: Introduce
JobOutputName,ModelMismatchReason, andauthMethodstring types for the clusters above.Estimated effort: ~2-3 hours combined.
Implementation Checklist
StepIDinto a single packageruntimeImportReferenceinto one shared structgraderManifestEntrya single shared definition (pkg/clireuses thepkg/workflowshape)Location/BaseFindinginpkg/scanfindingsand embed it intaint.Finding,gradershell.Finding,actionslanguageservice.Diagnostic,lint.DiagnosticJobOutputNametype to the 12 job-output constants inpkg/constants/job_constants.goModelMismatchReasontype to the 3 reason constants inpkg/cli/token_usage_types.goauthMethodtype to the 2 constants inpkg/cli/add_interactive_engine.goAnalysis Metadata
get_symbols_overview,find_symbol) + targeted pattern search, with manual verification of every reported cluster before inclusionAll reactions