|
| 1 | += Architecture Decision Record: 0009-build-path |
| 2 | +<!-- SPDX-License-Identifier: PMPL-1.0-or-later --> |
| 3 | +<!-- Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk> --> |
| 4 | + |
| 5 | +# 9. Canonical build paths: cargo for dev, Containerfile for ops |
| 6 | + |
| 7 | +Date: 2026-05-14 |
| 8 | + |
| 9 | +## Status |
| 10 | + |
| 11 | +Accepted |
| 12 | + |
| 13 | +## Context |
| 14 | + |
| 15 | +The repo carries four parallel build-environment definitions: |
| 16 | + |
| 17 | +* `flake.nix` + `.guix-channel` / `guix.scm` — reproducible |
| 18 | + builds via Nix and Guix. |
| 19 | +* `Containerfile` — OCI image build, used by ops. |
| 20 | +* `.devcontainer/` — VS Code Dev Container definition. |
| 21 | +* The implicit fifth path is **just cargo** — every Rust contributor |
| 22 | + runs `cargo build` locally without invoking any of the above. |
| 23 | +
|
| 24 | +Nothing is documented as canonical. Each path drifts at its own |
| 25 | +cadence; nothing keeps them in sync. New contributors don't know |
| 26 | +which one is the "right" way to build. |
| 27 | + |
| 28 | +## Decision |
| 29 | + |
| 30 | +Two paths are canonical, the rest are experimental: |
| 31 | + |
| 32 | +* **`cargo build` is canonical for development.** Direct Rust |
| 33 | + toolchain. Fastest iteration loop. The MSRV is pinned |
| 34 | + (`rust-version = "1.85"` per V-L3-K1) so a contributor with |
| 35 | + `rustup` and the right toolchain is fully set up. The |
| 36 | + Justfile wraps this. |
| 37 | +
|
| 38 | +* **`Containerfile` is canonical for ops.** Produces a single |
| 39 | + OCI image suitable for deployment, CI, and reproducible |
| 40 | + release builds. The release workflow (V-L3-L1, #58 / PR #80) |
| 41 | + builds binaries for four targets natively, but |
| 42 | + `Containerfile` is the supported way to *run* verisimiser in |
| 43 | + production. |
| 44 | +
|
| 45 | +`flake.nix`, `guix.scm`, `.guix-channel`, and `.devcontainer/` |
| 46 | +are **experimental**: |
| 47 | + |
| 48 | +* They remain in the tree because they were contributed by |
| 49 | + someone who needed them. |
| 50 | +* They are not maintained by the core team. CI does not exercise |
| 51 | + them. If they drift, the next user fixes them. |
| 52 | +* The README's "Install" section names cargo + Containerfile; |
| 53 | + the experimental paths are listed in a "Other build |
| 54 | + environments" subsection with the same caveat. |
| 55 | +
|
| 56 | +### Alternative considered |
| 57 | + |
| 58 | +Pick exactly one canonical path. Rejected because dev and ops |
| 59 | +have legitimately different cost/benefit: |
| 60 | + |
| 61 | +* For dev: cargo is universally faster than every container |
| 62 | + alternative. Forcing developers through a Containerfile |
| 63 | + build every time wastes hours per week. |
| 64 | +* For ops: a pinned OCI image with reproducible layers is more |
| 65 | + valuable than instructing operators to install rustup. |
| 66 | +
|
| 67 | +### Alternative considered (also rejected) |
| 68 | + |
| 69 | +Delete the experimental paths. Rejected because there's no harm |
| 70 | +in keeping them around — they take no CI time (CI doesn't invoke |
| 71 | +them), and someone has put work into them. Marking them |
| 72 | +experimental is the polite middle. |
| 73 | + |
| 74 | +## Consequences |
| 75 | + |
| 76 | +### Positive |
| 77 | + |
| 78 | +* README's "Install" section now has a single primary answer: |
| 79 | + use cargo for dev, the Containerfile for ops. |
| 80 | +* Contributors don't lose hours picking between four equally |
| 81 | + unmaintained paths. |
| 82 | +* The CI matrix (`rust-ci.yml` with `1.85` + `stable`) tests |
| 83 | + the canonical dev path. The release workflow tests the |
| 84 | + canonical ops path. No CI cycles spent on experimental |
| 85 | + paths. |
| 86 | +* Drift in `flake.nix` etc. is no longer a blocker — the |
| 87 | + experimental tag says "this might be broken; PR welcome". |
| 88 | +
|
| 89 | +### Negative |
| 90 | + |
| 91 | +* Nix and Guix users get a worse experience. They were |
| 92 | + presumably attracted by the presence of those files. If they |
| 93 | + want to keep those paths first-class, they'll need to |
| 94 | + volunteer maintenance. |
| 95 | +* `.devcontainer/` users (VS Code remote-container workflows) |
| 96 | + are also demoted. |
| 97 | +
|
| 98 | +### Neutral |
| 99 | + |
| 100 | +* No file is removed. The experimental files stay in the tree |
| 101 | + and can be re-promoted in a future ADR if a maintainer |
| 102 | + emerges. |
| 103 | +* The Justfile already wraps cargo, so the dev experience is |
| 104 | + unchanged for anyone using `just`. |
| 105 | +
|
| 106 | +## Follow-ups (separate work) |
| 107 | + |
| 108 | +* README "Install" section rewrite — small follow-up PR, not |
| 109 | + part of this ADR. |
| 110 | +
|
| 111 | +## Cross-references |
| 112 | + |
| 113 | +* ADR-0001 — RSR template adoption. |
| 114 | +* V-L3-K1 (#57) / Cargo.toml `rust-version = "1.85"` — pins the |
| 115 | + cargo dev path. |
| 116 | +* V-L3-L1 (#58) — release workflow that builds native binaries |
| 117 | + for four targets. |
| 118 | +* `Containerfile`, `flake.nix`, `guix.scm`, `.devcontainer/` — |
| 119 | + the files this ADR classifies. |
0 commit comments