L17: receiverHosted lift (fix the amd64 ReleaseSafe SEGV before merge) #264
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| # Rapid pushes to a branch (or PR) supersede in-flight runs: cancel the older | |
| # run so the 11-job matrix does not pile up and starve runners. | |
| # | |
| # KNOWN FAILURE MODE (2026-07-30): a run cancelled here can still execute | |
| # setup-zig's post step and save a PARTIAL `.zig-cache`. Because restores are | |
| # prefix-matched, the next run inherits it, and Zig then hits a manifest that | |
| # claims a cached artifact which is not in the tarball: | |
| # error: lld-link: could not open '.zig-cache\o\<hash>\compiler_rt.lib' | |
| # Worse, that run saves its own poisoned cache, so the failure self-perpetuates | |
| # across re-runs and later pushes — a re-run alone never clears it. | |
| # REMEDY: delete the entries and let the next run rebuild clean, e.g. | |
| # gh cache list --json id,key | ... | gh cache delete <id> | |
| # (Windows hit this first because it links compiler_rt.lib explicitly; nothing | |
| # in the repo's own code was involved.) | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| test: | |
| name: Test (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| # A hung test binary must fail the job, not burn a runner for the | |
| # 6-hour default. | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| # capnp gates ten serialization/codegen suites, which skip when it is | |
| # missing. Installing it on Linux only meant 26 tests silently skipped on | |
| # macOS and 29 on Windows while docs/stability.md advertised codegen as | |
| # "full" on all three tiers. Linux and macOS now both have it; see the | |
| # Windows note below for why that tier does not. | |
| - name: Install Cap'n Proto compiler (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| if command -v sudo >/dev/null 2>&1; then | |
| sudo apt-get update | |
| sudo apt-get install -y capnproto libcapnp-dev | |
| else | |
| apt-get update | |
| apt-get install -y capnproto libcapnp-dev | |
| fi | |
| - name: Install Cap'n Proto compiler (macOS) | |
| if: runner.os == 'macOS' | |
| run: brew install capnp | |
| # NOT installed on Windows, deliberately. Installing it there (upstream's | |
| # prebuilt tools from the C++ release archive) makes the suites run and | |
| # then FAIL: two of them compile schemas that use an absolute standard | |
| # import (`import "/capnp/stream.capnp"`), which capnp resolves from its | |
| # standard include tree. The Linux apt package ships that tree; the | |
| # Windows archive ships only the .exe files, so those imports cannot | |
| # resolve. Fixing it needs an `-I` include path threaded through ~10 test | |
| # files that currently hardcode their argv — real work, tracked as a known | |
| # gap in docs/stability.md rather than papered over. Windows codegen | |
| # coverage is therefore genuinely absent, not merely unmeasured. | |
| # Turn a missing tool into a hard job failure instead of ~10 test files | |
| # quietly returning SkipZigTest and the suite reporting green. This step | |
| # is the assertion; tests/hardening/toolchain_gate_test.zig covers | |
| # committed fixtures but cannot read the environment to check the tool. | |
| - name: Verify the toolchain the tests depend on is present | |
| if: runner.os != 'Windows' | |
| shell: bash | |
| run: capnp --version | |
| - name: Run tests | |
| timeout-minutes: 20 | |
| run: zig build test --summary all | |
| - name: Check compilation | |
| run: zig build check | |
| - name: API snapshot check | |
| # On every OS: the snapshot is target-stable by construction and | |
| # this is the gate that keeps it that way. | |
| run: zig build check-api --summary all | |
| - name: Stable-surface closure check | |
| # A frozen entry point whose signature mentions an Experimental type is | |
| # only nominally frozen. This fails when one does. | |
| run: zig build api-closure --summary all | |
| - name: Vendor RPC schema sync (check-rpc) | |
| if: runner.os == 'Linux' | |
| run: just src/rpc/check-rpc | |
| - name: Generated-artifact drift check | |
| # Linux only (needs the capnp CLI). Regenerates every committed | |
| # generated file + the API snapshot and fails if any drifted — the | |
| # class of bug that turned this workflow red mid-sprint more than once. | |
| if: runner.os == 'Linux' | |
| run: just check-generated | |
| - name: Soak smoke (2s, loopback TCP) | |
| run: zig build soak -- --seconds 2 | |
| - name: Self-interop e2e (zig client vs zig server, loopback) | |
| run: zig build e2e-self --summary all | |
| - name: RPC ping-pong example (guards the connection teardown seam) | |
| run: zig build example-rpc | |
| fmt-check: | |
| name: Format check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| - name: Check formatting | |
| run: just fmt-check | |
| evented-check: | |
| name: Evented backend check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| # This job used to run `zig build -Dio-backend=evented check`, which | |
| # verified nothing that plain `zig build check` did not already. | |
| # `-Dio-backend` is a `[]const u8` compared at RUNTIME by | |
| # `io_backend.parseKind`, so all three arms of `Backend.init` are | |
| # semantically analysed in EVERY configuration. Proven by ablation: | |
| # breaking the `.evented` arm turns plain `zig build check` red with no | |
| # flag passed at all. | |
| # | |
| # What was missing was any lane that EXECUTES a selector. `.threaded` is | |
| # the one that can actually carry RPC today — `std.Io.Evented` has no | |
| # working socket vtable upstream at the pinned toolchain (see | |
| # docs/stability.md), so an evented execution lane is not yet possible. | |
| # Ablation for this one: making `parseKind("threaded")` return null leaves | |
| # the old compile check green and turns this lane red. | |
| - name: Execute the RPC e2e over the threaded Io selector | |
| run: zig build -Dio-backend=threaded e2e-self --summary all | |
| # Kept as a cross-check that the evented selector still *builds* where Zig | |
| # exposes it. Cheap, and it documents the intent of the -Dio-backend | |
| # surface even though `check` subsumes it. | |
| - name: Check evented backend compilation | |
| run: zig build -Dio-backend=evented check --summary all | |
| quic-transport: | |
| name: QUIC baseline/native transport | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| # Package store cached separately from setup-zig's per-run cache; the | |
| # key is shared with nightly.yml's extended-gates job so nightly QUIC | |
| # runs inherit a warm cache from per-push CI. | |
| - name: Restore Zig package cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: .zig-cache/p | |
| key: zig-packages-${{ runner.os }}-${{ hashFiles('build.zig.zon') }} | |
| - name: Prefetch dependency tree | |
| # Retries transient upstream failures (googlesource.com 503s) so the | |
| # QUIC lane only fails on real regressions. | |
| run: | | |
| for attempt in 1 2 3; do | |
| if zig build --fetch=all; then | |
| exit 0 | |
| fi | |
| echo "::warning::dependency fetch attempt ${attempt} failed" | |
| if [ "$attempt" -lt 3 ]; then | |
| sleep $((attempt * 20)) | |
| fi | |
| done | |
| echo "dependency fetch failed after 3 attempts" | |
| exit 1 | |
| - name: Build QUIC-enabled targets | |
| run: zig build -Dquic=true --summary all | |
| - name: Check QUIC-enabled build graph | |
| run: zig build -Dquic=true check --summary all | |
| - name: Run QUIC baseline/native transport tests | |
| run: zig build -Dquic=true test-rpc-quic --summary all | |
| - name: Compile QUIC documentation snippet fixtures | |
| run: zig build -Dquic=true test-docs-snippets-quic --summary all | |
| docs-smoke: | |
| name: Docs smoke and snippets | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| - name: Compile documentation snippet fixtures | |
| run: zig build test-docs-snippets --summary all | |
| - name: Run documentation/examples smoke gate | |
| run: zig build docs-smoke --summary all | |
| - name: Check public API snapshot | |
| run: zig build check-api --summary all | |
| cross-targets: | |
| name: Cross-target compile (${{ matrix.target }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: | |
| - aarch64-linux-gnu | |
| - x86-linux-gnu # 32-bit | |
| - powerpc64-linux-gnu # big-endian | |
| - x86_64-windows # catches Windows rot without a Windows runner | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| - name: Compile-only check for ${{ matrix.target }} | |
| run: zig build check-compile -Dtarget=${{ matrix.target }} --summary all | |
| - name: Compile test suite for ${{ matrix.target }} | |
| # Windows-only: the native Test (windows) job runs the suite for | |
| # real; this step exists so test compile breakage for Windows is | |
| # caught even by contributors without Windows machines. | |
| if: matrix.target == 'x86_64-windows' | |
| run: zig build check-test-compile -Dtarget=${{ matrix.target }} --summary all | |
| hardening: | |
| name: Hardening gate (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| - name: Run hardening gate | |
| run: zig build hardening | |
| - name: Run deterministic fuzz/smoke tests | |
| run: zig build test-fuzz-smoke --summary all | |
| - name: Run coverage-guided fuzz targets (deterministic mode) | |
| run: zig build test-fuzz --summary all | |
| - name: Run resource-budget regression tests | |
| run: zig build test-resource-budgets --summary all | |
| - name: Run OOM regression tests | |
| run: zig build test-oom --summary all | |
| - name: Run raw-frame security e2e tests | |
| run: zig build test-e2e-security --summary all | |
| e2e-zig: | |
| name: Zig e2e interop | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| - name: Install Cap'n Proto compiler | |
| run: | | |
| if command -v sudo >/dev/null 2>&1; then | |
| sudo apt-get update | |
| sudo apt-get install -y capnproto libcapnp-dev | |
| else | |
| apt-get update | |
| apt-get install -y capnproto libcapnp-dev | |
| fi | |
| - name: Run Zig e2e gate | |
| run: just e2e-zig | |
| # The cross-implementation Level-3 HOSTING proof: the vendored Cap'n Proto | |
| # C++ reference drives the recipient and introducer roles over real TCP | |
| # against a capnp-zig two-peer VatC host. | |
| # | |
| # It is folded into this job rather than given its own because this job | |
| # already pays for docker and the cpp-rpc image, so the marginal cost is | |
| # near zero. Before this step existed, the lane ran in NO workflow and in | |
| # neither `just ci` nor `release-preflight` -- v0.6.0 shipped citing it as | |
| # the evidence for cross-impl hosting while nothing executed it. It is | |
| # also the only gate that would catch a vendored-submodule bump breaking | |
| # conformance. | |
| - name: Cross-impl L3 hosting gate (C++ drives A+B vs a Zig VatC host) | |
| run: just e2e-l3-vatc | |
| bench-check: | |
| name: Benchmark regression check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| - name: Run benchmark regression checks | |
| run: zig build -Doptimize=ReleaseFast bench-check | |
| wasm-build: | |
| name: WASM build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| - name: Build WASM host | |
| run: zig build wasm-host | |
| release-build: | |
| name: Release build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| - name: Build ReleaseSafe | |
| run: zig build -Doptimize=ReleaseSafe | |
| release-safe-tests: | |
| name: ReleaseSafe hardening tests (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - uses: jdx/mise-action@v4 | |
| with: | |
| version: 2026.7.17 | |
| - uses: ./.github/actions/setup-zig | |
| # STILL THE TEN-BINARY SUBSET, and that is a known gap rather than a | |
| # choice. Promoting this to the full suite | |
| # (`zig build test -Doptimize=ReleaseSafe`) is correct and was attempted: | |
| # it passes locally on macOS at 1291/1291, and it immediately found a | |
| # real defect on the other two tiers -- | |
| # `rpc_join_readiness_test."L4 Join proxy relay rolls back state under | |
| # OOM injection"` fails under ReleaseSafe on BOTH ubuntu-latest and | |
| # windows-latest, consistently, while passing in Debug everywhere and in | |
| # ReleaseSafe on macOS. That test drives `checkAllAllocationFailures`, so | |
| # the likely shape is an OOM rollback path whose behaviour depends on an | |
| # allocation sequence that optimization changes. | |
| # | |
| # The promotion lands once that is fixed. Recorded here rather than left | |
| # as a silently narrow lane: the subset covers message/codegen/framing/ | |
| # fuzz-smoke and two transport files, so most of the RPC runtime -- peer, | |
| # caps, promises, vat, integration -- is still never executed with safety | |
| # checks on in an optimized build. | |
| - name: Run the full suite under ReleaseSafe | |
| run: zig build test -Doptimize=ReleaseSafe --summary all | |
| # ReleaseFast, not for speed but because it is the only mode that does NOT | |
| # poison a freed pointer. A use-after-free reached from a destructor is | |
| # invisible in Debug and ReleaseSafe -- `HostPeer.deinit` freed the queue | |
| # that `Peer.deinit`'s own Finish/Release sends appended to, and all 981 | |
| # tests passed anyway until this lane existed. | |
| - name: Run teardown-heavy RPC suites under ReleaseFast | |
| run: zig build test-release-fast --summary all |