tests/draft22_roundtrip.rs: a seeded generator builds valid control messages of every type, subgroup and fetch streams in both Group Orders, datagrams and WAI_RECEIPT values; encode, decode, encode is the identity. The encodings and the corpus, mutated, are fed to every decoder, whole and incrementally; none may panic. joule-code-conformance runs the independent decoder over the corpus. Co-Authored-By: Claude Opus 5.5 <[email protected]>
140 lines
6.2 KiB
YAML
140 lines
6.2 KiB
YAML
name: joule-code conformance gate
|
||
|
||
# Enforces the Joule Code conformance contract on every change: the reference
|
||
# library must build and pass its tests, and the published C1–C4 wire vectors
|
||
# must round-trip (SPEC §8). "Conformant = round-trips the vectors" — checked,
|
||
# not asserted.
|
||
|
||
# One run per branch at a time. A push supersedes the run before it.
|
||
#
|
||
# There is one `macos` runner and it is the dev Mac, so every macOS job in this
|
||
# repo queues on it. With no concurrency group, a session pushing four versions
|
||
# of a branch queued four complete sets of runs and every one of them had to
|
||
# drain: on 2026-10-05 a PR's 21 contexts settled none in 70 minutes behind a
|
||
# backlog of 25 runs, and the queue grew faster than it cleared. Only the newest
|
||
# commit's verdict is wanted, so the older runs are cancelled.
|
||
#
|
||
# Verified on this forge (Forgejo 16.0.5) in `ci-test` before being added here:
|
||
# the key parses, and a newer push moves an older run to `cancelled` even while
|
||
# it is still queued, which is the case that matters.
|
||
#
|
||
# `cancel-in-progress: true` also applies to `main`. That is deliberate and
|
||
# safe here: main advances by merge commits whose tree contains the commits
|
||
# before them, so the newer run covers the older one's changes.
|
||
concurrency:
|
||
group: ${{ github.workflow }}-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
on:
|
||
pull_request:
|
||
paths:
|
||
- 'joule-code/**'
|
||
# joule-moq's receipt tests pin leaves, roots and signatures copied from WAI's
|
||
# jwp-conformance corpus, and run every leaf, group and object vector in it:
|
||
# a change there must re-run them.
|
||
- 'wai/jwp-conformance/**'
|
||
# joule-moq's tests/staged_moq_trace.rs runs the MoQ trace of
|
||
# wai/staged-conformance/moq/ over the envelopes of one of its cases.
|
||
- 'wai/staged-conformance/**'
|
||
- '.github/workflows/joule-code-conformance.yml'
|
||
push:
|
||
branches:
|
||
- main
|
||
paths:
|
||
- 'joule-code/**'
|
||
# joule-moq's receipt tests pin leaves, roots and signatures copied from WAI's
|
||
# jwp-conformance corpus, and run every leaf, group and object vector in it:
|
||
# a change there must re-run them.
|
||
- 'wai/jwp-conformance/**'
|
||
# joule-moq's tests/staged_moq_trace.rs runs the MoQ trace of
|
||
# wai/staged-conformance/moq/ over the envelopes of one of its cases.
|
||
- 'wai/staged-conformance/**'
|
||
- '.github/workflows/joule-code-conformance.yml'
|
||
|
||
jobs:
|
||
conformance:
|
||
name: Build + round-trip C1-C4 vectors
|
||
runs-on: linux
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
# Bootstrap rustup: the docker runner image ships no Rust, and
|
||
# dtolnay/rust-toolchain cannot help — it calls `rustup`, which is absent.
|
||
- name: Install Rust 1.98.0
|
||
run: |
|
||
export PATH="$HOME/.cargo/bin:$PATH"
|
||
command -v rustup >/dev/null 2>&1 || \
|
||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain 1.98.0
|
||
rustup toolchain install 1.98.0 --profile minimal
|
||
rustup default 1.98.0
|
||
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||
|
||
- name: Cache cargo
|
||
uses: actions/cache@v4
|
||
with:
|
||
path: |
|
||
~/.cargo/registry
|
||
~/.cargo/git
|
||
joule-code/joule-code-rs/target
|
||
key: joule-code-${{ runner.os }}-${{ hashFiles('joule-code/joule-code-rs/Cargo.lock') }}
|
||
|
||
# joule-code-remediate's formal gate shells out to `z3`, and the runner
|
||
# image has no solver. Its tests assert in both branches. With a solver
|
||
# installed here, JOULE_FIX_EXPECT_Z3=1 makes its absence a failure, so
|
||
# this gate runs the real-solver branch rather than the fail-closed one.
|
||
- name: Install z3
|
||
shell: bash
|
||
run: |
|
||
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
|
||
$SUDO apt-get update -qq
|
||
$SUDO apt-get install -y -qq z3
|
||
z3 --version
|
||
|
||
- name: Reference library tests
|
||
working-directory: joule-code/joule-code-rs
|
||
env:
|
||
JOULE_FIX_EXPECT_Z3: '1'
|
||
run: cargo test --workspace
|
||
|
||
# joule-moq's QUIC transport and its example compile only with `quic`. Named
|
||
# here so they stay built and tested whatever the workspace's other members
|
||
# happen to enable; this also runs tests/wai_jwp_corpus.rs, every leaf, group
|
||
# and object vector of wai/jwp-conformance through the crate.
|
||
- name: joule-moq with the QUIC transport, every target
|
||
working-directory: joule-code/joule-code-rs
|
||
run: cargo test -p joule-moq --features quic --all-targets
|
||
|
||
# joule-moq's draft-ietf-moq-transport-22 vectors, read by a second decoder
|
||
# written from the draft's text rather than from the crate. The step above
|
||
# (tests/draft22_vectors.rs) holds the crate to the same corpus and fails if
|
||
# the committed corpus is not what its generator makes. This one must read
|
||
# every good vector as stated and refuse every negative one as stated; it
|
||
# fails on an empty corpus.
|
||
- name: Ensure python3 is available
|
||
shell: bash
|
||
run: |
|
||
if ! command -v python3 >/dev/null 2>&1; then
|
||
SUDO=""; [ "$(id -u)" -ne 0 ] && SUDO="sudo"
|
||
$SUDO apt-get update -qq
|
||
$SUDO apt-get install -y -qq python3
|
||
fi
|
||
python3 --version
|
||
|
||
- name: joule-moq draft-22 vectors, independent decoder
|
||
run: python3 -I joule-code/joule-code-rs/crates/joule-moq/tests/vectors/draft-22/moqt22_check.py
|
||
|
||
- name: Round-trip the v1 conformance pack (C1-C4)
|
||
working-directory: joule-code/joule-code-rs
|
||
run: |
|
||
set -e
|
||
out="$(cargo run -q -p joule-code-conformance -- verify ../conformance/v1)"
|
||
echo "$out"
|
||
# The pack must pass with zero failures. The summary line reads
|
||
# "N passed, F failed, S skipped"; anchor on it, so that "10 failed" can never
|
||
# read as "0 failed", and require at least one pass, so an empty pack fails.
|
||
echo "$out" | grep -Eq '^[1-9][0-9]* passed, 0 failed, ' || { echo "::error::conformance pack reported failures"; exit 1; }
|
||
|
||
- name: L3 JouleClaw binding example builds + tests
|
||
working-directory: joule-code/examples/l3-jouleclaw
|
||
run: cargo test
|