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

## Verification profiles

The `validate` command bundles checks into profiles:

| Profile   | Stages                                       | Typical use         |
|-----------|----------------------------------------------|---------------------|
| `fast`    | analyze, static, tests                       | Local iteration     |
| `local`   | analyze, static, tests                       | Alias for `fast`    |
| `ci`      | analyze, static, tests, mutation             | Pull request gate   |
| `nightly` | analyze, static, tests, mutation, oracle     | Scheduled deep run  |

Run a profile:

```bash
vary validate src/ --profile ci
```

### Cost of each stage

| Stage      | Cost    | What it does                                        |
|------------|---------|-----------------------------------------------------|
| `analyze`  | Cheap   | Structural checks (dead code, style, lint rules)    |
| `static`   | Cheap   | Type checking and effect analysis                   |
| `tests`    | Cheap   | Runs `test` blocks and `test_*.vary`/`*_test.vary` files |
| `mutation` | Medium  | Source-level mutation testing, scales with test count |
| `oracle`   | Expensive | VAST 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-action
# .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:

| Stage | What it catches |
|-------|----------------|
| `analyze` | Structural lint checks |
| `static` | Type errors, effect violations, service host authority |
| `tests` | All `test` blocks execute and pass |
| `mutation` | Mutation score meets configured threshold |

---

## Nightly workflow (GitHub Actions)

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

```github-action
# .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:

```toml
[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:

```bash
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:

| Area | What to configure |
|------|-------------------|
| Project layout | Follow the [canonical structure](/docs/project-layout/) with pure core separated from effectful boundaries |
| `vary.toml` | Define `[profiles.ci]` and `[profiles.nightly]` with appropriate thresholds |
| PR gate | Run `vary validate --profile ci` and block merge on failure |
| Nightly job | Run `vary validate --profile nightly` with VAST oracle verification |
| Service host authority | Configure `[services]` in `vary.toml` if the app makes HTTP calls |
| Effect deny list | Configure `[check.effects]` to prevent unintended side effects in pure modules |
| Mutation threshold | At least 60% for CI, 80% for nightly |
| Contract preconditions | `in {}` blocks on public API functions for input validation |
| Test coverage | Both unit tests (`test` blocks) and integration tests for service boundaries |

### Quick start

Generate a project with these defaults already configured:

```bash
vary new my-app --template serious
```

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