Testing

CI verification

Set up continuous integration for a Vary project using GitHub Actions.

Verification profiles

The validate command bundles checks into profiles:

ProfileStagesTypical use
fastanalyze, static, testsLocal iteration
localanalyze, static, testsAlias for fast
cianalyze, static, tests, mutationPull request gate
nightlyanalyze, static, tests, mutation, oracleScheduled deep run

Run a profile:

vary validate src/ --profile ci

Cost of each stage

StageCostWhat it does
analyzeCheapStructural checks (dead code, style, lint rules)
staticCheapType checking and effect analysis
testsCheapRuns test blocks and test_*.vary/*_test.vary files
mutationMediumSource-level mutation testing, scales with test count
oracleExpensiveVAST corpus verification, generates and verifies broad test scenarios

Cheap stages finish in seconds for most projects. Mutation testing can take minutes. VAST/oracle verification takes longer and is best reserved for nightly or weekly runs.


PR workflow (GitHub Actions)

Runs on every pull request. Uses the ci profile: static analysis, type checking, tests, and mutation testing.

# .github/workflows/vary-pr.yml
name: Vary PR

on:
  pull_request:
    branches: [main]

jobs:
  verify:
    runs-on: ubuntu-latest
    timeout-minutes: 15

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '21'

      - name: Install Vary
        run: |
          curl -fsSL https://github.com/ccollicutt/vary/releases/latest/download/install.sh | sh
          echo "$HOME/.vary/bin" >> "$GITHUB_PATH"

      - name: Validate (CI profile)
        run: vary validate src/ --profile ci

      - name: Upload artifacts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: ci-artifacts
          path: .vary/runs/

What this covers:

StageWhat it catches
analyzeStructural lint checks
staticType errors, effect violations, service host authority
testsAll test blocks execute and pass
mutationMutation score meets configured threshold

Nightly workflow (GitHub Actions)

Runs the full verification suite including the VAST oracle stage. Schedule it during off-hours.

# .github/workflows/vary-nightly.yml
name: Vary Nightly

on:
  schedule:
    - cron: '0 3 * * *'  # 3 AM UTC daily
  workflow_dispatch:       # Allow manual trigger

jobs:
  verify:
    runs-on: ubuntu-latest
    timeout-minutes: 60

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '21'

      - name: Install Vary
        run: |
          curl -fsSL https://github.com/ccollicutt/vary/releases/latest/download/install.sh | sh
          echo "$HOME/.vary/bin" >> "$GITHUB_PATH"

      - name: Validate (nightly profile)
        run: vary validate src/ --profile nightly

      - name: Upload artifacts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: nightly-artifacts
          path: .vary/runs/

The oracle stage is the addition over PR CI. VAST corpus verification catches correctness issues that unit tests and mutation testing miss.


Custom profiles in vary.toml

Define project-specific profiles:

[profiles.pr-fast]
checks = ["check", "test"]
timeout = 300

[profiles.pr-fast.thresholds]
mutation_score = 60

[profiles.full]
checks = ["check", "test", "mutation", "oracle"]
timeout = 1800

[profiles.full.thresholds]
mutation_score = 80

Then reference them in CI:

vary validate src/ --profile pr-fast

Config profiles override built-in profiles of the same name, so you can customize ci or nightly for your project.


Production checklist

Minimum verification bar for a production Vary application:

AreaWhat to configure
Project layoutFollow the canonical structure with pure core separated from effectful boundaries
vary.tomlDefine [profiles.ci] and [profiles.nightly] with appropriate thresholds
PR gateRun vary validate --profile ci and block merge on failure
Nightly jobRun vary validate --profile nightly with VAST oracle verification
Service host authorityConfigure [services] in vary.toml if the app makes HTTP calls
Effect deny listConfigure [check.effects] to prevent unintended side effects in pure modules
Mutation thresholdAt least 60% for CI, 80% for nightly
Contract preconditionsin {} blocks on public API functions for input validation
Test coverageBoth unit tests (test blocks) and integration tests for service boundaries

Quick start

Generate a project with these defaults already configured:

vary new my-app --template serious

This scaffolds a project with vary.toml profiles, a GitHub Actions workflow, and the canonical directory structure.

← Testing