[typist] Typist - Go Type Consistency Analysis #64471
Closed
Replies: 1 comment
|
This discussion has been marked as outdated by Typist - Go Type Analysis. A newer discussion is available at Discussion #64752. |
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.
Analysis of repository: github/gh-aw — workflow run §36708587651
Executive Summary
I scanned 1,393 non-test
.gofiles underpkg/(roughly 2,466 files total including tests), split acrosspkg/cli(~557 files),pkg/workflow(~540 files), and 34 smaller packages (~396 files), using Serena's semantic tooling plus targetedinterface{}/any/constant pattern searches. In total I found around 700 top-level struct/interface declarations.The good news: this codebase already practices several of the strong-typing patterns I'd normally recommend from scratch —
pkg/types.BaseMCPServerConfigis explicitly embedded by bothparserandworkflowto avoid duplication,pkg/constants.StepID/JobNameandpkg/stringutil.PATTypeare clean typed-string enums withString()/IsValid()methods, and literalinterface{}has been almost entirely replaced byany. The remaining issues are concentrated in a few clear buckets: near-identical structs re-declared under different names (TrialArtifacts/WorkflowTrialResultbeing the cleanest example — three identical fields, down to an identical commented-out line), a dual representation of workflow tool config (WorkflowData.Tools map[string]anyliving alongside an already-parsed*Toolsstruct), and untyped string/int constants sitting right next to well-typed siblings in the same file (pkg/constants/job_constants.gohas a typedStepIDblock immediately followed by a dozen untyped output-name string constants). None of this is urgent, but each cluster below is a small, mechanical, low-risk cleanup.Full Analysis Report
Duplicated Type Definitions
Summary Statistics
.gofiles (pkg/cli,pkg/workflow, 34 other packages)pkg/cli, ~525 inpkg/workflow, ~90-100 elsewhere)pkg/cliandpkg/workfloware each a single Go package, so identical identifiers cannot literally collide within them (the compiler forbids it) — real duplication in those packages shows up as near-identical structs under different names, not exact redeclarations. Exact same-name duplication is only possible across packages.Cluster 1:
TrialArtifacts/WorkflowTrialResult— near-exact field duplicationType: Near-duplicate (verified)
Impact: Medium — same three fields hand-copied between two files, already drifting in comments
Locations:
pkg/cli/trial_support.go:19-24—TrialArtifactspkg/cli/trial_types.go:6-21—WorkflowTrialResultDefinition Comparison (verified by direct read):
Same JSON tags, same field order, even the same commented-out
AgentStdioLogsline copy-pasted between files — a strong signal one was cloned from the other.Recommendation: Have
WorkflowTrialResultembedTrialArtifactsinstead of re-declaring the three shared fields:Cluster 2: "Wire" schema-mirror structs in
pkg/cli/mcp_schema.goType: Near-duplicate (deliberate but risky)
Impact: Medium-high — five hand-maintained structs can silently drift from the real
MarshalJSONoutput they're supposed to mirrorLocations:
mcp_schema.go:239 toolUsageSummaryWiremirrorslogs_report_tools.go:46 ToolUsageSummarymcp_schema.go:247 mcpServerHealthDetailWiremirrorsaudit_expanded.go:90 MCPServerHealthDetailmcp_schema.go:258 mcpServerCrossRunHealthWiremirrorsaudit_cross_run.go:85 MCPServerCrossRunHealthmcp_schema.go:268 mcpFailureSummaryWiremirrorslogs_models.go:237 MCPFailureSummarymcp_schema.go:275 domainAnalysisWireSchemamirrorsaccess_log.go:35 DomainAnalysis(which already has its own hand-rolled siblingaccess_log.go:44 domainAnalysisWire)Recommendation: The
mcp_schema.go:238comment explains these exist becausejsonschema-goreflection can't infer customMarshalJSONoutput — a legitimate constraint. Rather than removing the pattern, add a round-trip test per pair (marshal the real type, unmarshal into the Wire type, assert field-for-field equality) so schema drift fails CI instead of shipping silently.Cluster 3: Dual tool-config representation in
pkg/workflow.WorkflowDataType: Near-duplicate / stale untyped field (verified)
Impact: High — this is the compiler's central data structure
Location:
pkg/workflow/workflow_data.go:90-92A fully-typed
*Toolsstruct already exists and is populated fromTools, but the untypedmap[string]anyremains the field threaded through much of the compiler (per the sub-analysis,Toolsis read far more widely thanParsedTools).Recommendation: Audit remaining
WorkflowData.Toolsreads, migrate them toParsedTools, and once nothing depends on the raw map, renameParsedToolstoToolsand drop the untyped field entirely (or keep the raw map only as a private parse-time intermediate, not a public field).Cluster 4: Near-duplicate "hosted web policy" / "network config" chains in
pkg/workflowType: Near-duplicate (layered, partially intentional)
Impact: Medium — high confusion risk even where layering is deliberate
Locations:
HostedWebPolicy(engine.go:210) vs.AWFHostedWebConfig/AWFHostedWebPolicy(awf_config.go:219,225) — same enabled/allowed/blocked/max-uses shape, divergent field names (AllowedvsAllowedDomains) across the frontmatter → AWF-runtime boundaryEngineNetworkConfig(engine.go:263) /EngineNetworkDefinition(engine_definition.go:189) /AWFNetworkConfig(awf_config.go:120) — three shapes across the frontmatter→definition→runtime pipelineEngineInstallConfig(engine_helpers.go:56) vs.EngineInstallationDefinition(engine_definition.go:198) — two parallel install-step systems (hardcoded vs. declarative engines)Recommendation: Where a working converter already exists (as with
EngineCapabilities→EngineCapabilitiesDefinition'sToRuntimeCapabilities()), no change needed — that's the right pattern. Where it doesn't (the three clusters above), add one and standardize field names (AllowedvsAllowedDomains) so the same concept doesn't require re-reading two structs to map fields.Cluster 5: "Per-domain stats" sprawl in
pkg/cli(lower confidence)Type: Near-duplicate concept, 8 occurrences
Impact: Low-medium — each may be justified by a different reporting context
Locations:
DomainItem(domains_command.go:35),DomainRequestStats(firewall_log.go:157),DomainBreakdown(outcome_domain_breakdown.go:14),DomainInventoryEntry/DomainRunStatus(audit_cross_run.go:152,162),DomainDiffEntry(audit_diff.go:31),DomainBuckets(domain_buckets.go:13),RedactedDomainsAnalysis(redacted_domains.go:21),domainAggregation(logs_report_firewall.go:33)Recommendation: This package already has a proven fix for exactly this shape of problem — the existing
AggregatedSummaryBase/MCPServerStatsBase/ToolUsageStatsBase/FirewallSummaryBase/DiffEntryBase/AnalysisBaseembedding pattern. Apply the same base-struct-plus-embedding approach to the Domain-* family rather than introducing a new abstraction.Untyped Usages
Summary Statistics
interface{}is essentially gone from production code — the codebase has already standardized onany.any/map[string]anyusage (thousands of occurrences) is intentional: arbitrary YAML/JSON frontmatter, MCP tool config, and JSON-RPC passthrough where the schema is genuinely user-defined or spec-mandated (e.g. JSON-RPC 2.0's polymorphicidfield). These were explicitly excluded from findings below.Category 1:
interface{}/anyin struct fields (real candidates)pkg/cli/copilot_events_jsonl.go:76Usage map[string]any{PromptTokens, CompletionTokens, TotalTokens int}InputTokens int/OutputTokens inton the same structpkg/cli/audit_report.go:161-171CreatedItemReport.ID any,.BeforeState/.AfterState map[string]anyID:string(GitHub node ID); before/after likelymap[string]stringper label-diff usagepkg/cli/bootstrap_profile_helpers.go:264,283manifest map[string]any(GitHub App manifest)GitHubAppManifeststructmanifest["default_permissions"]at line 285-289 — exactly the churn a concrete type removespkg/workflow/workflow_data.go:90Tools map[string]any*Tools(see Cluster 3 above)pkg/workflow/safe_output_handlers.go(~35 entries)NewConfig func() any { return &XConfig{} }SafeOutputConfigmarker interfacepkg/console/console_types.go:49FormField.Value anypkg/parser/import_observability.go:19observabilityImportEndpoint.Headers anystring | map[string]stringanydeliberately for later normalization bypkg/workflow— flagged, not a clean skipCategory 2: Untyped Constants
The strongest pattern here is inconsistency within a single file — a typed enum sits right next to an untyped one for the same kind of value:
Suggested fix: introduce
type OutputName stringmirroringStepIDand retype the output-name block — this is a copy-paste of a pattern the file already demonstrates correctly.Other verified/reported untyped-constant clusters:
pkg/workflow/run_phase.go:8-10runPhaseAgent = "agent", etc.type RunPhase stringpkg/workflow/sandbox_agent_images.go:32-42type AWFImageRole stringpkg/workflow/enclaves.go:46-53enclaveMCPConnectTimeout = 120,enclaveMCPReadinessTimeoutMS = 120000time.Duration-typed consts (name mixes seconds/ms today)pkg/workflow/ledger.go:19-21vspkg/workflow/repo_memory.go:28pkg/cli/add_interactive_engine.go:238-239authMethodCopilotRequests/authMethodPATbare strings, compared with==at 3 call sitestype authMethod stringpkg/cli/run_workflow_execution.go:25workflowCompletionWaitTimeoutMinutes = 6 * 60(bare int named "Minutes" storing 360)const workflowCompletionWaitTimeout = 6 * time.Hourpkg/cli/token_usage_types.go:149-150modelMismatchReasonTokenUsageMissing/ModelNotObservedbare strings assigned into a plain-stringfieldtype ModelMismatchReason stringpkg/agentdrain/anomaly.goAnomalyWeightNew/Low/Rare/MaxScorebarefloat64type AnomalyWeight float64pkg/cli/logs_cached_json.go:24,audit_cache.go:16,add_package_ownership.go:24intconstants, each compared against an unrelated struct fieldWhat's already good (cite as the target pattern)
pkg/types.BaseMCPServerConfig— explicitly embedded by bothpkg/parserandpkg/workflow"to eliminate duplication"; exactly the shared-type-package pattern to extend to the clusters above.pkg/stringutil.PATTypeandpkg/constants.StepID/JobName— typed string enums withString()/IsValid()methods.pkg/parser.ValidationErrorembeddingpkg/validationerror.Payload, detectable viaerrors.As— a clean shared-interface pattern other ad hoc error structs could imitate.Refactoring Recommendations
Priority 1 —
WorkflowData.Toolsdual representation (Cluster 3): highest blast radius since it's the compiler's core struct; migrate remainingToolsmap reads to the existing typedParsedTools, then retire the map. ~4-6 hours.Priority 2 —
TrialArtifacts/WorkflowTrialResultduplication (Cluster 1): mechanical, low-risk, embed instead of re-declare. <1 hour.Priority 3 —
job_constants.gooutput-name constants: copy the file's ownStepIDpattern onto the output-name block. ~1 hour.Priority 4 — MCP schema "Wire" struct drift risk (Cluster 2): add round-trip tests rather than removing the pattern (the underlying constraint is real). 2-3 hours.
Priority 5 (lower confidence, discuss first) — Domain-* stats sprawl (Cluster 5) and the hosted-web/network-config layering (Cluster 4): apply the codebase's own existing
*Baseembedding pattern / add missing converters.Implementation Checklist
TrialArtifactsintoWorkflowTrialResult*Wirestructs inmcp_schema.goWorkflowData.Toolsreaders toParsedTools, then drop the untyped map fieldtype OutputName stringinpkg/constants/job_constants.gotype RunPhase string/type AWFImageRole stringinpkg/workflow*Baseembedding patternHostedWebPolicy/EngineNetworkConfigchain field-name consistencyAnalysis Metadata
pkg/cli,pkg/workflow, 34 other packages)activate_project, symbol/reference search) + targeted grep pattern matching, with direct-read verification of the top clustersReferences:
All reactions