New .gitea/workflows/website.yaml: on a push to main or website that
touches website/**, build the Astro site with pnpm and deploy
website/dist to the `relplay` Cloudflare Pages project via wrangler —
--branch selects production (main) vs preview (website). Runs on the
bare ci-public runner (node present; pnpm via corepack). Pin pnpm with
package.json's packageManager for deterministic corepack installs.
Requires repo Actions secrets CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID.
The macOS release leg: workflow_dispatch (tag input) on the Tart runner —
test → build both *-apple-darwin targets → rewrite nix libiconv to /usr/lib
+ ad-hoc re-sign → upload binary + .sha256 to the tagged release (idempotent
create-or-get) → prune the nix store by generation. Composed entirely of
parts the smoke-test proved green, so the smoke-test is removed.
Dispatch-only fits the intermittent runner and keeps the 4-target Linux/
Windows release independent. Becomes triggerable once CI is on the default
branch (workflow_dispatch is default-branch-only in Gitea).
- Add `cargo test` before the darwin builds (gate is Linux-only; the macOS
leg is test-then-build) — a full dry-run of release-macos bar the upload.
- Add an `if: always()` prune step. The runner wipes the workspace each run,
so cargo target/ never accumulates (no sweep). The persistent cache is the
nix store: record the current toolchain in a persistent profile, keep the
2 newest generations (nix-env --delete-generations +2), reclaim the rest
(nix-collect-garbage). Pairs with min-free/max-free in the runner nix.conf.
libiconv is the only /nix/store dep the darwin stdenv bakes in (everything
else is system frameworks + libSystem/libobjc). The smoke-test now rewrites
that load path to /usr/lib/libiconv.2.dylib (ABI-compatible, present on
every Mac), re-signs ad-hoc (install_name_tool breaks the sig; arm64
requires a valid one), then verifies no /nix/store paths remain, the
signature is valid, and the native binary launches. Flake comment updated
to reflect the propagated-libiconv reality.
The smoke-test caught the aarch64 binary linking a /nix/store libiconv.dylib
— non-portable (won't exist on a user's Mac). The Apple SDK already provides
a system libiconv stub, so removing pkgs.libiconv makes the linker resolve
-liconv to /usr/lib instead. The smoke-test now fails if any /nix/store dylib
is linked.
Add the two *-apple-darwin targets to rust-toolchain.toml and apple-sdk +
libiconv to the flake devShell (darwin only) so the nix toolchain links
AppKit; make cargo-zigbuild/zig Linux-only (macOS builds natively). Repoint
the throwaway macOS workflow to actually build both darwin targets through
the flake on the Tart runner — the first real check of the macOS leg, which
can't be verified locally. Delete once release-macos lands.
In act_runner a label is `<name>:<backend>`; `:host` is the execution-
backend schema (run on host, no container), not part of the label. The
runner registered as `macos:host` therefore has the label `macos`, which
is what runs-on must reference.
Gitea only exposes workflow_dispatch for workflows on the default branch
(main); our CI is on `ci`, so the manual-run button/API isn't available.
Add a push trigger (filtered to the probe file) so we can drive the macOS
runner test from the ci branch. workflow_dispatch kept for post-merge.
Manual-dispatch probe on runs-on macos:host to confirm the runner picks up
jobs and report arch / macOS version / Xcode SDK / toolchains (nix, rustup,
cargo) / git+node, before wiring the macOS release leg. Delete once done.
release.yaml becomes test (once, host) -> build (matrix) over the four
cargo-zigbuild targets; each matrix job uploads its binary + .sha256 to
the shared release (idempotent create-or-get). Records the expansion in
ADR-ci-001 (2026-06-13 amendment); macOS stays deferred.
Add paths-ignore (docs/**, **/*.md) to the gate's push + pull_request
triggers so markdown/docs-only changes don't run a full clippy+test that
can't change the outcome. Mixed code+docs pushes still gate (not all
files are ignored); flake/toolchain changes are deliberately not ignored.
Also refresh a stale ADR-0049 -> ADR-ci-002 comment reference.
- Run cargo test before the build so a tag never publishes untested code.
- Pin shell: bash on the scripted steps; the runner defaults to dash,
which rejected `set -o pipefail` and failed run 22's package step.
- Swap `file` (absent in the slim image) for `ls -l`.
Tag pushes ignore paths: filters, so a release tag spuriously rebuilt
the unchanged CI image and re-ran the gate on a commit the branch push
already gated. Add branches: ['**'] to both push triggers — tag pushes
no longer fire them (release.yaml owns tags). Pushing commits + a tag
together still gates the commits via the branch push.
On a v* tag, builds the x86_64-unknown-linux-musl binary in the CI image
and publishes it (+ .sha256) to a Gitea release via the API and the
auto GITEA_TOKEN. x86_64 Linux only for now; rest of the D1 matrix and
D3 packaging layer on later. Correctness comes from the branch gate.
Job-container image the gate runs in. node:22-bookworm-slim satisfies
the act_runner contract (sleep/bash/node) far more cheaply than the
catthehacker images; single-user nix installed on top (pre-create /nix
+ empty build-users-group so it installs as root in a container) with
the flake's devShell pre-warmed — CI enters a ready 1.95.0 toolchain in
~1.4s. Verified by local build. ~5.5GB (rust toolchain closure); dep/
target caching is a noted follow-up.
Diagnostic to determine how the ci-public runner executes jobs and
where the nix toolchain is reachable (host vs default container vs a
custom container:), so the real gate is built on facts. Delete once
the gate lands.