stateforward-sml 1.2.0

sml.rs: a no-std Rust implementation of the sml.cpp transition-table DSL
Documentation
name: Quality gates

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read

jobs:
  quality:
    name: Format, lint, test, docs, package
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-python@v6
        with:
          python-version: "3.13"
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy,rustfmt
      - uses: taiki-e/install-action@cargo-llvm-cov
      - uses: taiki-e/install-action@cargo-deny
      - name: Run enforced quality gate
        run: ./scripts/quality_gates.sh

  platforms:
    name: Test ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
    steps:
      - uses: actions/checkout@v7
      - uses: dtolnay/rust-toolchain@stable
      - run: cargo test --workspace --all-features

  msrv:
    name: Rust 1.90 MSRV
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: dtolnay/rust-toolchain@1.90.0
      - run: cargo check --workspace --all-features

  dependency-policy:
    name: Dependency and license policy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: EmbarkStudios/cargo-deny-action@v2
        with:
          rust-version: "1.90.0"
          arguments: --all-features

  semver:
    name: Public API compatibility
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0
      - uses: actions/setup-python@v6
        with:
          python-version: "3.13"
      - name: Prepare API baseline
        env:
          BASELINE_REF: ${{ github.event.pull_request.base.sha || 'HEAD^' }}
        run: |
          mkdir .semver-baseline
          git archive "${BASELINE_REF}" | tar -x -C .semver-baseline
          python3 scripts/prepare_semver_baseline.py .semver-baseline
      - name: Prepare exact compatibility contract
        id: compatibility
        run: |
          current=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
          baseline=$(sed -n 's/^version = "\([^"]*\)"/\1/p' .semver-baseline/Cargo.toml | head -1)
          if [ "${baseline}" = "1.0.0" ] && [ "${current}" = "1.1.0" ]; then
            cp -R .semver-baseline .semver-authorized
            python3 scripts/prepare_machine_1_1_semver_baseline.py .semver-authorized
            echo "baseline_root=.semver-authorized" >> "${GITHUB_OUTPUT}"
            echo "machine_exception=true" >> "${GITHUB_OUTPUT}"
          else
            echo "baseline_root=.semver-baseline" >> "${GITHUB_OUTPUT}"
            echo "machine_exception=false" >> "${GITHUB_OUTPUT}"
          fi
      - name: Enforce compatibility outside the exact Machine exception
        uses: obi1kenobi/cargo-semver-checks-action@v2
        with:
          package: stateforward-sml
          feature-group: all-features
          baseline-root: ${{ steps.compatibility.outputs.baseline_root }}
          release-type: patch
      - name: Prepare unrelated-break negative control
        if: steps.compatibility.outputs.machine_exception == 'true'
        run: |
          mkdir .semver-negative
          git archive HEAD | tar -x -C .semver-negative
          python3 scripts/prepare_semver_negative_control.py .semver-negative
      - name: Prove unrelated breaking changes still fail
        if: steps.compatibility.outputs.machine_exception == 'true'
        id: negative_control
        continue-on-error: true
        uses: obi1kenobi/cargo-semver-checks-action@v2
        with:
          manifest-path: .semver-negative/Cargo.toml
          package: stateforward-sml
          feature-group: all-features
          baseline-root: .semver-authorized
          release-type: patch
      - name: Require the negative control to fail
        if: steps.compatibility.outputs.machine_exception == 'true'
        env:
          NEGATIVE_OUTCOME: ${{ steps.negative_control.outcome }}
        run: test "${NEGATIVE_OUTCOME}" = failure

  links:
    name: Documentation links
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: lycheeverse/lychee-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          args: >-
            --no-progress
            --exclude-path target
            --exclude-path fuzz/corpus
            './**/*.md'