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
I scanned 1,073 non-test, non-testdata .go files under pkg/ (960 struct types, 27 interfaces) looking for duplicated type definitions and weakly-typed (interface{}/any) usage. The good news first: there is no accidental exact-duplicate struct type in the codebase — the only 4 name collisions I found (RepositoryFeatures, SpinnerWrapper, ProgressBar, plus a fakeOS/Worker pair in linter testdata) are all legitimate (go/redacted):build js || wasm vs (go/redacted):build !js && !wasm platform-specific pairs, which is the correct idiomatic way to do this in Go.
Where it gets more interesting is near-duplication: the same shape of struct hand-copied under different names, and a handful of fields (TargetRepoSlug, AllowedRepos, Footer) that are pasted verbatim into a dozen-plus safe-output *Config structs instead of living in one shared mixin. The biggest single win is consolidating TargetRepoSlug/AllowedRepos — that field pair alone is referenced 148 times across 25 files, so a single shared embed would remove a lot of copy-paste surface area in one shot. On the untyped-usage side, most any/map[string]any in this repo is legitimate (it's parsing genuinely dynamic YAML frontmatter and JSON schemas) — but I found several fields where the actual runtime shape is a small, closed set (bool-or-string, string-or-slice) that the codebase already has a named type for (TemplatableBool) and just isn't using consistently in a few spots.
Full Analysis Report
Duplicated Type Definitions
Summary Statistics
Total struct types analyzed: 960 (non-test, excluding testdata/)
Total interface types analyzed: 27
Exact name collisions found: 4 — all legitimate wasm/native build-tag pairs (not defects)
Near-duplicate clusters found: 6
High-impact clusters (100+ reference sites): 1
Medium-impact clusters: 3
Low-impact / low-confidence clusters: 2
Cluster 1: TargetRepoSlug / AllowedRepos field pair — repeated across 12 safe-output Config structs
Type: Near duplicate (copy-pasted field pair, not a full struct collision) Impact: High — 148 references to .TargetRepoSlug across 25 files
An identical field appears verbatim in 12 different *Config structs:
Benefits: single source of truth for cross-repo targeting semantics; new safe-output types get the field for free
Cluster 2: Footer *string field — repeated across 11 Create/Update Config structs
Type: Near duplicate Impact: Medium-High — 64 references across 17 files
Same field + same doc comment ("Controls whether AI-generated footer is added...") copy-pasted into create_issue.go, create_discussion.go, create_pull_request.go, update_discussion.go, update_issue.go, update_pull_request.go, update_release.go, submit_pr_review.go, reply_to_pr_review_comment.go, comment_memory.go, add_comment.go.
Recommendation: fold into the same shared mixin as Cluster 1, or into BaseSafeOutputConfig/UpdateEntityConfig wherever it's currently missing.
Estimated effort: 1-2 hours
Benefits: consistent footer behavior guaranteed by the type system instead of by convention
Cluster 3: GitHubMCPDockerOptions vs GitHubMCPRemoteOptions — same file, ~65% field overlap
Type: Near duplicate Impact: Low usage count (4 files) but 100% avoidable boilerplate
Locations: pkg/workflow/mcp_renderer_types.go:66 and :100
Recommendation: factor a shared GitHubMCPCommonOptions struct embedded by both; keep transport-specific fields on each wrapper.
Estimated effort: 1 hour
Benefits: shrinks two large structs down to their actual differences
Cluster 4: AgentAPIProxyTargetConfig vs AWFAPITargetConfig — same package, manual field-copy already present
Type: Near duplicate Impact: Medium — ~7 referencing files, plus existing manual-copy code that would disappear
Locations: pkg/workflow/sandbox.go:101 and pkg/workflow/awf_config.go:337
Both share AuthHeader string, ExtraHeaders map[string]string, ExtraBodyFields map[string]string, SessionId string, with near-identical doc comments. AWFAPITargetConfig adds Host string. Telling evidence: pkg/workflow/awf_config.go:625-646 already manually copies these fields one-by-one between the two structs (existing.AuthHeader = copilotFrontmatter.AuthHeader, etc.) — direct proof this is one concept expressed twice.
Recommendation: pull the 4 shared fields into a common embedded struct to eliminate the manual copy block. Full merge may not be desirable since the two represent genuinely different wire formats (YAML frontmatter vs. AWF JSON config), so a partial embed is the pragmatic fix.
Estimated effort: 2 hours
Benefits: removes hand-written sync code that will silently drift if a field is added to one struct and not the other
Cluster 5: LogsDownloadOptions vs StdinLogsOptions — 17 identical fields
Type: Near duplicate Impact: Medium — 40 references across 11 files in pkg/cli
Locations: pkg/cli/logs_orchestrator_types.go:8 and :39
17 fields identical between the two: OutputDir, Engine, RepoOverride, Verbose, ToolGraph, NoStaged, FirewallOnly, NoFirewall, Parse, JSONOutput, SummaryFile, SafeOutputType, FilteredIntegrity, EvalsOnly, Train, Format, ReportFile, ArtifactSets. LogsDownloadOptions additionally carries run-selection fields (WorkflowName, Count, date range, BeforeRunID/AfterRunID, TimeoutMinutes); StdinLogsOptions instead has RunURLs/Timeout.
Recommendation: extract a LogsProcessingOptions embed for the 17 shared fields; keep run-selection fields on each wrapper.
Estimated effort: 2-3 hours
Benefits: one place to add new "how to process downloaded logs" options instead of two
Cluster 6: ErrorInfo vs CompileValidationError — same package, 3-of-4 fields identical
Type: Near duplicate, lower confidence Impact: Moderate — worth a spot-check before merging (JSON tag names differ slightly)
Both represent "a validation/error entry with a type, message, and line number" in the same package.
Recommendation: consolidate into one pkg/cli type (e.g. ValidationIssue) with an optional File field, shared by the audit-report pipeline and the compile-validation pipeline.
Estimated effort: 2 hours (needs care around JSON tag compatibility)
Benefits: one error-reporting shape used consistently across CLI subcommands
Checked and ruled out (no action needed): the MCPServerConfig (workflow) / RegistryMCPServerConfig (parser) / BaseMCPServerConfig (types) trio is already a deliberate, documented de-duplication via embedding. CacheMemoryToolConfig/CommentMemoryToolConfig are intentional thin Raw any delegation stubs. Most other Create*Config/Update*Config overlap beyond Clusters 1-2 is legitimate per-entity variation — each already embeds BaseSafeOutputConfig/UpdateEntityConfig.
Untyped constants worth a named type: 3 highlighted examples
Legitimate any usage (genuinely dynamic YAML/JSON frontmatter, generic AST/tree traversal): the large majority — correctly left alone
Most interface{}/any usage in this codebase is defensible: gh-aw parses YAML frontmatter, GitHub Actions config, and JSON schemas where the input shape is genuinely author-controlled and dynamic (e.g. FrontmatterConfig fields like Engine any, Imports any, RunsOn any are explicitly documented as accepting 2+ shapes). Those were deliberately not flagged — narrowing them would reduce legitimate robustness to author-supplied variance. The findings below are different: cases where gh-aw's own internal, closed-schema data is carried in an any field even though only 2-3 concrete shapes are ever produced.
Category 1: Fields That Should Reuse the Existing TemplatableBool Type
Impact: High — the codebase already solved this problem once and just isn't applying it consistently
Example 1: WorkflowStep.ContinueOnError
Location: pkg/workflow/step_types.go:28
Current: ContinueOnError any // Can be bool or string expression
Suggested fix: ContinueOnError *TemplatableBool (the type already defined at pkg/workflow/templatables.go:143 for exactly this bool-or-expression pattern)
Why it matters: direct inconsistency — the same 2-way sum type is correctly typed in some structs and left as any in others; unifying removes a class of assertion bugs
Current: any — comment says "bool, templatable expression string, or []interface{} categories"
Evidence: pkg/workflow/notify_comment_conclusion_helpers.go:346 does a 3-arm type switch (bool/string/[]any); the []any categories case is already parsed out separately into ReportFailureAsIssueCategories/ReportFailureAsIssueExcludedCategories fields right next to it
Suggested fix: since categories already have their own typed fields, this field only needs to represent bool-or-expression — reuse TemplatableBool here too
Benefits: removes a redundant runtime type switch on every consumer
Category 2: any Fields With a Documented, Closed Shape Not Yet Extracted Into a Type
Impact: Medium-High — parser already normalizes to 1-2 concrete types; the field just doesn't say so
Example: GitHubToolConfig.PrivateToPublicFlows
Location: pkg/workflow/tools_types.go:375
Current: any — doc says "allow" (string) or []string of server IDs
Evidence: pkg/workflow/tools_parser.go:394-412 normalizes every input shape down to exactly string or []string before storing; three consumer files each independently re-derive the shape via type assertion (pkg/workflow/mcp_gateway_config.go:175, pkg/workflow/strict_mode_network_validation.go:182 and :203)
Suggested fix: a small sum type, e.g. type PrivateToPublicFlows struct { Allow bool; Servers []string }, set once by the parser instead of re-derived three times
Benefits: a typo'd type assertion currently fails silently into a default branch; a struct makes that impossible
Current: type-switches over nil/string/float64/int/int64, but since these are MCP tool args always decoded from JSON, only string/float64 are ever actually produced — the int/int64 arms are dead for real traffic
Suggested fix: a StringOrNumber wrapper with custom UnmarshalJSON, or just narrow the type-switch/document that only 2 arms are reachable
Benefits: tightens a boundary type that's wider than what's actually reachable
Category 3: Untyped Constants Worth a Named Type
Impact: Medium — semantic clarity, prevents mixing incompatible units
// pkg/constants/constants.go:332,335 — bare ints for guardrail capsconstDefaultMaxRuns=500constDefaultMaxTurnCacheMisses=5// → type RunCount int; reuse across AWF guardrail signatures// pkg/cli/audit_cross_run.go:14,18 — bare float64 ratiosconstmcpErrorRateThreshold=0.10constmcpConnectionRateThreshold=0.75// → type RateThreshold float64, so these can't be mixed up with a raw count// pkg/constants/constants.go:245 — bare byte-size constantconstDefaultMCPGatewayPayloadSizeThreshold=524288// → type ByteSize int64, matching how time.Duration already models durations in this same file
Locations: pkg/constants/constants.go, pkg/cli/audit_cross_run.go Benefits: makes units explicit at call sites, following a pattern (time.Duration) the codebase already uses elsewhere in the same file
Refactoring Recommendations
Priority 1: High-Impact Field Consolidation
Recommendation: extract the TargetRepoSlug/AllowedRepos and Footer field pairs into shared mixins (Clusters 1-2)
Steps:
Add CrossRepoTargetConfig (or extend BaseSafeOutputConfig) with TargetRepoSlug/AllowedRepos
Add Footer *string to the same or an adjacent shared mixin
Replace the 12 (resp. 11) hand-copied field declarations with embeds
Run tests to confirm YAML tag behavior is unchanged
Estimated effort: 3-5 hours combined Impact: High — touches 148 + 64 reference sites' declaration source, zero behavior change
Priority 2: Reuse TemplatableBool Consistently
Recommendation: replace WorkflowStep.ContinueOnError and SafeOutputsConfig.ReportFailureAsIssue with *TemplatableBool
Steps:
Update the two field declarations
Update the type-switch call sites to use TemplatableBool's existing accessor methods instead of raw type switches
Run tests
Estimated effort: 2-3 hours Impact: High — removes duplicated bool-or-expression parsing logic scattered across consumers
Estimated effort: 7-9 hours combined Impact: Medium — mostly boilerplate reduction and removal of manual field-sync code
Priority 4: Named Types for Closed-Shape any Fields and Constants
Recommendation: introduce PrivateToPublicFlows, normalize runnerGuardWorkflowJob.Needs at unmarshal time, and add semantic types (RunCount, RateThreshold, ByteSize) to the constants called out above
Estimated effort: 4-6 hours combined Impact: Medium — compile-time safety at a handful of internal boundaries; low risk since these are gh-aw's own data, not third-party input
Replace ContinueOnError/ReportFailureAsIssueany fields with *TemplatableBool
Factor GitHubMCPCommonOptions for the Docker/Remote options pair (Cluster 3)
Share fields between AgentAPIProxyTargetConfig/AWFAPITargetConfig, remove manual copy code (Cluster 4)
Extract LogsProcessingOptions for the logs download/stdin option pair (Cluster 5)
Consolidate ErrorInfo/CompileValidationError after confirming JSON tag compatibility (Cluster 6)
Type GitHubToolConfig.PrivateToPublicFlows as a small sum type
Normalize runnerGuardWorkflowJob.Needs at unmarshal time
Add named types for the 3 highlighted untyped constants
Run full test suite after each consolidation step
Analysis Metadata
Total Go Files Analyzed: 1,073 (non-test, excluding testdata/, under pkg/)
Total Struct/Interface Definitions: 960 structs, 27 interfaces
Exact Name Collisions: 4 (all legitimate wasm/native build-tag pairs — no action needed)
Near-Duplicate Clusters: 6
High-Confidence Untyped-Usage Findings: 5
Untyped Constants Highlighted: 3
Detection Method: static grep-based struct/interface inventory + targeted field-level comparison and reference tracing (no Serena MCP available in this run; analysis performed via ripgrep + direct file reads)
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
I scanned 1,073 non-test, non-testdata
.gofiles underpkg/(960 struct types, 27 interfaces) looking for duplicated type definitions and weakly-typed (interface{}/any) usage. The good news first: there is no accidental exact-duplicate struct type in the codebase — the only 4 name collisions I found (RepositoryFeatures,SpinnerWrapper,ProgressBar, plus afakeOS/Workerpair in linter testdata) are all legitimate(go/redacted):build js || wasmvs(go/redacted):build !js && !wasmplatform-specific pairs, which is the correct idiomatic way to do this in Go.Where it gets more interesting is near-duplication: the same shape of struct hand-copied under different names, and a handful of fields (
TargetRepoSlug,AllowedRepos,Footer) that are pasted verbatim into a dozen-plus safe-output*Configstructs instead of living in one shared mixin. The biggest single win is consolidatingTargetRepoSlug/AllowedRepos— that field pair alone is referenced 148 times across 25 files, so a single shared embed would remove a lot of copy-paste surface area in one shot. On the untyped-usage side, mostany/map[string]anyin this repo is legitimate (it's parsing genuinely dynamic YAML frontmatter and JSON schemas) — but I found several fields where the actual runtime shape is a small, closed set (bool-or-string, string-or-slice) that the codebase already has a named type for (TemplatableBool) and just isn't using consistently in a few spots.Full Analysis Report
Duplicated Type Definitions
Summary Statistics
testdata/)Cluster 1:
TargetRepoSlug/AllowedReposfield pair — repeated across 12 safe-output Config structsType: Near duplicate (copy-pasted field pair, not a full struct collision)
Impact: High — 148 references to
.TargetRepoSlugacross 25 filesAn identical field appears verbatim in 12 different
*Configstructs:Locations:
pkg/workflow/create_issue.go,create_discussion.go,create_pull_request.go,create_agent_session.go,create_code_scanning_alert.go,create_pr_review_comment.go,update_project.go,push_to_pull_request_branch.go,dispatch_workflow.go,comment_memory.go,add_comment.go,safe_outputs_parser.goRecommendation: extract a small embeddable mixin (the codebase already uses this pattern successfully for
BaseSafeOutputConfig):Cluster 2:
Footer *stringfield — repeated across 11 Create/Update Config structsType: Near duplicate
Impact: Medium-High — 64 references across 17 files
Same field + same doc comment ("Controls whether AI-generated footer is added...") copy-pasted into
create_issue.go,create_discussion.go,create_pull_request.go,update_discussion.go,update_issue.go,update_pull_request.go,update_release.go,submit_pr_review.go,reply_to_pr_review_comment.go,comment_memory.go,add_comment.go.Recommendation: fold into the same shared mixin as Cluster 1, or into
BaseSafeOutputConfig/UpdateEntityConfigwherever it's currently missing.Cluster 3:
GitHubMCPDockerOptionsvsGitHubMCPRemoteOptions— same file, ~65% field overlapType: Near duplicate
Impact: Low usage count (4 files) but 100% avoidable boilerplate
Locations:
pkg/workflow/mcp_renderer_types.go:66and:100Shared fields:
ReadOnly,Lockdown,LockdownFromStep,GuardPoliciesFromStep,Toolsets,Features,AllowedTools []string,GuardPolicies map[string]any(8 of ~12-13 fields). Docker-only:DockerImageVersion,CustomArgs,IncludeTypeField,EffectiveToken,ContainerPinMappings. Remote-only:AuthorizationValue,IncludeToolsField,IncludeEnvSection.Recommendation: factor a shared
GitHubMCPCommonOptionsstruct embedded by both; keep transport-specific fields on each wrapper.Cluster 4:
AgentAPIProxyTargetConfigvsAWFAPITargetConfig— same package, manual field-copy already presentType: Near duplicate
Impact: Medium — ~7 referencing files, plus existing manual-copy code that would disappear
Locations:
pkg/workflow/sandbox.go:101andpkg/workflow/awf_config.go:337Both share
AuthHeader string,ExtraHeaders map[string]string,ExtraBodyFields map[string]string,SessionId string, with near-identical doc comments.AWFAPITargetConfigaddsHost string. Telling evidence:pkg/workflow/awf_config.go:625-646already manually copies these fields one-by-one between the two structs (existing.AuthHeader = copilotFrontmatter.AuthHeader, etc.) — direct proof this is one concept expressed twice.Recommendation: pull the 4 shared fields into a common embedded struct to eliminate the manual copy block. Full merge may not be desirable since the two represent genuinely different wire formats (YAML frontmatter vs. AWF JSON config), so a partial embed is the pragmatic fix.
Cluster 5:
LogsDownloadOptionsvsStdinLogsOptions— 17 identical fieldsType: Near duplicate
Impact: Medium — 40 references across 11 files in
pkg/cliLocations:
pkg/cli/logs_orchestrator_types.go:8and:3917 fields identical between the two:
OutputDir,Engine,RepoOverride,Verbose,ToolGraph,NoStaged,FirewallOnly,NoFirewall,Parse,JSONOutput,SummaryFile,SafeOutputType,FilteredIntegrity,EvalsOnly,Train,Format,ReportFile,ArtifactSets.LogsDownloadOptionsadditionally carries run-selection fields (WorkflowName,Count, date range,BeforeRunID/AfterRunID,TimeoutMinutes);StdinLogsOptionsinstead hasRunURLs/Timeout.Recommendation: extract a
LogsProcessingOptionsembed for the 17 shared fields; keep run-selection fields on each wrapper.Cluster 6:
ErrorInfovsCompileValidationError— same package, 3-of-4 fields identicalType: Near duplicate, lower confidence
Impact: Moderate — worth a spot-check before merging (JSON tag names differ slightly)
Locations:
pkg/cli/audit_report.go:158(File,Line,Type,Message) vspkg/cli/compile_config.go:52(Type,Message,Line)Both represent "a validation/error entry with a type, message, and line number" in the same package.
Recommendation: consolidate into one
pkg/clitype (e.g.ValidationIssue) with an optionalFilefield, shared by the audit-report pipeline and the compile-validation pipeline.Checked and ruled out (no action needed): the
MCPServerConfig(workflow) /RegistryMCPServerConfig(parser) /BaseMCPServerConfig(types) trio is already a deliberate, documented de-duplication via embedding.CacheMemoryToolConfig/CommentMemoryToolConfigare intentional thinRaw anydelegation stubs. Most otherCreate*Config/Update*Configoverlap beyond Clusters 1-2 is legitimate per-entity variation — each already embedsBaseSafeOutputConfig/UpdateEntityConfig.Untyped Usages
Summary Statistics
any): 5anyusage (genuinely dynamic YAML/JSON frontmatter, generic AST/tree traversal): the large majority — correctly left aloneMost
interface{}/anyusage in this codebase is defensible: gh-aw parses YAML frontmatter, GitHub Actions config, and JSON schemas where the input shape is genuinely author-controlled and dynamic (e.g.FrontmatterConfigfields likeEngine any,Imports any,RunsOn anyare explicitly documented as accepting 2+ shapes). Those were deliberately not flagged — narrowing them would reduce legitimate robustness to author-supplied variance. The findings below are different: cases where gh-aw's own internal, closed-schema data is carried in ananyfield even though only 2-3 concrete shapes are ever produced.Category 1: Fields That Should Reuse the Existing
TemplatableBoolTypeImpact: High — the codebase already solved this problem once and just isn't applying it consistently
Example 1:
WorkflowStep.ContinueOnErrorpkg/workflow/step_types.go:28ContinueOnError any // Can be bool or string expressionContinueOnError *TemplatableBool(the type already defined atpkg/workflow/templatables.go:143for exactly this bool-or-expression pattern)anyin others; unifying removes a class of assertion bugsExample 2:
SafeOutputsConfig.ReportFailureAsIssuepkg/workflow/safe_outputs_config_types.go:109any— comment says "bool, templatable expression string, or[]interface{}categories"pkg/workflow/notify_comment_conclusion_helpers.go:346does a 3-arm type switch (bool/string/[]any); the[]anycategories case is already parsed out separately intoReportFailureAsIssueCategories/ReportFailureAsIssueExcludedCategoriesfields right next to itTemplatableBoolhere tooCategory 2:
anyFields With a Documented, Closed Shape Not Yet Extracted Into a TypeImpact: Medium-High — parser already normalizes to 1-2 concrete types; the field just doesn't say so
Example:
GitHubToolConfig.PrivateToPublicFlowspkg/workflow/tools_types.go:375any— doc says"allow"(string) or[]stringof server IDspkg/workflow/tools_parser.go:394-412normalizes every input shape down to exactlystringor[]stringbefore storing; three consumer files each independently re-derive the shape via type assertion (pkg/workflow/mcp_gateway_config.go:175,pkg/workflow/strict_mode_network_validation.go:182and:203)type PrivateToPublicFlows struct { Allow bool; Servers []string }, set once by the parser instead of re-derived three timesdefaultbranch; a struct makes that impossibleExample:
runnerGuardWorkflowJob.Needs/jobNeeds(needs any) []stringpkg/cli/runner_guard_activation_gate.go:19(field),:168-185(function)any, type-switched overstring/[]any/[]stringUnmarshalYAMLinto[]string, eliminating the runtime switchExample (lower confidence):
normalizeAuditRunInput(input any, ...)/auditArgs.RunIDpkg/cli/mcp_tools_privileged.go:387-388,:400-418nil/string/float64/int/int64, but since these are MCP tool args always decoded from JSON, onlystring/float64are ever actually produced — theint/int64arms are dead for real trafficStringOrNumberwrapper with customUnmarshalJSON, or just narrow the type-switch/document that only 2 arms are reachableCategory 3: Untyped Constants Worth a Named Type
Impact: Medium — semantic clarity, prevents mixing incompatible units
Locations:
pkg/constants/constants.go,pkg/cli/audit_cross_run.goBenefits: makes units explicit at call sites, following a pattern (
time.Duration) the codebase already uses elsewhere in the same fileRefactoring Recommendations
Priority 1: High-Impact Field Consolidation
Recommendation: extract the
TargetRepoSlug/AllowedReposandFooterfield pairs into shared mixins (Clusters 1-2)Steps:
CrossRepoTargetConfig(or extendBaseSafeOutputConfig) withTargetRepoSlug/AllowedReposFooter *stringto the same or an adjacent shared mixinEstimated effort: 3-5 hours combined
Impact: High — touches 148 + 64 reference sites' declaration source, zero behavior change
Priority 2: Reuse
TemplatableBoolConsistentlyRecommendation: replace
WorkflowStep.ContinueOnErrorandSafeOutputsConfig.ReportFailureAsIssuewith*TemplatableBoolSteps:
TemplatableBool's existing accessor methods instead of raw type switchesEstimated effort: 2-3 hours
Impact: High — removes duplicated bool-or-expression parsing logic scattered across consumers
Priority 3: Consolidate
Options/Error-Shape StructsRecommendation: address Clusters 3-6 (
GitHubMCP*Options,AgentAPIProxyTargetConfig/AWFAPITargetConfig,LogsDownloadOptions/StdinLogsOptions,ErrorInfo/CompileValidationError)Estimated effort: 7-9 hours combined
Impact: Medium — mostly boilerplate reduction and removal of manual field-sync code
Priority 4: Named Types for Closed-Shape
anyFields and ConstantsRecommendation: introduce
PrivateToPublicFlows, normalizerunnerGuardWorkflowJob.Needsat unmarshal time, and add semantic types (RunCount,RateThreshold,ByteSize) to the constants called out aboveEstimated effort: 4-6 hours combined
Impact: Medium — compile-time safety at a handful of internal boundaries; low risk since these are gh-aw's own data, not third-party input
Implementation Checklist
TargetRepoSlug/AllowedReposshared mixin (Cluster 1)Footershared mixin (Cluster 2)ContinueOnError/ReportFailureAsIssueanyfields with*TemplatableBoolGitHubMCPCommonOptionsfor the Docker/Remote options pair (Cluster 3)AgentAPIProxyTargetConfig/AWFAPITargetConfig, remove manual copy code (Cluster 4)LogsProcessingOptionsfor the logs download/stdin option pair (Cluster 5)ErrorInfo/CompileValidationErrorafter confirming JSON tag compatibility (Cluster 6)GitHubToolConfig.PrivateToPublicFlowsas a small sum typerunnerGuardWorkflowJob.Needsat unmarshal timeAnalysis Metadata
testdata/, underpkg/)All reactions