All checks were successful
CultMesh QUIC native / Build win32-x64 (push) Has been skipped
CultMesh QUIC native / Build linux-x64 (push) Has been skipped
CultMesh QUIC native / Release native binaries (push) Has been skipped
CultMesh QUIC native / Verify committed binaries match SHA256SUMS (push) Successful in 36s
204 lines
11 KiB
YAML
204 lines
11 KiB
YAML
name: CultMesh portability and performance
|
|
|
|
# The forge runs one job at a time and this workflow holds the slot 14 to 30 minutes, so it runs once per change:
|
|
# on the pull request (never again on the push that merges it; a break that merges from a stale base waits for the
|
|
# schedule), skipped for design-note-only changes, and on a
|
|
# daily schedule so main is still exercised when nobody opens a pull request.
|
|
on:
|
|
pull_request:
|
|
paths-ignore:
|
|
# Not `**/*.md` or `docs/**`: docs/start/README.md is read by the first-call tests of every runtime.
|
|
- "docs/*.md"
|
|
- "research/**"
|
|
- ".voidbot/**"
|
|
schedule:
|
|
- cron: "17 3 * * *"
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
# A newer push or PR update replaces the older run on the same ref. Tag pushes and
|
|
# workflow_dispatch runs are never cancelled: a tag run carries a release.
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: ${{ github.event_name == 'pull_request' || (github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')) }}
|
|
|
|
jobs:
|
|
reactive-and-resource-lifetime:
|
|
name: ${{ matrix.os }} reactive semantics and leases
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 30
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# The forge runner (label `ubuntu-latest`) is Linux-only and no Windows runner exists: the Windows leg runs on workflow_dispatch only (GitHub or a Windows runner), the ubuntu-latest leg gates push and PR. Windows push/PR triggers return in the PR that registers a Windows runner.
|
|
os: ${{ fromJSON(github.event_name == 'workflow_dispatch' && '["windows-latest", "ubuntu-latest"]' || '["ubuntu-latest"]') }}
|
|
|
|
steps:
|
|
- name: Check out CultLib
|
|
uses: actions/checkout@v4
|
|
with:
|
|
# The declared-dependency-range test builds the admitted releases from their tags.
|
|
fetch-depth: 0
|
|
fetch-tags: true
|
|
|
|
- name: Set up .NET
|
|
uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: 10.0.x
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 24
|
|
cache: npm
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Install TypeScript workspace dependencies
|
|
run: npm install --no-package-lock
|
|
|
|
- name: Install Python CultLib packages
|
|
run: python -m pip install -e packages/cultcache-py -e packages/cultnet-py -e packages/cultmesh-py
|
|
|
|
# The forge runner images carry no cargo either (the cross-runtime store tests build the Rust interop example); GitHub's hosted images do.
|
|
- name: Install Rust toolchain
|
|
if: runner.os == 'Linux'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if ! command -v cargo >/dev/null && [ ! -x "$HOME/.cargo/bin/cargo" ]; then
|
|
curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
|
|
fi
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
|
|
# The forge runner images carry no pwsh; GitHub's Windows and hosted images do.
|
|
- name: Install PowerShell
|
|
if: runner.os == 'Linux'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if command -v pwsh >/dev/null; then pwsh -Version; exit 0; fi
|
|
SUDO=""; [ "$(id -u)" -eq 0 ] || SUDO="sudo"
|
|
PWSH_VERSION=7.4.6
|
|
curl -fsSL "https://github.com/PowerShell/PowerShell/releases/download/v${PWSH_VERSION}/powershell-${PWSH_VERSION}-linux-x64.tar.gz" -o "${RUNNER_TEMP:-/tmp}/powershell.tar.gz"
|
|
$SUDO mkdir -p /opt/microsoft/powershell/7
|
|
$SUDO tar -xzf "${RUNNER_TEMP:-/tmp}/powershell.tar.gz" -C /opt/microsoft/powershell/7
|
|
$SUDO chmod +x /opt/microsoft/powershell/7/pwsh
|
|
$SUDO ln -sf /opt/microsoft/powershell/7/pwsh /usr/local/bin/pwsh
|
|
echo "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1" >> "$GITHUB_ENV"
|
|
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 pwsh -Version
|
|
|
|
- name: Verify explicit reactive scheduling across runtimes
|
|
shell: pwsh
|
|
run: ./scripts/verify-reactive-document-scaling.ps1
|
|
|
|
- name: Measure representative reactive workload
|
|
shell: pwsh
|
|
run: ./scripts/measure-reactive-document-performance.ps1 -Quick -SkipRuntimeBuild
|
|
|
|
- name: Churn 100,000 distinct document leases
|
|
run: >-
|
|
dotnet test tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj
|
|
--filter FullyQualifiedName~Document_OneHundredThousandDistinctLeaseCyclesLeaveNoResourcesOrCallbacks
|
|
--logger "console;verbosity=minimal"
|
|
|
|
# The TypeScript side of the CultMesh authority rules. This job is the
|
|
# only one that runs on Linux for main, codex/** and pull requests (and on
|
|
# Windows too under workflow_dispatch): cultnet-interop.yml is windows-latest and dispatch-only, so
|
|
# until these steps existed the shared verifier's tests never ran on
|
|
# Linux at all, and the browser client's never ran in CI on any OS.
|
|
# packages/cultnet-ts verifies both vector files (content.test.ts judges both
|
|
# C# content files, the Rust one and its own); cultmesh-browser proves
|
|
# the browser client reads the shared rules rather than its own, and that its content reader releases only verified
|
|
# bytes, requesting the same URLs as the C# HTTPS connector.
|
|
# No workflow ran cultcache-ts's tests, and its test script listed two files by hand while a third sat compiled
|
|
# and unrun. The wiring check fails when any TypeScript test file is run by no script, and the cache's own suite
|
|
# runs here beside the packages built on it.
|
|
- name: Check that every TypeScript test file is run by its package
|
|
run: node scripts/check-typescript-tests-wired.mjs
|
|
|
|
- name: Verify the CultCache document owner with the TypeScript cache
|
|
run: npm run test --workspace packages/cultcache-ts
|
|
|
|
# The Python cache's unit suite ran only in cultnet-interop.yml (windows-latest, dispatch-only), so on Linux
|
|
# it ran nowhere. It sits after the TypeScript cache's test so the built cultcache-ts store holder exists for the
|
|
# cross-runtime store-lock test, which skips without it.
|
|
- name: Verify the CultCache document owner with the Python cache
|
|
run: python -m unittest discover -s packages/cultcache-py/tests
|
|
|
|
# cargo test for packages/cultcache-rs ran in no workflow: the Rust cache's own unit and doc tests were unwatched
|
|
# (only the interop example built, inside the C# store tests). The target directory is under RUNNER_TEMP, away from the checkout.
|
|
- name: Verify the CultCache document owner with the Rust cache
|
|
shell: bash
|
|
run: CARGO_TARGET_DIR="$RUNNER_TEMP/cultcache-rs-target" cargo test --manifest-path packages/cultcache-rs/Cargo.toml
|
|
|
|
# tests/GameCult.Caching.Tests, the C# reference cache's own suite (about 1,260 tests, under a minute), ran in no
|
|
# forge workflow; only the Mesh tests above exercised the reference.
|
|
# The forge runner is globalization-invariant, so ADeterministicIdIsTheSameUnderEveryCulture... cannot construct a
|
|
# culture and throws CultureNotFoundException; it is excluded here and still runs wherever ICU is present
|
|
# (variants:follow_up:culture-test-invariant-image).
|
|
- name: Verify the CultCache document owner with the C# reference
|
|
run: dotnet test tests/GameCult.Caching.Tests/GameCult.Caching.Tests.csproj --filter "FullyQualifiedName!~ADeterministicIdIsTheSameUnderEveryCulture" --logger "console;verbosity=minimal"
|
|
|
|
# Packs the four TypeScript packages and installs them into a clean consumer, so a package that builds but does
|
|
# not install or load fails here.
|
|
- name: Verify the packed TypeScript packages install and load from a clean consumer
|
|
run: npm run test:pack:ts
|
|
|
|
- name: Verify the CultMesh authority rules with the TypeScript verifier
|
|
run: npm run test --workspace packages/cultnet-ts
|
|
|
|
# cultmesh-browser's test compiles test/interop, which imports cultmesh-ts/content, so cultmesh-ts builds first,
|
|
# as in scripts/run-typescript-workspaces.mjs.
|
|
# The realtime frame codec and the HTTP content chunk provider (content.test.ts,
|
|
# its answers over node:http). The codec's byte parity rests on two vector files,
|
|
# contracts/cultmesh/realtime-frame-vectors.json written by the C#
|
|
# reference and decoded by this step, and realtime-frame-vectors.ts-written.json
|
|
# written by this codec and decoded by the C# step below. Neither half ran
|
|
# in CI on any OS until these two steps existed, so a codec that agreed
|
|
# only with itself would have gone green.
|
|
- name: Verify the realtime frame codec and the content provider with the TypeScript runtime
|
|
run: npm run test --workspace packages/cultmesh-ts
|
|
|
|
- name: Verify the browser client against the shared TypeScript verifier
|
|
run: npm run test --workspace packages/cultmesh-browser
|
|
|
|
# Both directions of the CultMesh authority vectors: the C#-written
|
|
# file (contracts/cultmesh/authority-route-vectors.json) and the
|
|
# TypeScript-signed file (authority-route-vectors.ts-signed.json) are
|
|
# verified by the C# reference here; the TypeScript side verifies both
|
|
# in the step above. CULTMESH_WRITE_VECTORS is never set in CI: the
|
|
# committed files are the contract.
|
|
- name: Verify the CultMesh authority vectors with the C# reference
|
|
run: >-
|
|
dotnet test tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj
|
|
--filter FullyQualifiedName~AuthorityProof
|
|
--logger "console;verbosity=minimal"
|
|
|
|
# The other half of the frame parity: the C# reference decodes and
|
|
# re-encodes the vector file the TypeScript codec wrote. A fixture
|
|
# authored on one side alone would only agree with itself.
|
|
- name: Verify the realtime frame vectors with the C# reference
|
|
run: >-
|
|
dotnet test tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj
|
|
--filter FullyQualifiedName~RealtimeWireProtocol
|
|
--logger "console;verbosity=minimal"
|
|
|
|
# The content plane: the reference writes the manifest and record-key
|
|
# vectors and judges the manifests the TypeScript packer wrote
|
|
# (content-vectors.ts-written.json). This suite also holds the C#/Rust
|
|
# content parity, which no CI step ran before this one. CULTNET_WRITE_VECTORS
|
|
# is never set in CI: the committed files are the contract.
|
|
- name: Verify the content vectors with the C# reference
|
|
run: >-
|
|
dotnet test tests/GameCult.Mesh.Tests/GameCult.Mesh.Tests.csproj
|
|
--filter FullyQualifiedName~CultMeshContentVectorTests
|
|
--logger "console;verbosity=minimal"
|
|
|
|
# The cross-process HTTPS content parity: the C# transfer service over the unmodified HTTPS connector and the
|
|
# TypeScript reader fetch from the TypeScript provider in its own process. Both refuse bytes tampered in flight,
|
|
# and the provider refuses a corrupt store.
|
|
- name: Verify HTTPS content parity across C#, the TypeScript provider and the TypeScript reader
|
|
run: npm run test:interop --workspace packages/cultmesh-browser
|