Files
horizon-airdef/.github/workflows/ci.yml
T
Ludovic Marie be16401f90 Telemetry: send to telemetry.playhorizon.dev, a benchmarks summary, the Railway config
- DEFAULT_ENDPOINT is https://telemetry.playhorizon.dev. The heartbeat, the launcher's live count and the
  outbox upload all go there; HORIZON_TELEMETRY_URL still names another server, and HORIZON_TELEMETRY_URL=off
  sends nothing at all. CI workflows and the harnesses that start the game or the launcher set off. Consent
  is unchanged: the four switches stay opt-in, only the anonymous ping is always on.
- GET /v1/benchmarks/summary: players' benchmark uploads grouped by GPU, CPU, render distance and game, groups
  of 3+ installs only, medians per install then across installs, no install ID, day, OS version, driver,
  memory or screen. Cached 10 minutes, CORS for the website. Same rules as website/scripts/benchmarks.mjs,
  tested on the same fixtures; a deleted install leaves its groups at once.
- /v1/aggregate no longer lists the newest 50 raw benchmark reports (hardware, driver, day, one install each):
  uploads are published only through the summary.
- Behind Railway's proxy the rate limit counts X-Real-IP, else the last X-Forwarded-For entry (the one the
  proxy adds; a client could choose the first). Still in memory only, never stored or logged.
- crates/horizon-telemetry-server/railway.json: Dockerfile build from the repository root, health check
  /healthz, one replica in europe-west4 (one SQLite file on the /data volume).
- Docs: docs/telemetry.md, the server README (the summary's shape, Railway setup), the privacy page (the ping
  is on, where the data lives, how benchmark uploads are shown).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 21:46:32 +02:00

538 lines
25 KiB
YAML

name: checks
# verify: every pull request and every push to main, on GitHub's runners (the repository is public). It is the
# check main requires, so it never has a condition: a skipped job counts as passed, and every run of this workflow
# must report a real verify (a pull request that changes no Rust finishes it in seconds instead).
# parity: the vanilla harnesses a pull request's changes can affect, on the Mac mini's runner, which holds the
# maintainer's own Minecraft files (Horizon never downloads the game); .github/workflows/parity.yml. A fork's pull
# request runs it only when a maintainer adds the run-parity label (.github/workflows/run-parity.yml), so labels
# never start this workflow. See docs/release-flow.md.
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
permissions:
contents: read
concurrency:
# A new push to a pull request replaces its running checks; main's runs all finish (releases follow them).
group: checks-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
# Test runs never reach the telemetry server: no live-count ping, no uploads (docs/telemetry.md).
HORIZON_TELEMETRY_URL: "off"
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Does this pull request need Rust checks?
if: github.event_name == 'pull_request'
id: rust
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: python3 tools/ci/rust_changes.py "$BASE_SHA" "$HEAD_SHA" >> "$GITHUB_OUTPUT"
- name: Keep game artifacts out of Git
run: |
python tools/check_public_tree.py
python tools/check_public_tree.py --history
- name: Test offline research tooling
run: python -m unittest discover -s tests -v
- name: Install Rust toolchain and the ALSA and udev headers the client links against
if: steps.rust.outputs.required != 'false'
run: |
sudo apt-get update && sudo apt-get install -y --no-install-recommends libasound2-dev libudev-dev
rustup toolchain install stable --profile minimal --component rustfmt --component clippy --target wasm32-unknown-unknown
# Dependencies and the workspace's own build, saved from main's runs (pull requests read main's cache).
- uses: Swatinem/rust-cache@v2
if: steps.rust.outputs.required != 'false'
with:
shared-key: verify
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Check formatting and lint
if: steps.rust.outputs.required != 'false'
run: |
cargo +stable fmt --all -- --check
cargo +stable clippy --workspace --all-targets -- -D warnings
# The server build (released as horizon-engine): the game without sound or controllers.
cargo +stable clippy -p horizon-client --all-targets --no-default-features -- -D warnings
- name: Test Rust core and voxel kernel correctness
if: steps.rust.outputs.required != 'false'
run: cargo +stable test --workspace
parity:
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
uses: ./.github/workflows/parity.yml
with:
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
# Horizon never downloads the game. These jobs need a self-hosted Linux runner
# (label horizon-game) holding the maintainer's own copy: the official launcher's
# game directory in HORIZON_MINECRAFT_DIR and the pinned server jar in
# HORIZON_SERVER_JAR. Start them by hand: gh workflow run checks --ref <branch>.
vanilla-parity:
if: github.event_name == 'workflow_dispatch'
runs-on: [self-hosted, linux, horizon-game]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Rust toolchain
run: rustup toolchain install stable --profile minimal
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '25'
- name: Compare Rust foundations with pinned vanilla client and server bytecode
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_rust_parity.py --prepare
- name: Check Rust world-data interoperability with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_world_parity.py
- name: Compare scheduled ticks and saved tick data with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_tick_parity.py
- name: Compare simulation geometry and cached block collision shapes
env:
RUSTUP_TOOLCHAIN: stable
run: |
python tools/test_geometry_parity.py
python tools/test_collision_parity.py
- name: Compare noise samplers and density kernels with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_noise_parity.py
- name: Compare compiled density samplers with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_density_parity.py
- name: Compare world-generation JSON codecs with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_worldgen_parity.py
- name: Compare heightmap predicates and chunk mutations with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_heightmap_parity.py
- name: Compare pre-light chunk status transitions and block writes
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_chunk_stage_parity.py
- name: Compare feature placement into resident neighboring chunks
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_feature_region_parity.py
- name: Compare nested feature selectors and sequences
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_feature_graph_parity.py
- name: Compare named feature holders and placed-feature tags
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_feature_catalog_parity.py
- name: Compare configured fill-layer block placement
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_fill_layer_parity.py
- name: Compare replacement-rule codecs and evaluation
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_rule_test_parity.py
- name: Compare simple-block placement and feature composition
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_simple_block_parity.py
- name: Compare block-column sampling and obstruction
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_block_column_parity.py
- name: Compare vertical pillars and cap feature placement
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_pillar_parity.py
- name: Compare exactly-one-neighbor feature spreading
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_neighbor_spread_parity.py
- name: Compare block-pile support and placement
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_block_pile_parity.py
- name: Compare disk replacement and postprocessing
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_disk_parity.py
- name: Compare block-blob support search and geometry
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_block_blob_parity.py
- name: Compare spring placement and fluid tick scheduling
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_spring_parity.py
- name: Compare vine attachment priority and placement
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_vines_parity.py
- name: Compare underwater magma floor scans and occlusion
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_underwater_magma_parity.py
- name: Compare blue-ice seeding and growth attempts
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_blue_ice_parity.py
- name: Compare spike geometry and discontinuous roots
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_spike_parity.py
- name: Compare End podium construction and destruction requests
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_end_podium_parity.py
- name: Rust End gateway parity
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_end_gateway_parity.py
- name: Compare bonus chest placement and conditional loot seeding
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_bonus_chest_parity.py
- name: Compare recursive chorus generation and connection refreshes
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_chorus_plant_parity.py
- name: Compare small speleothem patches and waterlogged points
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_speleothem_parity.py
- name: Compare replacement blob search and Manhattan shells
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_replace_blobs_parity.py
- name: Compare bamboo stalks, podzol patches and leafy caps
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_bamboo_parity.py
- name: Compare Nether delta rims and shifted contents
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_delta_parity.py
- name: Compare biome freezing and snow eligibility
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_biome_weather_parity.py
- name: Compare frozen top layers and snowy ground updates
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_snow_freeze_parity.py
- name: Compare generation-stage tick storage and routing
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_generation_tick_parity.py
- name: Compare below-zero upgrade metadata codecs
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_retrogen_data_parity.py
- name: Compare below-zero upgrade lifecycle and block transformations
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_retrogen_chunk_parity.py
- name: Compare chunk-status metadata, ordering and codecs
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_chunk_status_parity.py
- name: Compare proto-chunk block-entity storage and coordinates
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_block_entity_storage_parity.py
- name: Compare ordered single-block replacement features
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_replace_block_parity.py
- name: Compare scattered ore placement and air-exposure checks
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_scattered_ore_parity.py
- name: Compare resident bulk-section access and raw writes
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_bulk_section_parity.py
- name: Compare biome feature ordering and cycle detection
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_feature_sort_parity.py
- name: Compare world-generation random wrappers and seeding
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_worldgen_random_parity.py
- name: Compare biome filtering and top-level feature context
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_biome_placement_parity.py
- name: Compare biome decoration feature scheduling and seeding
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_decoration_parity.py
- name: Compare decoration against resident biome and terrain sections
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_decoration_region_parity.py
- name: Compare block-state provider choices and rotation
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_state_provider_parity.py
- name: Compare contained fluids and height queries with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_fluid_parity.py
- name: Compare entity obstruction with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_entity_obstruction_parity.py
- name: Compare block solidity and replaceability with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_block_properties_parity.py
- name: Compare face slicing and block support with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_face_support_parity.py
- name: Compare cached block support with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_block_support_parity.py
- name: Compare dynamic block support with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_dynamic_support_parity.py
- name: Compare moving-piston collision and interpolation with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_piston_shape_parity.py
- name: Compare supported block survival rules with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_block_survival_parity.py
- name: Compare noise-stage chunk filling with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_terrain_parity.py
- name: Compare structure terrain-adaptation density with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_structure_density_parity.py
- name: Compare seeded material bands and surface queries with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_material_surface_parity.py
- name: Compare material condition codecs and rule evaluation with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_material_condition_parity.py
- name: Compare biome temperatures and cache behavior with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_biome_temperature_parity.py
- name: Compare badlands and frozen-ocean extensions with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_material_extension_parity.py
- name: Compare bundled material-rule libraries with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_material_rule_library_parity.py
- name: Compare fixed, checkerboard and End biome sources with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_biome_source_parity.py
- name: Compare seeded cave paths and failure state with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_cave_carver_parity.py
- name: Compare seeded canyon paths and width factors with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_canyon_carver_parity.py
- name: Compare initial block-writing feature algorithms with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_basic_feature_parity.py
- name: Compare feature placement chains with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_feature_placement_parity.py
- name: Compare feature placement primitives with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_placement_parity.py
- name: Compare anchored height providers with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_height_provider_parity.py
- name: Compare scalar value providers with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_value_provider_parity.py
- name: Compare cave and canyon geometric primitives with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_carving_geometry_parity.py
- name: Compare carving-mask traversal and callback mutations with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_carving_mask_parity.py
- name: Compare registry-bound biome-source codecs with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_biome_source_codec_parity.py
- name: Compare all four biome-source kinds in chunk generation with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_biome_generation_parity.py
- name: Compare chunk biome filling and failure state with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_biome_chunk_parity.py
- name: Compare biome zoom and seed obfuscation with pinned vanilla
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_biome_zoom_parity.py
- name: Compare surface-stage chunks with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_material_stage_parity.py
- name: Compare block-state JSON codecs with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_block_state_codec_parity.py
- name: Compare vertical anchors with pinned vanilla client and server
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_anchor_parity.py
- name: Compare float logarithms at domain and rounding boundaries
env:
RUSTUP_TOOLCHAIN: stable
run: python tools/test_float_log_parity.py
portable-mod:
if: github.event_name == 'workflow_dispatch'
runs-on: [self-hosted, linux, horizon-game]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '25'
- name: Compile original mod and test metrics
run: python tools/build_mod.py
- name: Verify streaming JFR analysis against the JDK exporter
run: python tools/test_jfr.py
- name: Verify ZGC pause and allocation event interpretation
run: python tools/test_jfr.py --gc zgc
- name: Build pinned portable packs
run: python tools/build_pack.py
- name: Measure isolated worker pacing on this platform
run: python -c "from tools.build_mod import benchmark_workers; benchmark_workers()"
- name: Measure isolated debounce queue polling
run: python -c "from tools.build_mod import benchmark_debounce; benchmark_debounce()"
- name: Measure wakeable idle queue latency
run: python -c "from tools.build_mod import benchmark_idle; benchmark_idle()"
- name: Measure object allocations with compact headers off and on
run: python -c "from tools.build_mod import benchmark_headers; benchmark_headers()"
- name: Test pack integrity and comparisons
run: python -m unittest discover -s tests -v
- name: Start recommended OpenGL macOS clients and verify framebuffer readback
if: runner.os == 'macOS'
run: |
python tools/test_client_graphics.py --native-display
cp dist/client-graphics-smoke.json dist/client-graphics-macos-title.json
python tools/test_client_graphics.py --native-display --world
cp dist/client-graphics-smoke.json dist/client-graphics-macos-world.json
- name: Compile the private dispatch fixture
run: python -c "from tools.build_mod import build_dispatch_fixture; build_dispatch_fixture()"
- name: Compile the private integrated-server graphics fixture
run: python -c "from tools.build_mod import build_integration_fixture; build_integration_fixture('server-graphics', 'dev.horizonlab.metrics.ServerGraphicsIntegration', fixture_dependencies={})"
- name: Compile the private tick-manager state fixture
run: python -c "from tools.build_mod import build_integration_fixture; build_integration_fixture('tick-state', 'dev.horizonlab.metrics.TickStateIntegration')"
- name: Compile the private terrain tick membership fixture
run: python -c "from tools.build_mod import build_tick_dedup_fixture; build_tick_dedup_fixture()"
- name: Compile the private culling whitelist fixture
run: python -c "from tools.build_mod import build_culling_empty_fixture; build_culling_empty_fixture()"
- name: Compile the private culling ray geometry fixture
run: python -c "from tools.build_mod import build_integration_fixture; build_integration_fixture('culling-rays', 'dev.horizonlab.dispatch.CullingRayIntegration', ['entityculling'], ['CullingRayAccess'])"
- name: Compile the private terrain position lookup fixture
run: python -c "from tools.build_mod import build_integration_fixture; build_integration_fixture('terrain-position', 'dev.horizonlab.dispatch.PositionIntegration')"
- name: Compile the private terrain quad reuse fixture
run: python -c "from tools.build_mod import build_integration_fixture; build_integration_fixture('quad-reuse', 'dev.horizonlab.dispatch.QuadReuseIntegration')"
- name: Compile the private object-size agent and terrain quad fixture
run: python -c "from tools.test_quad_sizes import build_agent; from tools.build_mod import build_integration_fixture; build_agent(); build_integration_fixture('quad-size', 'dev.horizonlab.dispatch.QuadSizeIntegration')"
- name: Compile the private terrain read shutdown fixture
run: python -c "from tools.build_mod import build_integration_fixture; build_integration_fixture('terrain-read', 'dev.horizonlab.dispatch.TerrainReadIntegration')"
- name: Install headless graphics libraries for applied-hook checks
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y xvfb libgl1 libegl1 libvulkan1 mesa-vulkan-drivers libasound2t64 libxkbcommon0
- name: Verify integrated-server graphics report against the actual device
run: python tools/test_server_graphics.py ${{ runner.os == 'macOS' && '--native-display' || '' }}
- name: Exercise the applied dispatcher hooks and upstream rejection path
if: runner.os == 'Linux'
run: python tools/test_dispatch.py
- name: Verify applied tick membership transitions and allocation
if: runner.os == 'Linux'
run: python tools/test_tick_dedup.py
- name: Verify live culling whitelist registration and empty iteration
if: runner.os == 'Linux'
run: python tools/test_culling_empty.py
- name: Compare applied culling ray geometry and provider queries
if: runner.os == 'Linux'
run: python tools/test_culling_rays.py
- name: Verify actual full-data position lookup equivalence
if: runner.os == 'Linux'
run: python tools/test_terrain_position.py
- name: Verify actual terrain quad geometry and allocation
if: runner.os == 'Linux'
run: python tools/test_quad_reuse.py
- name: Measure actual builder and quad shallow sizes in both header modes
if: runner.os == 'Linux'
run: python tools/test_quad_sizes.py
- name: Verify interrupted DH reads and preserved shared futures
if: runner.os == 'Linux'
run: python tools/test_terrain_read.py
- name: Upload original mod and pack manifests only
uses: actions/upload-artifact@v4
with:
name: horizon-linux
path: |
dist/*.mrpack
dist/horizon-*.jar
dist/worker-pacing-benchmark.txt
dist/debounce-queue-benchmark.txt
dist/idle-queue-benchmark.txt
dist/object-header-benchmark.txt
dist/dispatch-integration.json
dist/tick-dedup-integration.json
dist/culling-empty-integration.json
dist/terrain-read-integration.json
dist/culling-rays-integration.json
dist/terrain-position-integration.json
dist/quad-reuse-integration.json
dist/quad-size-integration.json
dist/server-graphics-smoke.json
dist/client-graphics-smoke.json
dist/client-graphics-macos-title.json
dist/client-graphics-macos-world.json
retention-days: 3