on:
  pull_request:
    paths-ignore:
      - '.github/**'
      - 'docs/**'

name: Check, Build and Test

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  format:
    name: compat-rustfmt
    runs-on: [self-hosted]

    env:
      CARGO_TERM_COLOR: always

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          submodules: recursive

      - name: Install nightly toolchain
        run: |
          rustup toolchain install nightly --profile minimal
          rustup component add rustfmt --toolchain nightly

      - name: Run rustfmt
        run: cargo +nightly fmt --all --check

  clippy:
    name: compat-clippy
    strategy:
      fail-fast: true

    runs-on: [self-hosted]
    env:
      CARGO_TERM_COLOR: always
      RUSTUP_TOOLCHAIN: stable
      LIBRA_SKIP_WEB_BUILD: "1"

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          submodules: recursive

      - name: Setup Node.js
        uses: actions/setup-node@v5
        with:
          node-version: "22"

      - name: Enable pnpm
        run: |
          corepack enable
          corepack prepare pnpm@11.1.0 --activate

      - name: Run cargo clippy
        run: cargo clippy --all-targets --all-features -- -D warnings

  web-check:
    name: compat-web-check
    runs-on: [self-hosted]

    env:
      CARGO_TERM_COLOR: always

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          submodules: recursive

      - name: Setup Node.js
        uses: actions/setup-node@v5
        with:
          node-version: "22"

      - name: Enable pnpm
        run: |
          corepack enable
          corepack prepare pnpm@11.1.0 --activate

      # The Rust crate's `build.rs` skips the web build whenever
      # `LIBRA_SKIP_WEB_BUILD=1` (set on every other job for speed). This
      # dedicated job re-asserts that the Next.js source still type-checks,
      # lints, and produces a clean static export so `web/out/` cannot
      # silently drift away from `WebAssets` in main. Per
      # docs/improvement/web.md Phase 5 verification.
      - name: Install web dependencies
        run: pnpm --dir web install --frozen-lockfile

      - name: Lint web
        run: pnpm --dir web lint

      - name: Build web (static export → web/out/)
        run: pnpm --dir web build

  redundancy:
    name: compat-redundancy
    runs-on: [self-hosted]

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          submodules: recursive

      - name: Run redundancy check
        run: |
          x=$(find third-party/rust/crates -mindepth 2 -maxdepth 2 -type d -exec bash -c '
            n=$(find "$1" -maxdepth 1 -type f | wc -l)
            [ $n -gt 1 ]
          ' _ {} \; -print -quit | wc -l)
          if [ $x -gt 0 ]; then
            echo "❌ Redundant directories found"
            exit 1
          else
            echo "✅ All good"
            exit 0
          fi

  test:
    name: compat-offline-core

    runs-on: [self-hosted]

    env:
      CARGO_TERM_COLOR: always
      RUSTUP_TOOLCHAIN: stable
      LIBRA_SKIP_WEB_BUILD: "1"
      CARGO_PROFILE_TEST_DEBUG: "0"
      CARGO_BUILD_JOBS: "1"

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          submodules: recursive

      - name: Setup Node.js
        uses: actions/setup-node@v5
        with:
          node-version: "22"

      - name: Enable pnpm
        run: |
          corepack enable
          corepack prepare pnpm@11.1.0 --activate

      - name: Ensure ripgrep is available
        shell: bash
        run: |
          if command -v rg >/dev/null 2>&1; then
            rg --version
            exit 0
          fi

          if [ "$(id -u)" -eq 0 ]; then
            SUDO=""
          elif command -v sudo >/dev/null 2>&1; then
            SUDO="sudo"
          else
            SUDO=""
          fi

          if command -v apt-get >/dev/null 2>&1; then
            $SUDO apt-get update
            $SUDO apt-get install -y ripgrep
          elif command -v dnf >/dev/null 2>&1; then
            $SUDO dnf install -y ripgrep
          elif command -v yum >/dev/null 2>&1; then
            $SUDO yum install -y ripgrep
          elif command -v brew >/dev/null 2>&1; then
            brew install ripgrep
          else
            cargo install ripgrep --locked
            echo "${HOME}/.cargo/bin" >> "$GITHUB_PATH"
          fi

          command -v rg
          rg --version

      - name: Check compatibility matrix drift
        run: bash scripts/check_compat_matrix.sh

      - name: Run tests (L1 + L2 + L3)
        env:
          LIBRA_TEST_GITHUB_TOKEN: ${{ secrets.LIBRA_TEST_GITHUB_TOKEN }}
          LIBRA_TEST_GITHUB_NAMESPACE: ${{ secrets.LIBRA_TEST_GITHUB_NAMESPACE }}
          DEEPSEEK_API_KEY: ${{ secrets.DEEPSEEK_API_KEY }}
          LIBRA_D1_ACCOUNT_ID: ${{ secrets.LIBRA_D1_ACCOUNT_ID }}
          LIBRA_D1_API_TOKEN: ${{ secrets.LIBRA_D1_API_TOKEN }}
          LIBRA_D1_DATABASE_ID: ${{ secrets.LIBRA_D1_DATABASE_ID }}
          LIBRA_STORAGE_ENDPOINT: ${{ secrets.LIBRA_STORAGE_ENDPOINT }}
          LIBRA_STORAGE_BUCKET: ${{ secrets.LIBRA_STORAGE_BUCKET }}
          LIBRA_STORAGE_ACCESS_KEY: ${{ secrets.LIBRA_STORAGE_ACCESS_KEY }}
          LIBRA_STORAGE_SECRET_KEY: ${{ secrets.LIBRA_STORAGE_SECRET_KEY }}
        run: cargo test --all

      # Phase 6 — Local TUI Automation Control scenario suite (docs/improvement/tui.md).
      # Without `--features test-provider` + `LIBRA_ENABLE_TEST_PROVIDER=1`, the scenarios
      # in tests/code_ui_scenarios.rs and tests/harness_self_test.rs short-circuit; CI
      # would silently skip them. `--test-threads=1` because each scenario spawns a
      # `libra code` subprocess that contends for 0600 control-token files and ports.
      #
      # docs/improvement/test.md Wave 1 + Wave 3 also require the SSE harness and
      # lease matrix to run under the same gate, otherwise CI silently skips every
      # `lease_case!()` / `sse_case!()` registration.
      - name: Run TUI automation scenarios
        env:
          LIBRA_ENABLE_TEST_PROVIDER: "1"
          # These scenarios validate the loopback browser against the real
          # embedded Next.js app, so the build.rs fallback stub is not valid here.
          LIBRA_SKIP_WEB_BUILD: "0"
        run: |
          cargo test --features test-provider \
            --test code_ui_scenarios \
            --test harness_self_test \
            --test code_codex_default_tui_test \
            --test code_ui_remote_lease_matrix \
            --test code_ui_remote_sse_matrix \
            -- --test-threads=1

      - name: Upload TUI scenario artifacts on failure
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: code-ui-scenarios
          path: target/code-ui-scenarios/**
          if-no-files-found: ignore
          retention-days: 7

  network-remotes:
    name: compat-network-remotes
    runs-on: [self-hosted]

    env:
      CARGO_TERM_COLOR: always
      RUSTUP_TOOLCHAIN: stable
      LIBRA_SKIP_WEB_BUILD: "1"
      CARGO_PROFILE_TEST_DEBUG: "0"
      CARGO_BUILD_JOBS: "1"

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          submodules: recursive

      - name: Setup Node.js
        uses: actions/setup-node@v5
        with:
          node-version: "22"

      - name: Enable pnpm
        run: |
          corepack enable
          corepack prepare pnpm@11.1.0 --activate

      # Network-only test layer (`test-network` feature gate). Tests requiring outbound
      # network but no secrets are surfaced through this job; tests requiring real
      # credentials live behind `test-live-ai` / `test-live-cloud` and run only in
      # the `compat-live-*` (workflow_dispatch) jobs, which are intentionally not
      # GitHub required-checks.
      - name: Run network-remote tests
        run: cargo test --features test-network --test network_remotes_test -- --test-threads=1
