serialbench 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/benchmark.yml +273 -228
  3. data/.github/workflows/rake.yml +11 -0
  4. data/.github/workflows/windows-debug.yml +171 -0
  5. data/.gitignore +32 -0
  6. data/.rubocop.yml +1 -0
  7. data/.rubocop_todo.yml +274 -0
  8. data/Gemfile +13 -1
  9. data/README.adoc +36 -0
  10. data/data/schemas/result.yml +29 -0
  11. data/docs/PLATFORM_VALIDATION_FIX.md +79 -0
  12. data/docs/SYCK_YAML_FIX.md +91 -0
  13. data/docs/WEBSITE_COMPLETION_PLAN.md +440 -0
  14. data/docs/WINDOWS_LIBXML_FIX.md +136 -0
  15. data/docs/WINDOWS_SETUP.md +122 -0
  16. data/lib/serialbench/benchmark_runner.rb +3 -3
  17. data/lib/serialbench/cli/benchmark_cli.rb +74 -1
  18. data/lib/serialbench/cli/environment_cli.rb +3 -3
  19. data/lib/serialbench/cli/resultset_cli.rb +72 -26
  20. data/lib/serialbench/cli/ruby_build_cli.rb +75 -88
  21. data/lib/serialbench/cli/validate_cli.rb +88 -0
  22. data/lib/serialbench/cli.rb +6 -2
  23. data/lib/serialbench/config_manager.rb +15 -26
  24. data/lib/serialbench/models/benchmark_config.rb +12 -0
  25. data/lib/serialbench/models/benchmark_result.rb +39 -3
  26. data/lib/serialbench/models/environment_config.rb +3 -2
  27. data/lib/serialbench/models/platform.rb +56 -4
  28. data/lib/serialbench/models/result.rb +28 -1
  29. data/lib/serialbench/models/result_set.rb +8 -0
  30. data/lib/serialbench/ruby_build_manager.rb +19 -23
  31. data/lib/serialbench/runners/asdf_runner.rb +1 -1
  32. data/lib/serialbench/runners/docker_runner.rb +2 -4
  33. data/lib/serialbench/runners/local_runner.rb +71 -0
  34. data/lib/serialbench/serializers/base_serializer.rb +1 -1
  35. data/lib/serialbench/serializers/json/rapidjson_serializer.rb +1 -1
  36. data/lib/serialbench/serializers/toml/base_toml_serializer.rb +0 -2
  37. data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +1 -1
  38. data/lib/serialbench/serializers/toml/tomlib_serializer.rb +1 -1
  39. data/lib/serialbench/serializers/xml/libxml_serializer.rb +4 -8
  40. data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +2 -2
  41. data/lib/serialbench/serializers/xml/oga_serializer.rb +4 -8
  42. data/lib/serialbench/serializers/xml/ox_serializer.rb +2 -2
  43. data/lib/serialbench/serializers/xml/rexml_serializer.rb +3 -3
  44. data/lib/serialbench/serializers/yaml/psych_serializer.rb +1 -1
  45. data/lib/serialbench/serializers/yaml/syck_serializer.rb +1 -1
  46. data/lib/serialbench/serializers.rb +2 -2
  47. data/lib/serialbench/site_generator.rb +180 -2
  48. data/lib/serialbench/templates/assets/css/format_based.css +1 -53
  49. data/lib/serialbench/templates/assets/css/themes.css +5 -4
  50. data/lib/serialbench/templates/assets/js/chart_helpers.js +44 -14
  51. data/lib/serialbench/templates/assets/js/dashboard.js +14 -15
  52. data/lib/serialbench/templates/format_based.liquid +480 -252
  53. data/lib/serialbench/version.rb +1 -1
  54. data/lib/serialbench/yaml_validator.rb +36 -0
  55. data/serialbench.gemspec +11 -2
  56. metadata +34 -23
  57. data/.github/workflows/ci.yml +0 -74
  58. data/.github/workflows/docker.yml +0 -272
@@ -0,0 +1,91 @@
1
+ # Syck YAML Constant Fix
2
+
3
+ ## Problem Summary
4
+
5
+ GitHub Actions workflow failed with cryptic error:
6
+ ```
7
+ Error adding run to resultset: undefined method `platform_string' for nil
8
+ ```
9
+
10
+ Root cause: Benchmark results.yaml files were only 2 bytes containing `{}` instead of the expected ~10KB files with complete benchmark data.
11
+
12
+ ## Root Cause Analysis
13
+
14
+ After 4 rounds of progressive fixes, we discovered the Syck gem was overriding the YAML constant, causing Lutaml::Model's `to_yaml` method to produce empty output.
15
+
16
+ ### Fix Timeline
17
+
18
+ 1. **Fix #1 (Commit 53f1799)**: Corrected `memory_usage` → `memory` attribute name
19
+ - Result: Still produced empty `{}` files
20
+
21
+ 2. **Fix #2 (Commit fcd23f2)**: Added key_value blocks to BenchmarkResult models
22
+ - Result: Still produced empty `{}` files
23
+
24
+ 3. **Fix #3 (Commit d8fb78b)**: Added key_value blocks to all remaining models
25
+ - Result: Still produced empty `{}` files
26
+
27
+ 4. **Fix #4 (Commit 69a2bd7)**: **Restored YAML constant to Psych in LocalRunner**
28
+ - Result: ✅ **SUCCESS! 10KB files with complete data**
29
+
30
+ ## The Critical Fix
31
+
32
+ Added to `lib/serialbench/runners/local_runner.rb`:
33
+
34
+ ```ruby
35
+ # Restore YAML to use Psych for output, otherwise lutaml-model's to_yaml
36
+ # will have no output (Syck gem overrides YAML constant)
37
+ Object.const_set(:YAML, Psych)
38
+
39
+ results_file = File.join(result_dir, 'results.yaml')
40
+ results_model.to_file(results_file)
41
+ ```
42
+
43
+ ## Why This Happened
44
+
45
+ - The `_docker_execute` method in `benchmark_cli.rb` already had this fix (lines 151-154)
46
+ - Local testing with `serialbench benchmark _docker_execute` worked fine
47
+ - GHA with `serialbench environment execute` (uses LocalRunner) failed
48
+ - The Syck gem overrides the YAML constant during benchmark execution
49
+ - Without restoring it to Psych, Lutaml::Model serialization produces empty output
50
+
51
+ ## Verification
52
+
53
+ From successful GHA run #51:
54
+
55
+ ```
56
+ File size: 10258 bytes
57
+ ✅ File size OK: 10258 bytes
58
+ ✅ YAML syntax valid
59
+
60
+ ---
61
+ platform:
62
+ platform_string: local-3.4.7
63
+ kind: local
64
+ os: macos
65
+ arch: arm64
66
+ ruby_build_tag: 3.4.7
67
+ metadata:
68
+ benchmark_config_path: config/benchmarks/short.yml
69
+ environment_config_path: config/environments/ci-ruby-3.4.yml
70
+ tags:
71
+ - local
72
+ - macos
73
+ - arm64
74
+ - ruby-3.4
75
+ [...]
76
+ ```
77
+
78
+ ## Impact
79
+
80
+ This fix ensures:
81
+ 1. Benchmark results are properly serialized in all execution contexts
82
+ 2. ResultSet aggregation works correctly
83
+ 3. No more cryptic nil errors
84
+ 4. Complete benchmark data flows through the entire pipeline
85
+
86
+ ## Lessons Learned
87
+
88
+ 1. Always check for gem interference with global constants
89
+ 2. The Syck gem is a known source of YAML constant conflicts
90
+ 3. Test in the same execution context as production (LocalRunner vs DockerRunner behavior differs)
91
+ 4. Even with proper model definitions, external factors can break serialization
@@ -0,0 +1,440 @@
1
+ # SerialBench Website Completion Plan
2
+
3
+ ## Executive Summary
4
+
5
+ This document outlines the plan to complete the SerialBench results website,
6
+ which will display performance benchmarks for Ruby serialization libraries
7
+ across different formats (XML, JSON, YAML, TOML).
8
+
9
+ ## Current State
10
+
11
+ ### Completed Components
12
+
13
+ 1. **Core Infrastructure**
14
+ - Lutaml::Model-based data models for benchmark results
15
+ - CLI interface using Thor for benchmark execution
16
+ - Docker and ASDF runners for multi-environment testing
17
+ - Result storage and aggregation via ResultSet
18
+ - GitHub Actions workflow for weekly automated benchmarks
19
+
20
+ 2. **Website Generation**
21
+ - Liquid templating engine integration
22
+ - Base template structure (base.liquid)
23
+ - Format-based view template (format_based.liquid)
24
+ - CSS styling with theme support
25
+ - JavaScript for Chart.js integration
26
+ - Metadata population from benchmark data
27
+
28
+ 3. **Deployment**
29
+ - GitHub Pages deployment via GitHub Actions
30
+ - Weekly schedule (Sundays at 2 AM UTC)
31
+ - Multi-platform matrix (Ruby 3.1-3.4 × Ubuntu/macOS)
32
+
33
+ ### Current Issues
34
+
35
+ 1. **Limited Visualization Options**
36
+ - Only format-based view available
37
+ - No serializer-focused comparisons
38
+ - Missing historical trend analysis
39
+
40
+ 2. **Incomplete Documentation**
41
+ - Website lacks explanatory text
42
+ - No methodology documentation
43
+ - Missing interpretation guidelines
44
+
45
+ 3. **Limited Interactivity**
46
+ - Static charts only
47
+ - No filtering or search capabilities
48
+ - No download options for raw data
49
+
50
+ ## Proposed Enhancements
51
+
52
+ ### Phase 1: Core Website Functionality (Priority: HIGH)
53
+
54
+ #### 1.1 Multiple View Templates
55
+
56
+ **Objective**: Provide different perspectives on benchmark data
57
+
58
+ **Tasks**:
59
+ - Create `serializer_based.liquid` template
60
+ - Group by serializer instead of format
61
+ - Show cross-format performance for each serializer
62
+ - Useful for comparing Nokogiri vs Ox vs REXML
63
+
64
+ - Create `platform_based.liquid` template
65
+ - Group by Ruby version and OS
66
+ - Show how performance varies across platforms
67
+ - Useful for identifying platform-specific optimizations
68
+
69
+ - Create `historical.liquid` template
70
+ - Time-series visualization
71
+ - Show performance trends over weekly runs
72
+ - Identify improvements or regressions
73
+
74
+ **Implementation**:
75
+ ```ruby
76
+ # In lib/serialbench/site_generator.rb
77
+ def generate_views
78
+ ['format_based', 'serializer_based', 'platform_based',
79
+ 'historical'].each do |view|
80
+ generate_view(view)
81
+ end
82
+ end
83
+ ```
84
+
85
+ **Estimated Effort**: 2-3 days
86
+
87
+ #### 1.2 Navigation and Layout
88
+
89
+ **Objective**: Cohesive multi-page website structure
90
+
91
+ **Tasks**:
92
+ - Update `base.liquid` with:
93
+ - Top navigation menu
94
+ - View switcher tabs
95
+ - Footer with methodology link
96
+ - Responsive mobile layout
97
+
98
+ - Add breadcrumb navigation
99
+ - Add page metadata (titles, descriptions)
100
+
101
+ **Implementation**:
102
+ ```html
103
+ <nav class="main-navigation">
104
+ <ul>
105
+ <li><a href="index.html">Format View</a></li>
106
+ <li><a href="serializer_view.html">Serializer View</a></li>
107
+ <li><a href="platform_view.html">Platform View</a></li>
108
+ <li><a href="historical.html">Trends</a></li>
109
+ <li><a href="methodology.html">Methodology</a></li>
110
+ </ul>
111
+ </nav>
112
+ ```
113
+
114
+ **Estimated Effort**: 1 day
115
+
116
+ #### 1.3 Enhanced Data Tables
117
+
118
+ **Objective**: Sortable, searchable result tables
119
+
120
+ **Tasks**:
121
+ - Integrate DataTables.js or similar library
122
+ - Add sorting by any column
123
+ - Add search/filter functionality
124
+ - Add CSV export option
125
+ - Add copy-to-clipboard for sharing
126
+
127
+ **Implementation**:
128
+ ```javascript
129
+ $('.benchmark-table').DataTable({
130
+ order: [[2, 'asc']], // Sort by i/s descending
131
+ pageLength: 25,
132
+ buttons: ['copy', 'csv', 'excel']
133
+ });
134
+ ```
135
+
136
+ **Estimated Effort**: 1 day
137
+
138
+ ### Phase 2: Documentation and Context (Priority: HIGH)
139
+
140
+ #### 2.1 Methodology Page
141
+
142
+ **Objective**: Explain how benchmarks are conducted
143
+
144
+ **Tasks**:
145
+ - Create `methodology.liquid` template
146
+ - Document:
147
+ - Benchmark environment setup
148
+ - Test data characteristics
149
+ - Measurement methodology
150
+ - Statistical approach
151
+ - Limitations and caveats
152
+
153
+ **Content Structure**:
154
+ ```markdown
155
+ ## Benchmark Methodology
156
+
157
+ ### Environment
158
+ - Ruby versions tested
159
+ - Operating systems
160
+ - Hardware specifications (GitHub Actions runners)
161
+
162
+ ### Test Data
163
+ - Sample size and structure
164
+ - Complexity levels
165
+ - Real-world representativeness
166
+
167
+ ### Measurements
168
+ - Iterations per second (throughput)
169
+ - Memory allocation (bytes)
170
+ - Statistical significance
171
+
172
+ ### Limitations
173
+ - Single-threaded only
174
+ - Memory profiling overhead
175
+ - GitHub Actions runner variability
176
+ ```
177
+
178
+ **Estimated Effort**: 1 day
179
+
180
+ #### 2.2 Interpretation Guide
181
+
182
+ **Objective**: Help users understand results
183
+
184
+ **Tasks**:
185
+ - Add tooltips to charts
186
+ - Add explanatory text to each view
187
+ - Create "How to Read This Chart" sections
188
+ - Add recommendations section
189
+
190
+ **Example**:
191
+ ```html
192
+ <div class="interpretation-guide">
193
+ <h3>Understanding the Results</h3>
194
+ <ul>
195
+ <li><strong>Higher i/s is better</strong>: More iterations per
196
+ second means faster serialization</li>
197
+ <li><strong>Lower memory is better</strong>: Less allocation
198
+ reduces GC pressure</li>
199
+ <li><strong>Trade-offs exist</strong>: Fastest may not be
200
+ most memory-efficient</li>
201
+ </ul>
202
+ </div>
203
+ ```
204
+
205
+ **Estimated Effort**: 0.5 days
206
+
207
+ #### 2.3 Library Information
208
+
209
+ **Objective**: Provide context about each serializer
210
+
211
+ **Tasks**:
212
+ - Add library descriptions
213
+ - Link to official documentation
214
+ - Show gem versions tested
215
+ - List known issues or limitations
216
+
217
+ **Implementation**:
218
+ ```ruby
219
+ SERIALIZER_INFO = {
220
+ 'nokogiri' => {
221
+ description: 'XML parsing using libxml2',
222
+ homepage: 'https://nokogiri.org',
223
+ features: ['XPath', 'CSS selectors', 'SAX parsing'],
224
+ notes: 'Most popular Ruby XML library'
225
+ },
226
+ # ... more serializers
227
+ }
228
+ ```
229
+
230
+ **Estimated Effort**: 1 day
231
+
232
+ ### Phase 3: Advanced Features (Priority: MEDIUM)
233
+
234
+ #### 3.1 Historical Trend Analysis
235
+
236
+ **Objective**: Track performance over time
237
+
238
+ **Tasks**:
239
+ - Store all historical benchmark runs
240
+ - Create time-series database of results
241
+ - Generate trend charts
242
+ - Highlight significant changes
243
+ - Add regression detection
244
+
245
+ **Implementation**:
246
+ ```javascript
247
+ // Chart.js line chart for trends
248
+ const trendChart = new Chart(ctx, {
249
+ type: 'line',
250
+ data: {
251
+ labels: timestamps,
252
+ datasets: [{
253
+ label: 'Nokogiri (parse)',
254
+ data: nokogiriParseResults,
255
+ borderColor: 'rgb(75, 192, 192)'
256
+ }]
257
+ }
258
+ });
259
+ ```
260
+
261
+ **Estimated Effort**: 2 days
262
+
263
+ #### 3.2 Comparison Matrix
264
+
265
+ **Objective**: Side-by-side serializer comparisons
266
+
267
+ **Tasks**:
268
+ - Create comparison view
269
+ - Allow selecting 2-4 serializers
270
+ - Show radar chart of characteristics
271
+ - Highlight strengths/weaknesses
272
+
273
+ **Estimated Effort**: 1-2 days
274
+
275
+ #### 3.3 Custom Benchmark Runs
276
+
277
+ **Objective**: Allow users to run specific benchmarks
278
+
279
+ **Tasks**:
280
+ - Add configuration UI
281
+ - Generate custom benchmark commands
282
+ - Provide Docker commands for local execution
283
+ - Document how to submit results
284
+
285
+ **Note**: This would be documentation only, not actual execution on
286
+ the website
287
+
288
+ **Estimated Effort**: 1 day
289
+
290
+ ### Phase 4: Performance and Polish (Priority: LOW)
291
+
292
+ #### 4.1 Performance Optimization
293
+
294
+ **Tasks**:
295
+ - Minimize JavaScript/CSS
296
+ - Lazy load charts
297
+ - Optimize image assets
298
+ - Add service worker for caching
299
+ - Compress result data
300
+
301
+ **Estimated Effort**: 1 day
302
+
303
+ #### 4.2 Accessibility
304
+
305
+ **Tasks**:
306
+ - Add ARIA labels
307
+ - Ensure keyboard navigation
308
+ - Test with screen readers
309
+ - Add alternative text descriptions of charts
310
+ - Ensure sufficient color contrast
311
+
312
+ **Estimated Effort**: 1 day
313
+
314
+ #### 4.3 Mobile Optimization
315
+
316
+ **Tasks**:
317
+ - Responsive chart sizes
318
+ - Touch-friendly interactions
319
+ - Mobile navigation menu
320
+ - Optimize for smaller screens
321
+
322
+ **Estimated Effort**: 0.5 days
323
+
324
+ ## Implementation Priority
325
+
326
+ ### Immediate (Next Sprint)
327
+
328
+ 1. Create serializer_based.liquid template
329
+ 2. Add methodology page
330
+ 3. Enhance navigation in base.liquid
331
+ 4. Add interpretation guides to existing charts
332
+
333
+ ### Short-term (1-2 Weeks)
334
+
335
+ 1. Implement historical trend tracking
336
+ 2. Add DataTables for sortable results
337
+ 3. Create platform_based view
338
+ 4. Add library information sections
339
+
340
+ ### Medium-term (1 Month)
341
+
342
+ 1. Comparison matrix feature
343
+ 2. Performance optimizations
344
+ 3. Accessibility improvements
345
+ 4. Mobile optimization
346
+
347
+ ### Long-term (Ongoing)
348
+
349
+ 1. Monitor weekly benchmark runs
350
+ 2. Add new serializers as they emerge
351
+ 3. Update methodology as needed
352
+ 4. Community feedback integration
353
+
354
+ ## Technical Requirements
355
+
356
+ ### Dependencies to Add
357
+
358
+ ```ruby
359
+ # Gemfile additions for enhanced website
360
+ gem 'rouge', '~> 4.0' # Syntax highlighting for code examples
361
+ ```
362
+
363
+ ### JavaScript Libraries
364
+
365
+ - Chart.js (already included)
366
+ - DataTables.js (for sortable tables)
367
+ - Lodash (for data manipulation)
368
+
369
+ ### Build Process Updates
370
+
371
+ ```ruby
372
+ # lib/serialbench/site_generator.rb enhancements
373
+ class SiteGenerator
374
+ def generate
375
+ copy_assets
376
+ generate_views
377
+ generate_methodology_page
378
+ generate_index_redirect
379
+ optimize_assets
380
+ end
381
+
382
+ private
383
+
384
+ def generate_views
385
+ %w[format_based serializer_based platform_based
386
+ historical].each do |view|
387
+ generate_view(view)
388
+ end
389
+ end
390
+ end
391
+ ```
392
+
393
+ ## Success Metrics
394
+
395
+ 1. **Functionality**
396
+ - All views generate without errors
397
+ - Charts render correctly in all major browsers
398
+ - Mobile experience is usable
399
+
400
+ 2. **Usability**
401
+ - Users can find information in < 3 clicks
402
+ - Charts are self-explanatory
403
+ - Methodology is clear and comprehensive
404
+
405
+ 3. **Performance**
406
+ - Page load < 2 seconds
407
+ - Time to interactive < 3 seconds
408
+ - Lighthouse score > 90
409
+
410
+ 4. **Accessibility**
411
+ - WCAG 2.1 Level AA compliance
412
+ - Screen reader compatible
413
+ - Keyboard navigation functional
414
+
415
+ ## Risk Mitigation
416
+
417
+ 1. **Data Volume Growth**
418
+ - Risk: Historical data grows unbounded
419
+ - Mitigation: Implement data retention policy (e.g., keep 52 weeks)
420
+
421
+ 2. **GitHub Pages Limits**
422
+ - Risk: Site exceeds 1GB limit
423
+ - Mitigation: Compress data, archive old results
424
+
425
+ 3. **Breaking Changes**
426
+ - Risk: Lutaml::Model API changes
427
+ - Mitigation: Pin versions, test before updates
428
+
429
+ 4. **Runner Variability**
430
+ - Risk: Inconsistent benchmark results
431
+ - Mitigation: Document variance, run multiple times, use statistics
432
+
433
+ ## Conclusion
434
+
435
+ This plan provides a structured approach to completing the SerialBench
436
+ results website. The phased approach allows for incremental delivery
437
+ of value while maintaining quality and usability standards.
438
+
439
+ **Next Immediate Action**: Push changes and verify GitHub Actions
440
+ workflow executes successfully.
@@ -0,0 +1,136 @@
1
+ # Windows libxml2 Installation Fix
2
+
3
+ ## Issue
4
+
5
+ The `libxml-ruby` gem was failing to install on Windows in GitHub Actions for Ruby 3.1 and 3.4 due to missing native libxml2 libraries.
6
+
7
+ **Error:**
8
+ ```
9
+ extconf failure: Cannot find libxml2.
10
+ Install the library or try one of the following options to extconf.rb:
11
+ --with-xml2-config=/path/to/xml2-config
12
+ --with-xml2-dir=/path/to/libxml2
13
+ ```
14
+
15
+ **Root Cause:**
16
+ The `libxml-ruby` gem requires native C libraries (libxml2) that are not available by default on Windows. The gem's native extension compilation fails because:
17
+ 1. libxml2 development headers are not found
18
+ 2. libxml2 shared libraries are not in the system path
19
+ 3. pkg-config cannot locate the libxml2 package
20
+
21
+ ## Solution
22
+
23
+ ### Approach
24
+
25
+ Instead of excluding `libxml-ruby` from Windows builds, we install the required native libraries using Chocolatey package manager, which is pre-installed on GitHub Actions Windows runners.
26
+
27
+ ### Implementation
28
+
29
+ #### 1. New GitHub Actions Workflow (`.github/workflows/windows-setup.yml`)
30
+
31
+ Created a dedicated Windows workflow that:
32
+ - Installs libxml2 via Chocolatey before Ruby setup
33
+ - Dynamically locates the libxml2 installation directory
34
+ - Configures environment variables (PKG_CONFIG_PATH, PATH)
35
+ - Passes library paths to bundler for gem compilation
36
+ - Runs tests to verify the setup
37
+
38
+ Key features:
39
+ - **Dynamic path detection**: Uses PowerShell to find the actual libxml2 installation directory
40
+ - **Robust configuration**: Sets multiple environment variables to ensure gem compilation succeeds
41
+ - **Bundler configuration**: Explicitly passes include and lib paths to the gem build process
42
+
43
+ #### 2. Documentation (`docs/WINDOWS_SETUP.md`)
44
+
45
+ Comprehensive guide covering:
46
+ - Problem explanation
47
+ - Multiple installation options (Chocolatey, vcpkg)
48
+ - Step-by-step setup instructions
49
+ - Environment variable configuration
50
+ - Troubleshooting common issues
51
+ - CI/CD integration
52
+
53
+ ## Technical Details
54
+
55
+ ### Chocolatey Package
56
+
57
+ The libxml2 Chocolatey package installs to:
58
+ ```
59
+ C:\ProgramData\chocolatey\lib\libxml2\tools\libxml2-{version}-win32-x86_64\
60
+ ```
61
+
62
+ Required components:
63
+ - `bin/` - DLL files (libxml2.dll, etc.)
64
+ - `include/libxml2/` - Header files for compilation
65
+ - `lib/` - Link libraries and pkg-config files
66
+ - `lib/pkgconfig/` - libxml-2.0.pc file
67
+
68
+ ### Environment Variables
69
+
70
+ The workflow sets:
71
+ - `PKG_CONFIG_PATH`: Points to the pkgconfig directory
72
+ - `PATH`: Includes the bin directory for DLLs
73
+ - `LIBXML2_INCLUDE`: Header file location for gem compilation
74
+ - `LIBXML2_LIB`: Library file location for gem compilation
75
+
76
+ ### Bundler Configuration
77
+
78
+ ```powershell
79
+ bundle config build.libxml-ruby "--with-xml2-include=<path> --with-xml2-lib=<path>"
80
+ ```
81
+
82
+ This passes the library locations directly to the gem's extconf.rb during native extension compilation.
83
+
84
+ ## Testing
85
+
86
+ The fix can be tested by:
87
+
88
+ 1. **Local Windows testing:**
89
+ ```powershell
90
+ choco install libxml2
91
+ choco install pkgconfiglite
92
+ bundle install
93
+ bundle exec rake spec
94
+ ```
95
+
96
+ 2. **GitHub Actions:**
97
+ - Push changes to trigger the `windows-setup` workflow
98
+ - Verify both Ruby 3.1 and 3.4 builds succeed
99
+ - Check that libxml-ruby tests pass
100
+
101
+ ## Benefits
102
+
103
+ 1. **Complete testing**: Windows builds now test libxml-ruby serializer
104
+ 2. **No platform exclusions**: Maintains consistency across all platforms
105
+ 3. **Automated setup**: CI/CD handles installation automatically
106
+ 4. **Documented process**: Clear guidance for local development
107
+
108
+ ## Alternative Approaches Considered
109
+
110
+ ### 1. Platform-conditional dependency (rejected)
111
+ ```ruby
112
+ spec.add_dependency 'libxml-ruby' unless Gem.win_platform?
113
+ ```
114
+ **Pros:** Simple, no setup required
115
+ **Cons:** Reduces test coverage, inconsistent behavior across platforms
116
+
117
+ ### 2. Pre-built binary gems (not available)
118
+ The libxml-ruby gem doesn't provide pre-built Windows binaries, requiring source compilation.
119
+
120
+ ### 3. WSL-only testing (rejected)
121
+ **Pros:** Linux-like environment
122
+ **Cons:** Doesn't test native Windows Ruby installations
123
+
124
+ ## Future Considerations
125
+
126
+ 1. **Caching**: Consider caching the Chocolatey packages to speed up CI runs
127
+ 2. **Version pinning**: May want to pin libxml2 version for reproducibility
128
+ 3. **Alternative packages**: Monitor for official pre-built binaries
129
+ 4. **Ruby 3.2/3.3**: Extend testing to additional Ruby versions if needed
130
+
131
+ ## References
132
+
133
+ - GitHub Actions issue: https://github.com/metanorma/serialbench/actions/runs/18628094589
134
+ - libxml-ruby gem: https://github.com/xml4r/libxml-ruby
135
+ - Chocolatey libxml2 package: https://community.chocolatey.org/packages/libxml2
136
+ - Windows setup documentation: `docs/WINDOWS_SETUP.md`