# APOPHIS Behavioral confidence for Fastify services. APOPHIS checks whether route behavior holds across operations, states, and protocol flows. Inspired by the concept of invariant-driven automated testing: instead of only checking payload shape, APOPHIS encodes intended behavior as executable contracts and verifies them with property-based and stateful testing. Supported Node.js versions: >=20.18.1 (20.x) and 22.x. ```bash npm install @apophis/fastify fastify @fastify/swagger npx apophis init --preset safe-ci npx apophis verify --profile quick --routes "POST /users" ``` `x-ensures` is an OpenAPI schema extension for behavioral contracts — statements about what a route must guarantee. ## Cross-Route Failure Example Add one behavioral contract next to a route schema. APOPHIS can verify cross-route behavior, such as whether a resource created by one route is retrievable through another. **Route:** ```javascript import crypto from 'crypto'; app.post('/users', { schema: { 'x-category': 'constructor', 'x-ensures': [ // BEHAVIORAL: Creating a user must make it retrievable 'response_code(GET /users/{response_body(this).id}) == 200' ] } }, async (request, reply) => { const { name } = request.body; const id = `usr-${crypto.createHash('sha256').update(name).digest('hex').slice(0, 8)}`; reply.status(201); return { id, name }; }); ``` **APOPHIS output:** ```text Contract violation POST /users Profile: quick Seed: 42 Expected response_code(GET /users/{response_body(this).id}) == 200 Observed GET /users/usr-7d865e 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}. ``` JSON Schema cannot express this relationship. APOPHIS turns it into an executable check. ## Three Modes | Mode | Purpose | Default Environments | |---|---|---| | `verify` | Deterministic CI and local contract verification | local, test, CI | | `observe` | Programmatic runtime visibility and drift detection without blocking (validated via `doctor --mode observe`) | staging, prod | | `qualify` | Exercise scenarios, stateful flows, and configured chaos checks before release | local, test, staging | ## Quickstart ```bash # 1. Install npm install @apophis/fastify fastify @fastify/swagger # 2. Scaffold npx apophis init --preset safe-ci # 3. Verify npx apophis verify --profile quick --routes "POST /users" # 4. Doctor npx apophis doctor ``` See [docs/getting-started.md](docs/getting-started.md) for the full walkthrough. ## Trust and Safety - **Deterministic replay**: Every failure includes a seed and a one-command replay. - **Explicit test budget**: Control how many tests run with `runs: 10` in your preset. - **CI-safe default path**: `verify` is deterministic and safe for CI pipelines. - **Machine-readable output**: `--format json-summary` and `--format ndjson-summary` for CI dashboards. - **Production-safe observe path**: `observe` is the programmatic runtime plugin (no CLI command). Non-blocking by default. Blocking behavior requires explicit break-glass policy. - **Qualify path gated away from prod**: `qualify` is blocked in production by default. - **Monorepo workspace support**: `--workspace` fans out `verify` and `doctor` across all packages. - **Explicit environment boundaries**: Config rejects unknown keys and unsafe environment mixes. ## LLM-Safe APOPHIS gives coding agents a constrained, repeatable way to encode and verify behavior: - Official scaffolds (`safe-ci`, `llm-safe`, `platform-observe`, `protocol-lab`) - `apophis doctor` checks for missing dependencies, malformed config, and unsafe modes - CI policy guards catch unknown keys, unsafe environments, and missing seeds - Generated code follows the same pattern in every repo See [docs/llm-safe-adoption.md](docs/llm-safe-adoption.md) for templates and CI policy. ## Full Documentation - [Getting Started](docs/getting-started.md) — First route, first verify run, first replay - [CLI Reference](docs/cli.md) — All 6 commands, global flags, exit codes - [Verify Mode](docs/verify.md) — Deterministic contract verification - [Observe Mode](docs/observe.md) — Runtime visibility and drift detection - [Qualify Mode](docs/qualify.md) — Scenarios, stateful testing, chaos - [Quality Engines](docs/quality.md) — Chaos injection, flake detection, mutation testing - [Performance](docs/performance.md) — Repeatable benchmarks and CPU profiling - [LLM-Safe Adoption](docs/llm-safe-adoption.md) — Scaffolds and CI guards - [Protocol Extensions](docs/attic/protocol-extensions-spec.md) — JWT, X.509, SPIFFE, WIMSE ## Recommended Integration **New projects:** Use `createFastify()` to ensure route discovery is installed before any routes are registered. ```ts import { createFastify } from '@apophis/fastify' const app = await createFastify({ logger: true, apophis: { runtime: process.env.NODE_ENV === 'test' ? 'error' : 'off', observe: process.env.NODE_ENV === 'production' ? { enabled: true, sampling: 0.1, sinks: [metricsSink] } // your ObserveSink : undefined, }, }) // Register swagger, auth, plugins, and routes after app creation. ``` **Existing projects:** Register APOPHIS or install route discovery before routes. Run `apophis doctor` to verify routes are discovered with full schema metadata. **Schema-less fallback:** If APOPHIS is registered after routes, `printRoutes()` can recover paths but not route schemas or behavioral contracts. `apophis doctor` and `apophis verify` will warn when discovery is schema-less. ## Current Limitations These reflect current implementation behavior. All are actively tracked for improvement. - **Route discovery requires ordering.** If the APOPHIS plugin or route discovery hook is not installed before routes are registered, behavioral contract annotations (x-ensures, x-requires, x-outbound, x-variants, x-timeout) cannot be recovered. Use `createFastify()` for new projects or register APOPHIS early. - **Observe is programmatic.** Register `apophisPlugin` with `observe: { enabled: true, sinks: [...] }` for non-blocking contract evaluation on live traffic. Use `apophis doctor --mode observe` to validate config before deploying. See `docs/observe.md`. - **CLI verify samples once per contract by default.** Set `runs` in your preset to increase the number of property-based test samples per route. The programmatic `fastify.apophis.contract()` API supports the same `runs` configuration. - **Outbound mocks are scoped per async context.** Uses `AsyncLocalStorage` so concurrent tests get isolated mock runtimes. No process-global lock. - **Qualify coverage depends on profile configuration.** Qualify runs scenario, stateful, and chaos checks based on profile gates. Chaos route selection uses the configured strategy (one/all/sample/routes). ## Compatibility - **Fastify v5 only.** Fastify v4 and earlier are not supported. - **ESM only.** This package is `"type": "module"` and does not provide a CommonJS build. Use `import` syntax. - **Node.js `>=20.18.1 <21 || >=22 <23`**. - **`@fastify/swagger` must be registered before routes** (APOPHIS auto-registers it if missing). ## License MIT