You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Good news first: this codebase is already disciplined about cross-package type sharing. Rather than copy-pasting struct definitions, it leans on Go type aliases — e.g. type InputDefinition = types.InputDefinition, type SanitizeOptions = stringutil.SanitizeOptions, type LogMetrics = workflow.LogMetrics, the ActionPin/ActionYAMLInput family re-exported from pkg/actionpins, and fan-outs like MissingDataConfig/MissingToolConfig/ReportIncompleteConfig = IssueReportingConfig and CloseIssuesConfig/ClosePullRequestsConfig/CloseDiscussionsConfig = CloseEntityConfig. So most same-name-in-two-places hits are intentional single-source-of-truth aliases, not duplication. 🎉
Across ~990 non-test .go files under pkg/ (~1,015 top-level types), the genuine opportunities cluster into: three parallel shapes for GitHub rate-limit data, a family of per-tool scanner finding structs, several MCP-server-config representations, and two parallel audit diff vs. comparison delta vocabularies. On typing, any/interface{} appears in 160+ files — mostly legitimate YAML/frontmatter parsing, with a few spots where a concrete type would remove runtime assertions. Nothing on fire — a friendly punch-list. 🙂
Method: repo-wide type/any pattern extraction plus Serena-assisted spot verification. Clusters marked exact were read and confirmed; semantic ones are judgment calls for a human.
⚠️False positives (ignore):SpinnerWrapper, ProgressBar, RepositoryFeatures each appear twice only as //go:build wasm build-tag variants — the same name is required. Leave them.
logs_github_rate_limit_usage.go:33GitHubRateLimitEntry (Reset as string)
logs_rate_limit.go:36rateLimitResource (Reset as int64)
update_org.go:48orgRateLimitResponse
Same limit/remaining/used/reset concept modeled 3x, with a Reset type mismatch (string vs int64). Fix: one shared RateLimitBucket; reconcile the Reset encoding. Effort 2-3h.
Overlapping fields (rule id, message, severity, path, line). Fix: keep thin per-tool decode structs, add one internal ScanFinding, convert at each boundary. Effort 3-4h.
Cluster 3 (near) — Experiment records (exported vs. JSON twin)
cli/experiments_command.go:41ExperimentRunRecord vs cli/audit_report_experiments.go:42experimentRunRecord; also ExperimentState vs experimentStateJSON.
Fix: if the twins only decode the same JSON, delete them and decode into the exported types. Effort 1-2h.
Cluster 4 (semantic) — MCP-server config shapes across packages
Layered-by-design, so not a full merge — but check whether the others can embedBaseMCPServerConfig instead of redeclaring overlapping fields. Effort 4-6h.
Cluster 5 (semantic) — Audit diff vs. comparison deltas
cli/audit_diff.go — AuditDiff, FirewallDiff, MCPToolsDiff, ToolCallsDiff, TokenUsageDiff, and more
cli/audit_comparison.go — AuditComparisonDelta, AuditComparisonIntDelta, AuditComparisonStringDelta, and more
Two parallel difference-between-two-runs vocabularies. Consider a generic Delta[T any] struct{ Before, After T; Changed bool } to collapse the int/string delta twins. Effort 3-5h.
Untyped Usages
any/interface{} in 160+ non-test files; dominant pattern is map[string]any for YAML/frontmatter (largely idiomatic at the boundary).
Category 1 — map[string]any threaded deep (medium):
cli/codemod_factory.go:13PostTransformFunc(... frontmatter map[string]any, fieldValue any) — both untyped
Decode into structs near the boundary where the shape is known; keep the map only at the raw-YAML edge.
Category 2 — any factory + untyped scope (low/medium):
workflow/safe_output_handlers.go:17NewConfig func() any (40+ uses). A marker interface would restore some compile-time safety.
workflow/tools_types.go:302type GitHubReposScope any — the comment documents two real shapes (string or slice); a small sum-type or decode-time validation fits.
Category 3 — untyped string constants (low):pkg/constants already defines strong types (JobName, StepID, EngineName, WorkflowID, URL, and more), but filename/artifact-name constants in job_constants.go (SafeOutputArtifactName, AgentOutputFilename, SarifFileName) stay untyped. Optional — type only to prevent mixing artifact names with arbitrary strings.
Prioritized Recommendations
Medium — shared RateLimitBucket, reconcile Reset encoding (Cluster 1). 2-3h.
Medium — internal ScanFinding + per-tool adapters (Cluster 2). 3-4h.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
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
Good news first: this codebase is already disciplined about cross-package type sharing. Rather than copy-pasting struct definitions, it leans on Go type aliases — e.g.
type InputDefinition = types.InputDefinition,type SanitizeOptions = stringutil.SanitizeOptions,type LogMetrics = workflow.LogMetrics, theActionPin/ActionYAMLInputfamily re-exported frompkg/actionpins, and fan-outs likeMissingDataConfig/MissingToolConfig/ReportIncompleteConfig = IssueReportingConfigandCloseIssuesConfig/ClosePullRequestsConfig/CloseDiscussionsConfig = CloseEntityConfig. So most same-name-in-two-places hits are intentional single-source-of-truth aliases, not duplication. 🎉Across ~990 non-test
.gofiles underpkg/(~1,015 top-level types), the genuine opportunities cluster into: three parallel shapes for GitHub rate-limit data, a family of per-tool scanner finding structs, several MCP-server-config representations, and two parallel audit diff vs. comparison delta vocabularies. On typing,any/interface{}appears in 160+ files — mostly legitimate YAML/frontmatter parsing, with a few spots where a concrete type would remove runtime assertions. Nothing on fire — a friendly punch-list. 🙂Full Analysis Report
Duplicated Type Definitions
pkg/)Cluster 1 (near) — GitHub rate-limit data, 3 shapes in
pkg/clilogs_github_rate_limit_usage.go:33GitHubRateLimitEntry(Reset asstring)logs_rate_limit.go:36rateLimitResource(Reset asint64)update_org.go:48orgRateLimitResponseSame limit/remaining/used/reset concept modeled 3x, with a
Resettype mismatch (stringvsint64). Fix: one sharedRateLimitBucket; reconcile theResetencoding. Effort 2-3h.Cluster 2 (near) — Per-tool scanner finding structs
cli/zizmor.go:23zizmorFinding·cli/poutine.go:24poutineFinding·cli/runner_guard.go:21runnerGuardFinding·cli/audit_report.go:63Finding·workflow/markdown_security_scanner.go:57SecurityFindingOverlapping fields (rule id, message, severity, path, line). Fix: keep thin per-tool decode structs, add one internal
ScanFinding, convert at each boundary. Effort 3-4h.Cluster 3 (near) — Experiment records (exported vs. JSON twin)
cli/experiments_command.go:41ExperimentRunRecordvscli/audit_report_experiments.go:42experimentRunRecord; alsoExperimentStatevsexperimentStateJSON.Fix: if the twins only decode the same JSON, delete them and decode into the exported types. Effort 1-2h.
Cluster 4 (semantic) — MCP-server config shapes across packages
types/mcp.go:6BaseMCPServerConfig·workflow/tools_types.go:430MCPServerConfig·parser/mcp.go:39RegistryMCPServerConfig(+MCPServerInfo) ·cli/mcp_registry.go:19MCPRegistryServerForProcessing·cli/mcp_registry_types.go:26ServerDetail·cli/mcp_config_file.go:22VSCodeMCPServerLayered-by-design, so not a full merge — but check whether the others can embed
BaseMCPServerConfiginstead of redeclaring overlapping fields. Effort 4-6h.Cluster 5 (semantic) — Audit diff vs. comparison deltas
cli/audit_diff.go—AuditDiff,FirewallDiff,MCPToolsDiff,ToolCallsDiff,TokenUsageDiff, and morecli/audit_comparison.go—AuditComparisonDelta,AuditComparisonIntDelta,AuditComparisonStringDelta, and moreTwo parallel difference-between-two-runs vocabularies. Consider a generic
Delta[T any] struct{ Before, After T; Changed bool }to collapse the int/string delta twins. Effort 3-5h.Untyped Usages
any/interface{}in 160+ non-test files; dominant pattern ismap[string]anyfor YAML/frontmatter (largely idiomatic at the boundary).Category 1 — map[string]any threaded deep (medium):
cli/codemod_factory.go:13PostTransformFunc(... frontmatter map[string]any, fieldValue any)— both untypedcli/outcome_eval_update.go:25mutableStateLoader ... (map[string]any, bool, error)cli/devcontainer.go:45DevcontainerFeatures map[string]any·workflow/mcp_config_types.go:66MapToolConfig map[string]anyDecode into structs near the boundary where the shape is known; keep the map only at the raw-YAML edge.
Category 2 — any factory + untyped scope (low/medium):
workflow/safe_output_handlers.go:17NewConfig func() any(40+ uses). A marker interface would restore some compile-time safety.workflow/tools_types.go:302type GitHubReposScope any— the comment documents two real shapes (string or slice); a small sum-type or decode-time validation fits.Category 3 — untyped string constants (low):
pkg/constantsalready defines strong types (JobName,StepID,EngineName,WorkflowID,URL, and more), but filename/artifact-name constants injob_constants.go(SafeOutputArtifactName,AgentOutputFilename,SarifFileName) stay untyped. Optional — type only to prevent mixing artifact names with arbitrary strings.Prioritized Recommendations
RateLimitBucket, reconcileResetencoding (Cluster 1). 2-3h.ScanFinding+ per-tool adapters (Cluster 2). 3-4h.BaseMCPServerConfig(Cluster 4); genericDelta[T](Cluster 5); marker interface for the safe-output factory (Cat 2).Checklist
RateLimitBucket+Resetencoding reconciledScanFinding+ adaptersBaseMCPServerConfigembeddingDelta[T]Files analyzed: ~990 · Types: ~1,015 · Clusters: 5 (+3 false positives) · Untyped footprint: 160+ files · Date: 2026-07-02
Beta Was this translation helpful? Give feedback.
All reactions