Files
apophis-fastify/docs/verify.md
T
John Dvorak d0523fcc2d fix: harden engine, enrich failure diagnostics, close adoption gaps
- P0: CLI verify now honors  test budget with seeded multi-sample
- P0: Observe sampling enforced via Math.random() gate in hook-validator
- P1: Remove misleading undici-mock-agent isolation option
- P1: Qualify reuses shared discoverRouteDetails() with warnings
- P1: Chaos/scenario config exposed via preset schema
- P1: README/docs limitations updated to current state
- P2: Nested response annotations prefer 2xx deterministically
- P2: --changed documented as heuristic in verify.md

- Add observe sink tests (sampling 0/1, sink failure non-interference)
- Add verify runs regression tests (scale, determinism, variants)
- Add configured-scenario qualify test (independent of OAuth fixture)
- Add coverageBreakdown to qualify artifacts (per-gate route coverage)
- Add production-style observe example with real sink in docs/observe.md
- Add nightly/staging vs PR gating guidance to docs/qualify.md

- Enrich VerifyFailure with formula-aware diagnostics:
  status:201 => 'HTTP 200', body field checks => actual values
- Remove stale observe CLI activation message
- Document outbound mocks as process-global in getting-started.md
- Refresh APOPHIS_ADOPTION_AUDIT.md with current state

903 tests pass, build clean, typecheck clean.
2026-05-21 20:39:36 -07:00

4.7 KiB

Verify Mode

Deterministic contract verification for CI and local development.

APOPHIS implements invariant-driven testing: encode intended behavior as executable formulas, then verify them automatically with property-based generation and deterministic replay.

When to Use It

  • Local development: Quick feedback on behavioral changes
  • CI pipelines: Catch regressions before merge
  • Pre-commit hooks: Fast smoke verification

Profile Examples

Quick (local smoke)

profiles: {
  quick: {
    name: 'quick',
    mode: 'verify',
    preset: 'safe-ci',
    routes: ['POST /users']
  }
}

CI (PR checks)

profiles: {
  ci: {
    name: 'ci',
    mode: 'verify',
    preset: 'safe-ci',
    routes: []
  }
}

Run with: apophis verify --profile ci --changed

Deep (nightly verification)

profiles: {
  deep: {
    name: 'deep',
    mode: 'verify',
    preset: 'safe-ci',
    routes: []
  }
}

Route Filtering

Filter routes with the --routes flag:

# Single route
apophis verify --routes "POST /users"

# Multiple routes (comma-separated)
apophis verify --routes "POST /users,PUT /users/:id"

# Wildcards
apophis verify --routes "POST /users/*"

# All routes (empty or omitted)
apophis verify --profile quick

* and ? wildcards are supported in --routes.

--changed Flag

Run only routes modified in the current git branch:

apophis verify --profile ci --changed

If no routes changed, exits 2 with a message.

--changed is a heuristic: it maps changed file paths to routes by checking route path segments against file names. This is useful as a developer convenience, but for strict CI gating, prefer explicit --routes filters or full verification.

Failure Output Format

When a contract fails, APOPHIS prints:

Contract violation
POST /users
Profile: quick
Seed: 42

Expected
  response_code(GET /users/{response_body(this).id}) == 200

Observed
  GET /users/usr-123 returned 404

Why this matters
  The resource created by POST /users is not retrievable.

Replay
  apophis replay --artifact reports/apophis/failure-2026-04-28T12-30-22Z.json

Next
  Check the create/read consistency for POST /users and GET /users/{id}.

Replay Workflow

  1. Copy the replay command from failure output
  2. Run it with the recorded route, seed, and artifact data; source or dependency drift can change the outcome
  3. Fix the bug in your handler
  4. Re-run verify to confirm the fix
apophis replay --artifact reports/apophis/failure-2026-04-28T12-30-22Z.json

Nondeterminism warnings appear in output when the same seed produces different results across runs. This indicates stateful behavior in your application that contracts cannot control.

Machine Output for CI

Use concise formats to reduce log volume in large verify runs:

  • --format json-summary — single JSON with summary, failures, warnings. Omits per-step traces.
  • --format ndjson-summary — three NDJSON lines: run.started, run.summary, run.completed.

Filtering examples

# Extract only failed routes from full ndjson
# Note: route.failed events are only emitted for failures, not passed routes
apophis verify --profile quick --format ndjson | jq 'select(.type == "route.failed")'

# Write artifact to disk and parse the file instead of stdout
apophis verify --profile quick --format json --artifact-dir reports/apophis

Exit Codes

Code Meaning
0 All contracts passed
1 One or more behavioral contracts failed
2 Config error, no routes matched, no contracts found, or not a git repo
3 Internal APOPHIS error
130 Interrupted (SIGINT)

Config Example

// apophis.config.js
export default {
  profile: 'quick',
  profiles: {
    quick: {
      mode: 'verify',
      preset: 'safe-ci',
      routes: ['POST /users']
    }
  },
  presets: {
    'safe-ci': {
      runs: 10,
      timeout: 5000
    }
  }
};

For the full config schema, see CLI Reference.

Workspace Support

Run verify across all packages in a monorepo workspace:

apophis verify --workspace --profile quick --format json

Output includes per-package pass/fail summaries. Fails if any package fails.

Test Budget

The runs field in your preset controls how many property-based test samples execute per route. Default is 50. Lower for faster CI feedback, higher for deeper exploration:

profiles: {
  quick: {
    mode: 'verify',
    preset: 'safe-ci',
    routes: ['POST /users']
  }
},
presets: {
  'safe-ci': {
    runs: 10,
    timeout: 5000
  }
}

CLI verify generates one property-based test sample per contract by default when no runs is specified. Set runs in the preset to increase sampled inputs per route.