name: ci # Release/runtime, external-consumer, and instrumented-coverage jobs run on # separate runners. These builds do not depend on each other's artifacts. # A prose-only push skips this workflow and runs docs.yml instead; mixed # source/documentation changes keep the full CI suite. A push that changes only # the Mac app in apps/ or its workflow runs sevra-mac.yml instead, which also # runs for engine changes because the app builds on the engine. on: pull_request: paths-ignore: ["**.md", "docs/**", "db/**", "llms.txt", "llms-full.txt", "LICENSE", "apps/**", ".github/workflows/sevra-mac.yml"] push: branches: [main] paths-ignore: ["**.md", "docs/**", "db/**", "llms.txt", "llms-full.txt", "LICENSE", "apps/**", ".github/workflows/sevra-mac.yml"] permissions: contents: read jobs: weights-free: runs-on: macos-26 steps: - uses: actions/checkout@v7 - name: harness entry points (before the native build) run: | python3 Tools/static_gates_binary_test.py python3 Tools/planner_gates_test.py python3 Tools/release_candidate_test.py - name: toolchain run: sudo xcode-select -s "$(ls -d /Applications/Xcode*.app | sort -V | tail -1)" - name: pinned Metal library run: SLOTSTREAM_METALLIB_MACOS=26 Tools/fetch_metallib.sh - name: release build # `make build` also colocates the pinned metallib with the binary; # sampler-golden executes MLX kernels and a bare SwiftPM build does not. run: make build - name: preserve the candidate before testing run: | mkdir ci-candidate tar -czf ci-candidate/slotstream-arm64.tar.gz -C .build/release \ slotstream mlx.metallib build-identity.json build-source.tar.gz (cd ci-candidate && shasum -a 256 slotstream-arm64.tar.gz > slotstream-arm64.tar.gz.sha256) - uses: actions/upload-artifact@v4 if: github.event_name == 'push' && github.ref == 'refs/heads/main' with: name: slotstream-ci-candidate path: ci-candidate/ if-no-files-found: error - name: planner startup and checkpoint gates (fail early) run: Tools/planner_gates.sh - name: pinned dbmd (the brain gates inside static_gates.sh need it) run: Tools/dbmd_install.sh - name: static and runtime safety gates run: Tools/static_gates.sh - name: sampler and governor goldens run: | python3 -m pip install --quiet --break-system-packages numpy Tools/sampler_gates.sh - name: check catalogue (every check by name) # The release build already put the metallib in .build/release, which is # where MLX looks for it: beside the executable that is running. The # runner sits in that same directory, so T1 finds the shaders too. run: .build/release/slotstream-checks --tier t0 --tier t1 - name: the tested bytes still match the candidate run: | python3 Tools/release_candidate.py --archive ci-candidate/slotstream-arm64.tar.gz --output .build/checked-candidate for file in slotstream mlx.metallib build-identity.json build-source.tar.gz; do cmp ".build/release/$file" ".build/checked-candidate/$file" done public-library: runs-on: macos-26 steps: - uses: actions/checkout@v7 - name: toolchain run: sudo xcode-select -s "$(ls -d /Applications/Xcode*.app | sort -V | tail -1)" - name: the library is importable from outside the package run: Tools/consumer_smoke.sh coverage: runs-on: macos-26 steps: - uses: actions/checkout@v7 - name: toolchain run: sudo xcode-select -s "$(ls -d /Applications/Xcode*.app | sort -V | tail -1)" - name: pinned Metal library run: SLOTSTREAM_METALLIB_MACOS=26 Tools/fetch_metallib.sh - name: instrumented checks and coverage collection run: Tools/coverage.sh t0 t1 --lcov coverage.info - name: coverage changes (advisory) # Test/build/report errors still fail. Historical percentages are review # signals; separate context, CLI and real-model suites are not counted. run: python3 Tools/coverage_ratchet.py coverage.info - name: coverage report if: ${{ always() && hashFiles('coverage.info') != '' }} uses: actions/upload-artifact@v4 with: name: coverage-lcov path: coverage.info