Files
rdbms-playground/docs/ci/adr
claude@clouddev1 aeb92f56a7
ci / gate (push) Successful in 3m23s
docs(ci): record macOS implementation in ADR-ci-003 (D1 complete)
macOS is no longer deferred — built natively on a Tart (Apple-Silicon)
runner (real hardware → licensed SDK, no grey area). Amendment documents
release-macos.yaml (dispatch-only, needs main), the libiconv de-nix +
ad-hoc re-sign, the runner-label `:host` backend nuance, generation-based
cache pruning, and D2-on-macOS (system libs only). All six D1 targets now
produce artifacts. Updates the deferred list + index entry.
2026-06-15 15:56:38 +00:00
..

CI / Build Architecture Decision Records

Decision records for the continuous-integration + release pipeline subproject — the Gitea Actions workflows under .gitea/, the nix CI image, and the release tooling. These are kept in their own namespace, separate from the project-wide ADRs in docs/adr/, so CI decisions never compete with the main global ADR sequence for numbers — the same split the website subproject uses (docs/website/adr/, on the website branch), and for the same reason (see ADR-0000 "Numbering discipline").

Numbering. Files are named <date>-adr-ci-<NNN>.md and referenced in prose as ADR-ci-NNN. The <date> (the ADR's accepted/created day, YYYYMMDD) plus the ci segment keeps the namespace disjoint from main's integers. Assign the next free NNN from this index. Every ADR change updates this index in the same edit (the ADR-0000 index-upkeep rule applies here too).

Index

  • ADR-ci-001 — CI + release pipeline on Gitea ActionsAccepted 2026-06-12 (implemented the same day on the ci branch). Establishes the CI/release pipeline on the self-hosted Gitea instance's Actions runner (ci-public). Runner model (established by a throwaway probe): jobs execute inside a container (catthehacker/ubuntu:act-22.04 by default), as root, so the runner host's nix is not reachable from steps. Toolchain delivery: a baked CI imagenode:22-bookworm-slim (satisfies the act_runner job-container contract: /bin/sleep keep-alive, bash, node for JS actions; a bare nixos/nix image lacks these and won't start) + single-user nix + the flake's devShell pre-warmed — built by build-ci-image.yaml via DinD and pushed to the Gitea container registry as a public package, so CI runs nix develop -c … against the same pinned toolchain as dev (the flake, ADR-ci-002) with a warm store (~1.4 s to a ready toolchain). Gate (ci.yaml): clippy -D warnings + cargo test inside that image on branch pushes + PRs; fmt deliberately not gated (the tree isn't stock-rustfmt-clean — user decision, revisit on main; see ADR-ci-002). Release (release.yaml): on a v* tag, runs the tests, builds the static x86_64-unknown-linux-musl binary (D2: single static binary, no runtime deps — the glibc/nix build is non-portable), strips it, and publishes it + a .sha256 to a Gitea release via the API and the auto-provided GITEA_TOKEN. Triggers: gate + image-build are scoped to branch pushes (branches: ['**']) so a release tag doesn't spuriously re-run them; the image-build additionally path-filters to its inputs (Dockerfile/flake/toolchain); the release owns tags. Auth: a dedicated PAT (REGISTRY_USERNAME/REGISTRY_TOKEN secrets) pushes the image; the auto GITEA_TOKEN publishes releases. Scope: the original release job was Linux x86_64 only; it's now the four non-macOS D1 targets (Linux + Windows × x86_64/aarch64) cross-built via cargo-zigbuild — see ADR-ci-003. macOS, D3 package-manager manifests, CI-speed dependency caching, and the website's static→Cloudflare deploy remain deferred, added step by step. Verified live: probe → runner facts; image built + checked locally; gate green (2424 tests); release exercised end-to-end (v0.0.0-citest2 published with binary + checksum). Builds on ADR-ci-002 (the nix flake, relocated here from main's ADR-0049 to avoid exactly this cross-branch collision).
  • ADR-ci-002 — Nix flake for a reproducible dev + build environmentAccepted 2026-06-12 (relocated from main's ADR-0049 on the same day — content unchanged — to keep CI/dev-env decisions out of main's integer sequence). The single, version-pinned declaration of the dev and build toolchain so CI never relies on whatever Rust is on the build machine — mirroring datamage ADR 0046, but far simpler (pure-Rust TUI). Root Nix flake with two outputs: devShells.default (pinned Rust 1.95.0 via rust-toolchain.toml + rust-overlay, cargo-sweep, and the musl cc for the static release build) and packages.default (rustPlatform.buildRustPackage from the committed Cargo.lock; doCheck = false). Exact-pin (not floating stable) so nix flake update can't surprise-bump clippy past the -D warnings gate. System inputs near-empty by design (libsqlite3-sys bundled → stdenv cc only; arboardx11rb pure-Rust). .envrc (use flake) for direnv parity. Verified through the flake: nix build yields a working binary, clippy clean, 2424 tests pass / 0 fail / 1 intentional ignored doctest. Consumed by ADR-ci-001 (the pipeline). Alternatives rejected: dev-shell-only; a standard rust:1.95 CI image (a second toolchain definition = drift); rustup on the build host (non-reproducible).
  • ADR-ci-003 — Cross-platform release builds (the D1 matrix)Accepted 2026-06-13 (implemented + a real matrix release verified the same day — tag v.0.0.0-citest3 published 8 assets). Cross-compiles the four non-macOS D1 targets from the Linux x86_64 runner with cargo-zigbuild (Zig's bundled clang + libc as one universal cross cc/linker, incl. rusqlite's bundled SQLite C; added to the flake devShell, replacing the single-target musl cc): x86_64/aarch64-unknown-linux-musl (musl + crt-static → fully static, D2) and x86_64-pc-windows-gnu / aarch64-pc-windows-gnullvm (Zig statically links libc → standalone .exe). Windows synchronization stub: Rust std links -lsynchronization (WaitOnAddress thread-parking), an import lib rust-overlay's toolchain doesn't ship and Zig's mingw lacks; the symbols are forwarded by kernel32, so an empty 8-byte stub libsynchronization.a (ci/winstub/, wired via .cargo/config.toml for the Windows targets only) satisfies the linker. Workflow: release.yaml = test once (host) → build matrix over the four targets (needs: test, fail-fast: false); each job packages binary (.exe for Windows) + .sha256 and uploads to the shared release via idempotent create-or-get. macOS (2026-06-14 amendment) — built natively on a Tart (Apple-Silicon) runner (runs-on: macos), which makes the SDK fully licensed and dissolves the grey-area/public-image problem; release-macos.yaml is dispatch-only (intermittent runner; becomes triggerable once CI is on main), de-nixes the binary's libiconv load path (install_name_tool/usr/lib) + re-signs ad-hoc, and uploads to the tagged release. D1 complete (all six targets). Alternatives rejected: cross (no macOS, needs DinD), per-target nix cross (Windows-aarch64 unpackaged, macOS-from-Linux unsupported), a real libsynchronization.a (more machinery, doesn't cover Windows-aarch64). Runtime-verified by the user (2026-06-13): Linux x86_64 + Windows aarch64 run correctly; Linux aarch64 + Windows x86_64 are the outstanding runtime checks. Builds on ADR-ci-002 (flake) and fills in ADR-ci-001 §3 (Release).