vipune 0.18.0

A minimal memory layer for AI agents
Documentation
name: CI

on:
  push:
    branches:
      - main
  pull_request:
  schedule:
    - cron: "0 6 * * *" # Nightly at 06:00 UTC

# Cache keys are keyed on the pinned model revisions (issue #217); the
# air-gapped/docs drift test in src/embedding.rs pins both keys against the
# profile revision constants — bump a key if and only if its revision changes.
env:
  HF_CACHE_KEY: hf-hub-bge-small-en-v1.5-5c38ec7
  HF_CACHE_KEY_E5: hf-hub-multilingual-e5-small-614241f

jobs:
  test:
    name: Test
    runs-on: ubicloud-standard-4

    steps:
      - uses: actions/checkout@v7

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        uses: actions/cache@v6
        with:
          path: ~/.cargo/registry
          key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo index
        uses: actions/cache@v6
        with:
          path: ~/.cargo/git
          key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo build
        uses: actions/cache@v6
        with:
          path: target
          key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache HuggingFace models
        uses: actions/cache@v6
        with:
          path: ~/.cache/huggingface/hub
          key: ${{ runner.os }}-${{ env.HF_CACHE_KEY }}

      - name: Format check
        run: cargo fmt --check

      - name: Clippy
        run: cargo clippy --locked --all-targets -- -D warnings

      - name: Test
        run: cargo test --locked

      - name: Test (ignored — requires model)
        if: github.event_name == 'schedule'
        run: cargo test --locked -- --ignored

      # Note: ONNX Runtime shared library is auto-downloaded during build
      # CI may need extra time on first run due to download

  test-no-default-features:
    name: Test (no default features)
    runs-on: ubicloud-standard-4

    steps:
      - uses: actions/checkout@v7

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        uses: actions/cache@v6
        with:
          path: ~/.cargo/registry
          key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo index
        uses: actions/cache@v6
        with:
          path: ~/.cargo/git
          key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo build
        uses: actions/cache@v6
        with:
          path: target
          key: ${{ runner.os }}-cargo-build-target-ndf-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache HuggingFace models
        uses: actions/cache@v6
        with:
          path: ~/.cache/huggingface/hub
          key: ${{ runner.os }}-${{ env.HF_CACHE_KEY }}

      - name: Clippy (no default features)
        run: cargo clippy --locked --no-default-features --all-targets -- -D warnings

      - name: Test (no default features)
        run: cargo test --locked --no-default-features

  # MSRV gate (issue #257). The declared `rust-version` in Cargo.toml is a
  # promise to users, and the default `mcp` feature pulls a dependency graph
  # (rmcp -> rmcp-macros -> darling 0.23) whose floor is far above that field
  # used to claim. Nothing here checked the declared version, so it rotted.
  # This job installs *exactly* the declared toolchain and checks BOTH feature
  # sets with --locked — the default set and `--no-default-features` — so a
  # dependency raising its own rust-version above the declaration reddens CI
  # instead of breaking user builds, whichever feature set they build.
  #
  # Both feature sets must build on 1.88. Keep the toolchain pin in sync with
  # `rust-version` in Cargo.toml, the minimum stated in README.md and the floor
  # in CONTRIBUTING.md — `test_msrv_version_pins_agree` locks all four together.
  msrv:
    name: MSRV
    runs-on: ubicloud-standard-4
    timeout-minutes: 30

    steps:
      - uses: actions/checkout@v7

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@master
        with:
          toolchain: 1.88.0

      - name: Cache cargo registry
        uses: actions/cache@v6
        with:
          path: ~/.cargo/registry
          key: ${{ runner.os }}-cargo-registry-msrv-1.88.0-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo build
        uses: actions/cache@v6
        with:
          path: target
          key: ${{ runner.os }}-cargo-build-target-msrv-1.88.0-${{ hashFiles('**/Cargo.lock') }}

      - name: Check (default features)
        run: cargo check --locked --all-targets

      - name: Check (no default features)
        run: cargo check --locked --no-default-features --all-targets

  # Dependency-advisory gate (issue #253). Runs on pull_request (and every push
  # to main) plus the nightly schedule above, so a newly published RustSec
  # advisory reddens the nightly even when nothing changed here. Kept separate
  # from the test jobs: it needs no target/ or HuggingFace cache and no compile,
  # so it reports in seconds. `--locked` checks the committed Cargo.lock — the
  # graph we actually ship — instead of a fresh resolution nobody runs.
  #
  # cargo-deny is pinned so the gate's verdict cannot change under us mid-PR;
  # bump it with `cargo deny --locked check advisories bans` run locally, since
  # a new release can tighten reporting and turn green red.
  deny:
    name: Dependency advisories
    runs-on: ubicloud-standard-4
    timeout-minutes: 10

    steps:
      - uses: actions/checkout@v7

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Install cargo-deny
        uses: taiki-e/install-action@v2
        with:
          tool: cargo-deny@0.20.2

      - name: Check advisories and denied features
        run: cargo deny --locked check advisories bans