ADR-0005: Cargo workspace layout and containerized toolchain
Status
Accepted
Context
The spec mandates a repository layout (cmd/, api/v1alpha1, internal/*,
config/, charts/, trainer/, docs/, examples/, test/e2e) that was
written for Go. The development environment has no host Rust toolchain and
builds inside podman containers; CI uses real toolchains on GitHub runners.
Decision
- One Cargo workspace (
resolver = "3", edition 2024, toolchain pinned inrust-toolchain.toml,Cargo.lockcommitted,--lockedeverywhere). - One crate per architectural seam, mirroring the spec's
internal/*names undercrates/(routed-decision,routed-policy, ...). The cargo dependency graph is the enforcement of the seams:routed-decision,routed-policy,routed-snapshot, androuted-apiare pure and may not depend on tokio, kube client/runtime, axum, hyper, tonic, ort, reqwest, or redis (crates/apiuseskubewith default features off, for the CRD derive macros only). - Binaries live under
cmd/exactly as in the spec.api/v1alpha1maps tocrates/api/src/v1alpha1.trainer/is auvPython project outside the workspace. - Local builds run through
scripts/cargo-in-podman.sh, which builds a toolchain image frombuild/toolchain.Containerfile(officialrust:<pin>-bookwormplus clippy, rustfmt, cargo-deny) and bind-mountstarget/and the cargo registry from the repository so rebuilds are incremental and the VM disk is not consumed. The Makefile exposesCARGO ?=so CI setsCARGO=cargo. scripts/check-hygiene.shasserts that the toolchain pin is identical inrust-toolchain.toml, the Containerfiles, and the CI workflow.- Runtime images are
gcr.io/distroless/cc-debian12:nonrootfor every binary (ADR-0002). Multi-arch images are produced by native runners per architecture and joined with a manifest list; no QEMU emulation. - Build metadata (
version,commit) comes fromcrates/versionwith abuild.rsthat readsROUTED_COMMIT(set by the Makefile and image builds) or git.
Consequences
- Contributors with podman but no Rust can build and test; contributors with a matching host toolchain are not slowed down.
- Adding a dependency to a pure crate fails
make boundary. cargo-denyenforces the license allowlist (Apache-2.0 compatible) and bansopenssl-sys(rustls only).
Alternatives considered
- Fewer, larger crates. Rejected: seams would be comments rather than compile-time facts, and incremental builds would be slower.
- sccache / remote cache. Deferred: a persisted
target/is sufficient. - QEMU multi-arch builds. Rejected: Rust + ONNX Runtime under emulation is too slow and fragile.