[Schema Consistency] 🔍 Schema Consistency Check - Runtime Type Coercion Analysis (2025-11-19) #4307
Closed
Replies: 2 comments 1 reply
-
|
/plan |
Beta Was this translation helpful? Give feedback.
1 reply
-
|
This discussion was automatically closed because it was created by an agentic workflow more than 1 week ago. |
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.
-
🔍 Schema Consistency Check - 2025-11-19
Summary
This analysis reveals critical type validation gaps between what the JSON schema defines and what the runtime actually accepts. While the implementation is safe and user-friendly, external validation tools cannot replicate the runtime's type coercion behavior, creating a disconnect for IDE validation and automated tooling.
Overview
The gh-aw compiler implements graceful type coercion that goes beyond what the JSON schema documents. This makes workflows more forgiving (users can write
timeout: "300"as a string instead oftimeout: 300as a number), but creates validation gaps where:Critical Issues: Type Coercion Not Documented
Critical Issues
1. String-to-Number Coercion Undocumented
Severity: 🔴 Critical - Creates validation gap
Location:
pkg/workflow/metrics.go:253-257(ConvertToInt)pkg/workflow/map_helpers.go:5-18(parseIntValue)Issue: Runtime accepts string representations of numbers and automatically converts them using
strconv.Atoi(), but schema only defines"type": "integer"or"type": "number".Affected Fields:
timeouttimeout: "300"✅ works, ❌ fails schemamaxmax: "20"✅ works, ❌ fails schemamax-turnsmax-turns: "100"✅ works, ❌ fails schemamax-patch-sizemax-patch-size: "1024"✅ works, ❌ fails schemaCode Evidence:
Real-World Impact:
timeout: "300"Recommendation:
"type": ["integer", "string"]with pattern validation2. Silent Float-to-Int Truncation
Severity: 🟡 Moderate - Unexpected behavior
Location:
pkg/workflow/map_helpers.go:13-14Issue: Runtime silently truncates float values to integers without warning or validation.
Code Evidence:
Example:
Runtime behavior:
timeout: 60Recommendation:
# Note: 60.5 → 603. Category Field Type Polymorphism
Severity: 🟡 Moderate - Undocumented flexibility
Location:
pkg/workflow/create_discussion.go:26-32Issue:
categoryfield accepts bothstringandintat runtime, but schema only documentsstring.Code Evidence:
Schema Says:
Recommendation:
"type": ["string", "integer"]to schema4. Version Field Multi-Type Acceptance
Severity: 🟡 Moderate - Undocumented flexibility
Location:
pkg/workflow/runtime_setup.go:507-518Issue:
versionfields acceptstring,int, andfloat64, but schema only documentsstring.Code Evidence:
Examples that work at runtime but fail schema:
Recommendation:
"type": ["string", "number"]Positive Findings: Well-Implemented Patterns
Positive Findings
1. ✅ Polymorphic oneOf Fields (12 fields)
Status: Excellent implementation
Fields with correct oneOf type handling:
on: string | objectpermissions: string | objectruns-on: string | array | objectconcurrency: string | objectenv: object | stringenvironment: string | objectcontainer: string | objectnetwork: string | objectsteps: object | arraypost-steps: object | arraycache: object | arrayroles: string | arrayWhy this is good:
2. ✅ Defensive Type Conversion
Status: Safe implementation
Evidence: All type conversion functions return sensible zero values on failure:
ConvertToInt()→ returns0ConvertToFloat()→ returns0.0parseIntValue()→ returns(0, false)Benefit:
3. ✅ Type Safety Helpers
Status: Well-architected
Reusable functions:
parseIntValue(any) (int, bool)- Safe int parsingConvertToInt(any) int- Flexible int conversionConvertToFloat(any) float64- Flexible float conversionformatYAMLValue(any) string- Type-aware YAML formattingBenefit:
4. ✅ Comprehensive Type Switch Coverage
Status: Thorough implementation
Found 20+ type switch statements across:
safe_outputs.go:341- max count handlingcreate_discussion.go:26- category handlingruntime_setup.go:507- version handlingrole_checks.go:56- roles handlingmcp_servers.go:301- toolsets handlingPattern:
Benefit:
Schema vs Runtime Type Acceptance Matrix
Type Acceptance Comparison
timeoutintegermetrics.go:253maxintegermap_helpers.go:5max-turnsintegermetrics.go:253max-patch-sizeintegersafe_outputs.go:458categorystringcreate_discussion.go:26versionstringruntime_setup.go:507onstring | objectrolesstring | arraypermissionsstring | objectLegend:
Technical Deep Dive
Methodology
Phase 1: Schema Type Analysis
main_workflow_schema.json"type": "integer")"oneOf": [...])Phase 2: Runtime Type Coercion Analysis
ParseInt,ParseFloat,ParseBoolimportsstrconv.*usageswitch v := x.(type))Phase 3: Cross-Reference with Workflows
max: 1(notmax: "1")Phase 4: Gap Identification
Key Code Locations
Type Conversion Helpers
pkg/workflow/map_helpers.go:5-18-parseIntValue()pkg/workflow/metrics.go:245-259-ConvertToInt()pkg/workflow/metrics.go:262-276-ConvertToFloat()Type Switch Patterns
pkg/workflow/safe_outputs.go:341-356- max count (int | float64)pkg/workflow/create_discussion.go:26-32- category (string | int)pkg/workflow/runtime_setup.go:438-482- formatYAMLValue (all types)pkg/workflow/runtime_setup.go:507-519- version (string | int | float64)pkg/workflow/role_checks.go:56-70- roles (string | array)pkg/workflow/mcp_servers.go:301-315- toolsets (array only)Any Type Struct Fields
pkg/workflow/compiler.go:281-Steps []map[string]anypkg/workflow/threat_detection.go:20-Steps []anypkg/workflow/safe_jobs.go:18-RunsOn anypkg/workflow/safe_jobs.go:21-Steps []anypkg/workflow/tools_types.go:80-Custom map[string]anyRecommendations
High Priority (Affecting User Experience)
📝 Document String-to-Number Coercion
timeout: 300andtimeout: "300"🔧 Create Validation Tooling
gh aw validatecommand that uses same type coercion rules as runtime"type": ["integer", "string"])📖 Update Documentation
Medium Priority (Developer Experience)
WARN: timeout value 60.5 truncated to 60✨ Enhance Schema Definitions
categoryto"type": ["string", "integer"]versionfields to"type": ["string", "number"]patternconstraints for string-formatted numbersLow Priority (Long-term Improvements)
🧪 Expand Test Coverage
"1.5e3","+123","0xFF"🛡️ Consider Strict Mode
--strict-typesto reject type coercionsStrategy Performance
Why This Strategy Works
Comparison to Other Strategies
Next Steps
Immediate Actions
gh aw validate)Follow-up Analysis
Conclusion
Runtime is MORE PERMISSIVE than schema - This is excellent for user experience (YAML flexibility) but creates validation gaps for external tooling. The implementation is safe, defensive, and well-architected, but the schema doesn't accurately document the type flexibility.
Key Takeaway: The gap between schema strictness and runtime flexibility is intentional and user-friendly, but needs better documentation to enable external validation tools to replicate runtime behavior.
Success Criteria Met: ✅
Beta Was this translation helpful? Give feedback.
All reactions