A fork of mtelver's day10 project
at main 697 lines 28 kB view raw view rendered
1# Gap Analysis: Replacing ocaml-docs-ci with day10 2 3**Date:** 2026-02-03 4**Purpose:** Comprehensive comparison of `day10` (OHC) and `ocaml-docs-ci` to identify features, gaps, and requirements for replacing ocaml-docs-ci as the documentation CI system for docs.ocaml.org. 5 6--- 7 8## Table of Contents 9 101. [Executive Summary](#executive-summary) 112. [Architecture Overview](#architecture-overview) 123. [Feature Comparison Matrix](#feature-comparison-matrix) 134. [Detailed Gap Analysis](#detailed-gap-analysis) 145. [Ecosystem Integration](#ecosystem-integration) 156. [Implementation Roadmap](#implementation-roadmap) 167. [Risk Assessment](#risk-assessment) 17 18--- 19 20## Executive Summary 21 22### Current State 23 24| Aspect | day10 | ocaml-docs-ci | 25|--------|-------|---------------| 26| **Primary Purpose** | Health checking OPAM packages (build + docs) | CI pipeline for docs.ocaml.org | 27| **Architecture** | Standalone CLI with fork-based parallelism | OCurrent-based reactive pipeline | 28| **Container Runtime** | runc/OCI with overlay2 layers | OCluster (single machine in practice) | 29| **Doc Generation** | Uses odoc_driver_voodoo | Uses voodoo-do + odoc_driver_voodoo | 30| **State Management** | File-based (layer.json) | SQLite database + OCurrent cache | 31| **Scalability** | Single machine, forked workers | Single machine (OCluster theoretical) | 32 33### Key Findings 34 35**Important Context:** While ocaml-docs-ci has OCluster infrastructure for theoretically distributed execution, **in practice it runs on a single machine**. This significantly reduces the gap between the two systems. 36 37**day10 Strengths:** 38- Simpler, more portable architecture (Linux/Windows/FreeBSD) 39- Efficient overlay2-based incremental building 40- Direct container control without orchestration overhead 41- Standalone operation without external services 42- Comparable parallelism model (fork-based vs single-machine OCluster) 43 44**ocaml-docs-ci Strengths:** 45- Production-proven for docs.ocaml.org 46- Reactive pipeline with automatic rebuilding 47- Rich monitoring and status APIs 48- Epoch-based atomic updates 49- Web UI for status visibility 50 51### Migration Complexity: **MODERATE** 52 53Since both systems effectively run on single machines, the gap is smaller than it might appear from the architecture diagrams. The core documentation generation is identical (both use voodoo/odoc_driver_voodoo). The main gaps are in orchestration (reactive vs manual), state management, and deployment infrastructure (epochs). 54 55--- 56 57## Architecture Overview 58 59### day10 Architecture 60 61``` 62┌─────────────────────────────────────────────────────────────┐ 63│ day10 CLI │ 64├─────────────────────────────────────────────────────────────┤ 65│ Commands: health-check | ci | batch | list | sync-docs │ 66└─────────────────────┬───────────────────────────────────────┘ 67 68 ┌────────────┼────────────┐ 69 ▼ ▼ ▼ 70┌─────────────┐ ┌──────────┐ ┌──────────────┐ 71│ Solver │ │ Builder │ │ Doc Gen │ 72│ opam-0install│ │ runc │ │odoc_driver │ 73└─────────────┘ └──────────┘ └──────────────┘ 74 │ │ │ 75 └────────────┼────────────┘ 76 77 ┌────────────────────────┐ 78 │ Overlay2 Layers │ 79 │ (cache_dir/) │ 80 │ ├── base/fs │ 81 │ ├── build-{hash}/ │ 82 │ ├── doc-{hash}/ │ 83 │ └── layer.json │ 84 └────────────────────────┘ 85``` 86 87**Key Characteristics:** 88- Single-machine execution with fork-based parallelism 89- Layer-based caching with overlay2 filesystem 90- Deterministic hash-based layer identification 91- Direct runc container execution 92 93### ocaml-docs-ci Architecture 94 95``` 96┌─────────────────────────────────────────────────────────────┐ 97│ ocaml-docs-ci │ 98│ (OCurrent Pipeline) │ 99├─────────────────────────────────────────────────────────────┤ 100│ Stages: Track → Solve → Prep → Bless → Compile → Publish │ 101└─────────────────────┬───────────────────────────────────────┘ 102103 ┌─────────────────┼─────────────────┐ 104 ▼ ▼ ▼ 105┌─────────┐ ┌───────────┐ ┌──────────────┐ 106│ Solver │ │ OCluster │ │ Storage │ 107│ Service │ │ (Workers) │ │ Server │ 108│(Cap'n P)│ │ │ │ (SSH/rsync) │ 109└─────────┘ └───────────┘ └──────────────┘ 110111 ┌──────────┴──────────┐ 112 ▼ ▼ 113┌─────────────────┐ ┌─────────────────┐ 114│ prep/ │ │ html/ │ 115│ (voodoo-prep) │ │ (HTML output) │ 116└─────────────────┘ └─────────────────┘ 117118119 ┌─────────────────┐ 120 │ docs.ocaml.org │ 121 │ (epoch symlinks)│ 122 └─────────────────┘ 123``` 124 125**Key Characteristics:** 126- OCluster infrastructure (but single-machine in practice) 127- Reactive pipeline (rebuilds on changes) 128- SQLite for state tracking 129- Cap'n Proto for service communication 130- Epoch-based atomic deployments 131 132**Note:** Despite the distributed architecture in the diagram, ocaml-docs-ci currently runs all workers on a single machine, making it comparable to day10's fork-based approach. 133 134--- 135 136## Feature Comparison Matrix 137 138### Core Features 139 140| Feature | day10 | ocaml-docs-ci | Gap Level | 141|---------|-------|---------------|-----------| 142| **Package Building** | ✅ Full | ✅ Full | None | 143| **Documentation Generation** | ✅ odoc_driver_voodoo | ✅ voodoo + odoc_driver | None | 144| **Dependency Solving** | ✅ opam-0install | ✅ opam-0install (service) | Minor | 145| **Multiple OCaml Versions** | ✅ Configurable | ✅ Multiple tracked | None | 146| **Blessing System** | ✅ Implemented | ✅ Implemented | None | 147| **Incremental Building** | ✅ overlay2 layers | ✅ prep caching | Different approach | 148 149### Orchestration & Scheduling 150 151| Feature | day10 | ocaml-docs-ci | Gap Level | 152|---------|-------|---------------|-----------| 153| **Parallelism** | ✅ Fork-based (--fork N) | ✅ OCluster (single machine) | Similar | 154| **Distributed Execution** | ❌ Single machine | ⚠️ Single machine (theory: multi) | None (in practice) | 155| **Reactive Rebuilding** | ❌ Manual trigger | ✅ OCurrent reactive | **MAJOR GAP** | 156| **Job Queuing** | ❌ None | ✅ OCluster scheduler | Minor | 157| **Automatic Change Detection** | ❌ Manual | ✅ Git-based tracking | **MAJOR GAP** | 158 159### State Management 160 161| Feature | day10 | ocaml-docs-ci | Gap Level | 162|---------|-------|---------------|-----------| 163| **Build State Tracking** | ✅ layer.json files | ✅ SQLite database | Different | 164| **Solution Caching** | ✅ Per-commit hash | ✅ Per-commit hash | Similar | 165| **Pipeline History** | ❌ None | ✅ Full history in DB | **MAJOR GAP** | 166| **Package Status Tracking** | ⚠️ Basic (JSON) | ✅ Full (DB + API) | **Moderate** | 167| **Epoch Management** | ❌ None | ✅ Full (atomic updates) | **MAJOR GAP** | 168 169### External Integrations 170 171| Feature | day10 | ocaml-docs-ci | Gap Level | 172|---------|-------|---------------|-----------| 173| **opam-repository Tracking** | ✅ Local path | ✅ Git clone + tracking | Minor | 174| **Storage Backend** | ✅ Local filesystem | ✅ SSH/rsync server | **Moderate** | 175| **Web UI** | ❌ None | ✅ OCurrent web | **MAJOR GAP** | 176| **API for Querying** | ❌ None | ✅ Cap'n Proto API | **MAJOR GAP** | 177| **GitHub Integration** | ❌ None | ✅ Via opam-repo | Minor | 178 179### Output & Publishing 180 181| Feature | day10 | ocaml-docs-ci | Gap Level | 182|---------|-------|---------------|-----------| 183| **HTML Generation** | ✅ Full | ✅ Full | None | 184| **Search Index** | ✅ Via odoc_driver | ✅ Via voodoo-gen | None | 185| **Atomic Deployment** | ❌ None | ✅ Epoch symlinks | **MAJOR GAP** | 186| **Valid Package List** | ❌ None | ✅ Published list | **Moderate** | 187| **Sync to Remote** | ✅ sync-docs command | ✅ rsync integration | Similar | 188 189### Platform Support 190 191| Feature | day10 | ocaml-docs-ci | Gap Level | 192|---------|-------|---------------|-----------| 193| **Linux x86_64** | ✅ | ✅ | None | 194| **Linux arm64** | ✅ | ✅ | None | 195| **Windows** | ✅ containerd | ❌ Linux only | day10 ahead | 196| **FreeBSD** | ✅ | ❌ | day10 ahead | 197| **Multi-arch builds** | ✅ | ✅ | None | 198 199--- 200 201## Detailed Gap Analysis 202 203### 1. CRITICAL GAPS (Must Have) 204 205#### 1.1 Reactive Pipeline / Change Detection 206 207**ocaml-docs-ci has:** 208- OCurrent-based reactive pipeline that automatically rebuilds when inputs change 209- Git-based tracking of opam-repository commits 210- Automatic detection of new/updated packages 211- Dependency-aware rebuilding (if A changes, rebuild dependents) 212 213**day10 lacks:** 214- No automatic change detection 215- Manual triggering required 216- No concept of "pipeline" - just single-shot execution 217 218**Implementation Options:** 2191. **Add OCurrent integration** - Wrap day10 in OCurrent pipeline 2202. **Implement custom watcher** - Poll opam-repo, track changes, trigger builds 2213. **External orchestration** - Use GitHub Actions/Jenkins to trigger day10 222 223**Recommended:** Option 1 or 3. Adding full OCurrent would be significant work but provides the richest feature set. 224 225--- 226 227#### 1.2 ~~Distributed Execution~~ (Not a Real Gap) 228 229**Reality check:** While ocaml-docs-ci has OCluster infrastructure, **it runs on a single machine in practice**. This means: 230 231- Both systems effectively use single-machine parallelism 232- day10's fork-based approach (`--fork N`) is comparable to ocaml-docs-ci's actual operation 233- OCluster adds overhead without providing real distribution benefits in current deployment 234 235**Conclusion:** This is **not a gap** for the migration. day10's existing parallelism model is sufficient. 236 237**Future consideration:** If true distribution becomes needed, day10 could add OCluster support, but this is not required for feature parity with the current production system. 238 239--- 240 241#### 1.3 Epoch-Based Deployment 242 243**ocaml-docs-ci has:** 244- Epoch system for versioned artifact collections 245- Atomic promotion via symlinks (html-current → html-live) 246- Garbage collection of old epochs 247- Safe rollback capability 248 249**day10 lacks:** 250- No epoch concept 251- Direct file output 252- No atomic update mechanism 253 254**Implementation Required:** 255- Add epoch directory management 256- Implement symlink-based promotion 257- Add epoch cleanup/GC functionality 258- Support for `html-current``html-live` workflow 259 260--- 261 262#### 1.4 Web UI & Monitoring 263 264**ocaml-docs-ci has:** 265- OCurrent-based web dashboard 266- Real-time pipeline status 267- Job logs viewable in browser 268- Package-level status tracking 269 270**day10 lacks:** 271- No web interface 272- CLI-only interaction 273- No real-time monitoring 274 275**Implementation Options:** 2761. **Use OCurrent web** - If integrating with OCurrent 2772. **Build custom web UI** - Separate web service reading day10 state 2783. **Static status pages** - Generate HTML status reports 279 280**Recommended:** Option 1 if using OCurrent, otherwise Option 3 for minimal viable monitoring. 281 282--- 283 284#### 1.5 Remote API 285 286**ocaml-docs-ci has:** 287- Cap'n Proto RPC API for querying pipeline state 288- Package status queries 289- Pipeline health checks 290- CLI client (ocaml-docs-ci-client) 291 292**day10 lacks:** 293- No remote API 294- No programmatic access to state 295- Cannot query status without reading files 296 297**Implementation Options:** 2981. **Add Cap'n Proto service** - Match ocaml-docs-ci interface 2992. **REST API** - Simpler but different from existing ecosystem 3003. **GraphQL** - Modern but overkill for this use case 301 302**Recommended:** Option 1 for compatibility with existing tooling. 303 304--- 305 306### 2. MODERATE GAPS (Should Have) 307 308#### 2.1 Database-Backed State 309 310**ocaml-docs-ci:** SQLite database tracking pipeline runs, package statuses, build history 311 312**day10:** File-based state (layer.json, JSON outputs) 313 314**Gap Impact:** Harder to query historical data, no pipeline-level tracking 315 316**Implementation:** Add SQLite or similar for tracking builds over time 317 318--- 319 320#### 2.2 Solver Service Architecture 321 322**ocaml-docs-ci:** External solver service via Cap'n Proto, can run multiple solvers in parallel 323 324**day10:** In-process solving, one solve at a time per fork 325 326**Gap Impact:** Potentially slower for large solve operations 327 328**Implementation:** Could extract solver to service, but current approach works 329 330--- 331 332#### 2.3 Valid Package List Publishing 333 334**ocaml-docs-ci:** Publishes list of successfully-built packages for ocaml.org filtering 335 336**day10:** No concept of valid package list 337 338**Implementation:** Add post-build step to generate/publish valid package manifest 339 340--- 341 342### 3. MINOR GAPS (Nice to Have) 343 344#### 3.1 Storage Server Integration 345 346**ocaml-docs-ci:** SSH/rsync to remote storage server, automatic sync 347 348**day10:** Local filesystem, manual sync-docs command 349 350**Gap Impact:** Requires additional orchestration for remote deployment 351 352--- 353 354#### 3.2 Multiple opam-repository Sources 355 356**ocaml-docs-ci:** Tracks specific git repository with commit history 357 358**day10:** Supports multiple local paths, no git tracking 359 360**Gap Impact:** Cannot automatically detect new packages 361 362--- 363 364### 4. DAY10 ADVANTAGES 365 366Features day10 has that ocaml-docs-ci lacks: 367 368| Feature | Benefit | 369|---------|---------| 370| **Windows Support** | Can build Windows packages | 371| **FreeBSD Support** | Can build BSD packages | 372| **Simpler Deployment** | No cluster infrastructure needed | 373| **Layer-based Caching** | More efficient disk usage with overlay2 | 374| **Standalone Operation** | Works without external services (OCluster, solver-service) | 375| **Direct Container Control** | Lower latency, no scheduler overhead | 376| **Equivalent Parallelism** | Fork-based model matches ocaml-docs-ci's actual single-machine operation | 377| **Simpler Debugging** | No distributed system complexity to troubleshoot | 378 379--- 380 381## Ecosystem Integration 382 383### Voodoo Integration 384 385Both day10 and ocaml-docs-ci use the same documentation toolchain: 386 387``` 388 ┌─────────────────┐ 389 │ voodoo-prep │ 390 │ (artifact prep) │ 391 └────────┬────────┘ 392393 ┌───────────────┴───────────────┐ 394 ▼ ▼ 395 ┌─────────────────┐ ┌─────────────────┐ 396 │ voodoo-do │ │odoc_driver_voodoo│ 397 │ (compile/link) │ │ (all-in-one) │ 398 └────────┬────────┘ └────────┬────────┘ 399 │ │ 400 └───────────────┬───────────────┘ 401402 ┌─────────────────┐ 403 │ voodoo-gen │ 404 │ (HTML output) │ 405 └─────────────────┘ 406``` 407 408**day10 uses:** odoc_driver_voodoo (modern unified approach) 409**ocaml-docs-ci uses:** Both voodoo-do and odoc_driver_voodoo 410 411**Integration Status:** ✅ Compatible - both can produce compatible output 412 413### OCluster Integration (Optional - Not Required for Parity) 414 415**Note:** Since ocaml-docs-ci runs on a single machine in practice, OCluster integration is **not required** for feature parity. day10's existing fork-based parallelism provides equivalent functionality. 416 417``` 418Current ocaml-docs-ci reality: 419┌─────────────────────────────────────────────────────────────┐ 420│ OCluster Scheduler │ 421│ (Single Machine) │ 422└─────────────────────────┬───────────────────────────────────┘ 423424425 ┌───────────┐ 426 │ Worker │ ← All workers on same machine 427 │ (linux- │ 428 │ x86_64) │ 429 └───────────┘ 430``` 431 432**If future scaling is needed**, day10 could add OCluster: 4331. Add `current_ocluster` dependency 4342. Generate OBuilder specs from day10 build commands 4353. Submit jobs via OCluster API 4364. Collect results from worker output 437 438But this is a **future enhancement**, not a migration requirement. 439 440### Solver Service Integration 441 442The solver-service repository provides a standalone solving service: 443 444``` 445┌──────────────┐ Cap'n Proto ┌────────────────┐ 446│ day10 │ ─────────────────── │ solver-service │ 447│ (client) │ solve() │ (server) │ 448└──────────────┘ └────────────────┘ 449``` 450 451**Current day10:** In-process opam-0install 452**Migration option:** Use solver-service for consistency with ecosystem 453 454--- 455 456## Implementation Roadmap 457 458### Phase 1: Core Infrastructure (Weeks 1-4) 459 460**Goal:** Establish foundation for docs.ocaml.org integration 461 462| Task | Priority | Effort | Dependencies | 463|------|----------|--------|--------------| 464| 1.1 Add epoch management | P0 | Medium | None | 465| 1.2 Implement valid package list | P0 | Low | None | 466| 1.3 Add remote storage sync (SSH/rsync) | P0 | Medium | None | 467| 1.4 SQLite state tracking | P1 | Medium | None | 468 469**Deliverable:** day10 can produce epoch-structured output compatible with docs.ocaml.org 470 471### Phase 2: Change Detection (Weeks 5-8) 472 473**Goal:** Automatic rebuilding on opam-repository changes 474 475| Task | Priority | Effort | Dependencies | 476|------|----------|--------|--------------| 477| 2.1 Git-based opam-repo tracking | P0 | Medium | None | 478| 2.2 Change detection algorithm | P0 | High | 2.1 | 479| 2.3 Dependency-aware rebuild | P1 | High | 2.2 | 480| 2.4 Incremental solution updates | P1 | Medium | 2.2 | 481 482**Deliverable:** day10 can detect and rebuild changed packages automatically 483 484### Phase 3: ~~Distributed Execution~~ Skipped 485 486**Not required:** Since ocaml-docs-ci runs on a single machine in practice, day10's existing fork-based parallelism (`--fork N`) provides equivalent functionality. OCluster integration can be added later if true distribution becomes necessary. 487 488**Time saved:** 6 weeks 489 490### Phase 3 (was 4): Monitoring & API (Weeks 9-12) 491 492**Goal:** Production observability and integration 493 494| Task | Priority | Effort | Dependencies | 495|------|----------|--------|--------------| 496| 3.1 Cap'n Proto API service | P1 | High | 1.4 | 497| 3.2 Status query endpoints | P1 | Medium | 3.1 | 498| 3.3 Web dashboard (or static pages) | P2 | Medium | 3.1 | 499| 3.4 Health check endpoints | P2 | Low | 3.1 | 500 501**Note:** API/monitoring is lower priority if day10 runs as a batch job (like ocaml-docs-ci in practice). 502 503**Deliverable:** day10 provides status visibility (at minimum via static pages/JSON) 504 505### Phase 4 (was 5): Migration & Cutover (Weeks 13-16) 506 507**Goal:** Replace ocaml-docs-ci in production 508 509| Task | Priority | Effort | Dependencies | 510|------|----------|--------|--------------| 511| 4.1 Parallel run comparison | P0 | Medium | All above | 512| 4.2 Output compatibility validation | P0 | Medium | 4.1 | 513| 4.3 Gradual traffic shift | P0 | Low | 4.2 | 514| 4.4 Full cutover | P0 | Low | 4.3 | 515| 4.5 ocaml-docs-ci deprecation | P2 | Low | 4.4 | 516 517**Deliverable:** day10 is the production system for docs.ocaml.org 518 519### Revised Timeline Summary 520 521| Phase | Original | Revised | Savings | 522|-------|----------|---------|---------| 523| Core Infrastructure | Weeks 1-4 | Weeks 1-4 | - | 524| Change Detection | Weeks 5-8 | Weeks 5-8 | - | 525| Distributed Execution | Weeks 9-14 | Skipped | 6 weeks | 526| Monitoring & API | Weeks 15-18 | Weeks 9-12 | - | 527| Migration | Weeks 19-22 | Weeks 13-16 | - | 528| **Total** | **22 weeks** | **16 weeks** | **6 weeks** | 529 530--- 531 532## Risk Assessment 533 534### High Risk 535 536| Risk | Probability | Impact | Mitigation | 537|------|-------------|--------|------------| 538| Output format incompatibility | Low | High | Comprehensive comparison testing | 539| Epoch management bugs | Medium | High | Extensive testing, staged rollout | 540 541### Medium Risk 542 543| Risk | Probability | Impact | Mitigation | 544|------|-------------|--------|------------| 545| Performance regression | Medium | Medium | Benchmark early, optimize iteratively | 546| Change detection complexity | Medium | Medium | Start with simple polling approach | 547| State tracking gaps | Medium | Medium | Design carefully, review with team | 548 549### Low Risk 550 551| Risk | Probability | Impact | Mitigation | 552|------|-------------|--------|------------| 553| Voodoo incompatibility | Low | High | Already using same tools | 554| Platform regressions | Low | Low | Existing test coverage | 555| Parallelism issues | Low | Low | Both systems use single-machine model | 556 557**Note:** OCluster integration risk removed since it's not required for parity. 558 559--- 560 561## Recommendations 562 563### Immediate Actions 564 5651. **Validate voodoo compatibility** - Confirm day10 and ocaml-docs-ci produce identical HTML output for the same package 5662. **Design epoch system** - Document epoch structure and promotion workflow 5673. **Prototype change detection** - Simple git-based tracking of opam-repository changes 568 569### Architecture Decision 570 571**Recommended Approach:** Incremental enhancement of day10 572 573Since both systems run on single machines in practice, day10's architecture is actually well-suited for the task. The migration is simpler than the theoretical architecture comparison suggests. 574 575**Key additions needed:** 5761. **Epoch management** - For atomic deployments (similar to ocaml-docs-ci) 5772. **Change detection** - Git-based tracking of opam-repository 5783. **Valid package list** - For ocaml.org integration 5794. **Status reporting** - JSON/static HTML for visibility 580 581**Not needed for parity:** 582- OCluster integration (single-machine in practice) 583- Full OCurrent reactive pipeline (can use simpler cron/polling) 584- Cap'n Proto API (if batch job model is acceptable) 585 586### Simplest Migration Path 587 588Rather than adding OCurrent complexity, consider a simpler operational model: 589 590```bash 591# Cron job or systemd timer 592while true; do 593 git -C /opam-repo pull 594 if [ $(git rev-parse HEAD) != $(cat /state/last-commit) ]; then 595 day10 batch --cache-dir /cache --opam-repository /opam-repo \ 596 --html-output /data/html-current @changed-packages.json 597 # Atomic promotion 598 ln -sfn /data/html-current /data/html-live 599 git rev-parse HEAD > /state/last-commit 600 fi 601 sleep 3600 602done 603``` 604 605This provides: 606- Automatic change detection 607- Incremental rebuilding 608- Atomic deployments 609- No additional infrastructure 610 611### Alternative: OCurrent Wrapper 612 613If reactive behavior and web UI are required, wrap day10 in OCurrent: 614 615```ocaml 616(* Hypothetical OCurrent pipeline using day10 *) 617let pipeline = 618 let packages = track_opam_repo () in 619 let solutions = Current.list_map solve packages in 620 let builds = Current.list_map (day10_build ~config) solutions in 621 let docs = Current.list_map (day10_docs ~config) builds in 622 publish_epoch docs 623``` 624 625This adds complexity but provides OCurrent's monitoring and caching. 626 627--- 628 629## Appendix A: File Structure Comparison 630 631### day10 Output Structure 632 633``` 634cache_dir/ 635├── {os_key}/ 636│ ├── base/fs/ 637│ ├── build-{hash}/ 638│ │ ├── fs/ 639│ │ └── layer.json 640│ └── doc-{hash}/ 641│ ├── fs/ 642│ │ └── html/ 643│ │ ├── p/{pkg}/{ver}/ 644│ │ └── u/{universe}/{pkg}/{ver}/ 645│ └── layer.json 646└── solutions/ 647 └── {repo-sha}/ 648 └── {pkg}.json 649``` 650 651### ocaml-docs-ci Output Structure 652 653``` 654/data/ 655├── prep/ 656│ └── universes/{u}/{pkg}/{ver}/ 657├── compile/ 658│ ├── p/{pkg}/{ver}/ 659│ └── u/{u}/{pkg}/{ver}/ 660├── linked/ 661│ ├── p/{pkg}/{ver}/ 662│ └── u/{u}/{pkg}/{ver}/ 663├── html-raw/ 664│ ├── p/{pkg}/{ver}/ 665│ └── u/{u}/{pkg}/{ver}/ 666└── epoch-{hash}/ 667 └── html/ 668 └── (symlinks to html-raw) 669``` 670 671--- 672 673## Appendix B: Glossary 674 675| Term | Definition | 676|------|------------| 677| **Epoch** | A versioned collection of documentation artifacts, enabling atomic updates | 678| **Blessed** | The canonical/primary documentation version for a package (lives in `p/`) | 679| **Universe** | A specific set of package dependencies, identified by hash | 680| **Layer** | An overlay2 filesystem layer containing build artifacts | 681| **OCluster** | OCaml's distributed build cluster system | 682| **OCurrent** | Reactive CI/CD pipeline framework for OCaml | 683| **voodoo** | Documentation preparation and generation toolchain | 684| **odoc_driver_voodoo** | Unified driver for odoc compilation/linking/generation | 685 686--- 687 688## Appendix C: Related Repositories 689 690| Repository | Purpose | URL | 691|------------|---------|-----| 692| ocaml-docs-ci | Current docs.ocaml.org CI | github.com/ocurrent/ocaml-docs-ci | 693| voodoo | Doc preparation tools | github.com/ocaml-doc/voodoo | 694| ocluster | Distributed build cluster | github.com/ocurrent/ocluster | 695| solver-service | Dependency solving service | github.com/ocurrent/solver-service | 696| odoc | Documentation compiler | github.com/ocaml/odoc | 697