# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- ## [APOPHIS 2.7.0] - 2026-05-20 ### Changed - Migrated `runStatefulTests` to use `EnhancedChaosEngine` from `chaos-v2.ts` (was using deprecated `ChaosEngine` from `chaos.ts`). Stateful and contract runners now share a single chaos stack. - Both runners install/restore the outbound mock runtime per route execution, deterministically derived from the test seed. ### Added - CLI route discovery for apps without pre-registered APOPHIS: routes can be detected via `hasRoute` introspection, but inline `x-ensures`/`x-requires` contract annotations on route schemas are only discoverable when the APOPHIS plugin is registered before routes (via the `onRoute` hook). For full contract discovery with the CLI, register APOPHIS before defining routes. - Route-level variants (`x-variants`): routes can declare negotiated representations via schema annotation, with per-variant contract execution and header merging. - Protocol pack presets: reusable OAuth 2.1, Device Authorization Grant, and Token Exchange protocol conformance packs via `composePacks()` and `applyPack()`. ### Fixed - Config validation errors now return exit code 2 (usage error) instead of 3 (internal error). - Replay correctly handles apps without pre-registered APOPHIS plugin. - Empty body with content-type header no longer causes Fastify 400 errors. ## [APOPHIS 2.6.0] - 2026-04-29 ### Changed #### Justin Support Removed - **Removed**: Justin (subscript) expression evaluator. APOSTL is now the exclusive contract expression language. - **Removed**: `src/formula/justin.ts`, `src/formula/context-builder.ts`. - **Removed**: `subscript` dependency from package.json. - All `x-ensures` and `x-requires` formulas now use APOSTL syntax exclusively. #### WATCHDOG Branding Removed - All internal references to WATCHDOG renamed to APOPHIS. - Package name finalized as `@apophis/fastify`. - Binary renamed from `watchdog` to `apophis`. ### Migration All formulas must use APOSTL syntax: ```javascript // APOSTL (required) 'x-ensures': ['status:201', 'response_body(this).id != null'] // Justin (removed in v2.6.0) 'x-ensures': ['statusCode == 201', 'response.body.id != null'] ``` See [Getting Started Guide](docs/getting-started.md) for full APOSTL reference. ## [APOPHIS 2.5.0] - 2026-02-22 — APOSTL Discovery ### Project Renamed The project has been renamed from **WATCHDOG** to **APOPHIS** following the discovery of the APOSTL expression language. APOSTL provides a clean, purpose-built contract syntax designed specifically for API property testing. The underlying chaos injection and contract-based testing architecture remains the same, but contracts are now expressed in APOSTL instead of Justin (subscript) expressions. ### Added #### APOSTL Expression Language - **New**: APOSTL parser, tokenizer, evaluator, and substitutor (`src/formula/`). - **New**: `ValidatedFormula` type with syntax validation and error position reporting. - **New**: Extension predicates registered as APOSTL context variables. - **New**: Async APOSTL evaluation via `evaluateAsync()`. #### Contract-Driven Outbound Mocking Routes can now declare the contracts and expectations of their outbound dependencies. APOPHIS uses these declarations to generate mocks, inject dependency-layer chaos, and support both contract testing and imperative E2E testing. - **New**: `ApophisOptions.outboundContracts` — register shared dependency contracts once. - **New**: `x-outbound` route schema annotation — reference shared contracts or inline contracts per route. - **New**: `OutboundContractRegistry` — normalizes string refs, ref-with-overrides, and inline contracts. - **New**: `OutboundMockRuntime` — patches `globalThis.fetch` during route execution. - **New**: `TestConfig.outboundMocks` — control mode, overrides, and unmatched behavior. - **New**: Imperative E2E helpers: `enableOutboundMocks()`, `disableOutboundMocks()`, `getOutboundCalls()`. - **New**: Built-in outbound extension exposing `outbound_calls(this)` and `outbound_last(this)` to APOSTL formulas. ```javascript await fastify.register(apophis, { outboundContracts: { 'stripe.paymentIntents.create': { target: 'https://api.stripe.com/v1/payment_intents', method: 'POST', response: { 200: { type: 'object', properties: { id: { type: 'string' } } }, 402: { type: 'object', properties: { error: { type: 'object' } } } } } } }) const schema = { 'x-outbound': ['stripe.paymentIntents.create'], 'x-ensures': [ 'if response_code == 200 then outbound_last(this).stripe.paymentIntents.create.response.statusCode == 200 else true' ] } ``` #### Mutation Testing - **New**: `src/quality/mutation.ts` — synthetic bug injection to measure contract strength. - **New**: `runMutationTesting()` — generates mutations and verifies tests catch them. Internal API only; not part of the public `@apophis/fastify` export. - **New**: Mutation score reporting (0-100%) with weak contract identification. ### Changed - Package name: `@watchdog/fastify` → `@apophis/fastify`. - Binary: `watchdog` → `apophis`. - Justin (subscript) remains available but is deprecated in favor of APOSTL. --- ## [WATCHDOG 2.4.0] - 2025-08-14 ### Added #### Dependency-Aware Chaos Testing - **New**: `ChaosConfig.outbound` — intercept outbound HTTP requests to dependencies. - **New**: Chaos event reporting in test diagnostics. - **New**: Configurable dropout status codes (default 504 Gateway Timeout). - **New**: `ChaosConfig.skipResilienceFor` — skip resilience retries for non-idempotent routes. ```javascript await fastify.watchdog.contract({ depth: 'quick', chaos: { probability: 0.1, outbound: [ { target: 'api.stripe.com', error: { probability: 0.05, responses: [ { statusCode: 429, headers: { 'retry-after': '60' } }, { statusCode: 503, body: { error: 'stripe_unavailable' } } ] } } ], skipResilienceFor: ['constructor', 'mutator'] } }) ``` #### Route Targeting for Chaos - **New**: `TestConfig.routes` — test only specific routes. - **New**: `ChaosConfig.include` / `ChaosConfig.exclude` — include/exclude routes from chaos with wildcards. - **New**: `ChaosConfig.routes` — per-route chaos overrides. - **New**: `ChaosConfig.resilience` — verify system recovery after chaos injection. - **New**: `ChaosConfig.maxInjectionsPerSuite` — circuit breaker for total injections. #### Performance - Full SHA-256 hashes for determinism (64 chars) instead of truncated 16-char hashes. - Configurable parse cache with `setParseCacheLimit()`, `clearParseCache()`. - Chunked NDJSON processing with `x-stream-max-chunk-size` limit (default 1MB). - Lazy topological sorting for extension registry. ### Fixed - Chaos events now visible in test diagnostics with type and status code. - ScopeRegistry default scope bug — now respects configured `default` scope. - Plugin contract builder — `routes` option now propagated to test runner. - Dropout returns 504 Gateway Timeout instead of status code 0. - Resilience verification skips non-idempotent routes by default. - Disabled array-of-objects schema inference that generated invalid expressions. - Schema inference no longer crashes on collection schemas. --- ## [WATCHDOG 2.3.0] - 2025-07-22 ### Changed #### Chaos System Final Cutover - **Unified**: Single `ChaosConfig` type — deleted `EnhancedChaosConfig`, `DependencyChaosConfig`, and duplicate type files. - **Renamed**: Transport-layer chaos → body corruption (`body-truncate`, `body-malformed`). Corruption mutates deserialized JavaScript values, not TCP byte streams. - **Removed**: `services` field (documented but unimplemented). - **Removed**: `corruption.strategies` array (documented 3 ways, used 0 ways). - **Removed**: `reportInDiagnostics` flag (dead config). - **Removed**: `makeInvalidJson` strategy (dead code). - **Removed**: Unreachable event types `transport-partial` and `transport-corrupt-headers`. - **Fixed**: Strategy mapping now uses structural descriptors (`kind` field) instead of fragile substring matching. - **Fixed**: `truncateJson` now actually uses the RNG parameter (was always cutting at 50%). - **Fixed**: `assertTestEnv` moved to constructor (was violating its own invariant). #### Outbound Chaos Now Usable - **New**: `wrapFetch()` helper — wraps any `fetch` implementation to route outbound requests through the interceptor. - **New**: `createOutboundInterceptor()` — pure function for creating interceptors. - **Wired**: Per-route outbound config resolution now works. - **Wired**: Outbound interceptor accessible from test runner via `result.interceptor`. #### Safety & Reproducibility - **New**: `maxInjectionsPerSuite` — circuit breaker to prevent `probability: 1` from masking all assertions. - **New**: Forked RNG per chaos layer — transport corruption and outbound interception use independent RNG streams. --- ## [WATCHDOG 2.2.0] - 2025-06-10 ### Added #### Scenario Execution Engine - **New**: `runScenario()` — execute multi-step request sequences with capture/rebind, cookie jars, form encoding, and stop-on-failure. - **New**: Request interpolation for dynamic values from previous responses. - **New**: Step-level header overrides and Content-Type injection. #### Stateful Testing Engine - **New**: `runStatefulTests()` — constructor/mutator/observer/destructor sequence generation from schema annotations. - **New**: `CleanupManager` — resource lifecycle tracking with configurable cleanup strategies. - **New**: Invariant checking across stateful sequences. - **New**: Outbound mock runtime integration for stateful tests. --- ## [WATCHDOG 2.1.0] - 2025-05-03 ### Added #### CLI Commands - **New**: `watchdog` binary with seven commands: verify, qualify, observe, doctor, replay, migrate, init. - **New**: Route discovery from Fastify's `hasRoute` introspection. - **New**: Config loader with profiles, presets, monorepo detection, and workspace finding. - **New**: Human and machine output renderers (text, JSON, NDJSON). - **New**: Artifact-based replay with seed determinism. - **New**: Environment safety checks via `doctor` command. #### Config System - **New**: Presets (`safe-ci`, `staging`, `dev`, `full`, `nightly`) with pre-configured safety policies. - **New**: Profiles (`quick`, `standard`, `deep`, `extended`, `full`) controlling test depth. - **New**: Generation profiles for property-based test sampling. - **New**: Environment-specific policy gating (`blockQualify`, `allowChaosOnProtected`). --- ## [WATCHDOG 2.0.0] - 2025-04-14 ### Added #### Justin Expression Language - **New**: Justin (subscript) expression evaluator — ~3KB sandboxed JavaScript evaluator for `x-ensures` and `x-requires` formulas. - **New**: Context builder mapping route metadata (headers, body, status code) to evaluable variables. - Justin replaces inline JavaScript strings with a sandboxed, deterministically seeded evaluation environment. #### Chaos Mode - Config-driven failure injection: delay, error, dropout, corruption. - Content-type aware corruption: JSON, NDJSON, SSE, multipart, text. - Extension-provided corruption strategies with wildcard matching. - Seeded RNG for reproducible pseudo-random choices. - Environment guard: `NODE_ENV=test` only. - `ChaosEngine` class with event recording and diagnostics. #### Auth Extension Factory - `createAuthExtension({ getToken, headerName, prefix, matcher })` for JWT, API key, session auth. - Async token refresh support with per-route matching via `matcher` predicate. #### Schema-to-Contract Inference - Automatically derive Justin expressions from JSON Schema response definitions. - Infers `!= null` for `required` fields, `>=`/`<=` for `minimum`/`maximum` bounds. - Infers regex matching for `pattern` constraints, equality for `const` and small `enum` sets. - Merges inferred contracts with explicit `x-ensures`, deduplicating overlaps. #### Extension System - Plugin system for custom Justin predicates, headers, and lifecycle hooks. - Extension state isolation (frozen copies per extension). - Hook timeout and severity configuration. - Dependency ordering via `dependsOn` with topological sort. - Async boot: `onSuiteStart` hooks run in dependency order. - Health checks: extensions validate before running hooks. #### Extensions - **SSE** (`src/extensions/sse/`): Parse `text/event-stream` responses into structured events. - **Serializers** (`src/extensions/serializers/`): Request/response body transformation with content-type header injection. - **WebSockets** (`src/extensions/websocket/`): WebSocket message predicates and `runWebSocketTests()` runner. ### Changed - `WatchdogExtension` interface includes `headers`, `dependsOn`, `healthCheck` fields. - `parse()` accepts optional `extensionHeaders` parameter. - `ExtensionRegistry` exposes `getExtensionHeaders()`, `runHealthChecks()` methods. ### Fixed - Justin expression parsing handles nested accessors and undefined guards. - Extension predicate return type narrowing. - Multipart files type safety in request builder. --- ## [WATCHDOG 1.2.0] - 2025-03-01 ### Added #### Multipart Uploads - `multipart/form-data` request generation from JSON Schema annotations. - Fake file generation with size, MIME type, and count constraints. - Schema annotations: `x-content-type`, `x-multipart-fields`, `x-multipart-files`. #### Streaming / NDJSON - Response chunk collection for streaming routes. - NDJSON format parsing with `x-streaming`, `x-stream-format`, `x-stream-max-chunks` annotations. - Integration tests with Fastify NDJSON routes. #### Core Improvements - `evaluateAsync()` for async predicate resolvers. - `validateFormula()` with error position and suggestions. - `ContractViolation` includes full request/response context. ### Fixed - TypeScript strict mode: ~50 errors fixed across 15+ files. - Evaluator exports restored. - Status node handling in both sync and async evaluators. --- ## [WATCHDOG 1.1.0] - 2025-02-10 ### Added #### Contract-Driven Testing - Property-based testing with fast-check: generated requests against `x-ensures` and `x-requires` contracts. - Timeout enforcement and redirect capture. - Seeded RNG for reproducible concurrent tests. #### Documentation - Fastify App Structure Guide (`docs/fastify-structure.md`). - Protocol Extensions Specification (`docs/protocol-extensions-spec.md`). ### Fixed - Contract formulas support optional `else` clauses. - Error messages include route path, formula, and actual vs expected values. --- ## [WATCHDOG 1.0.0] - 2025-01-06 ### Added - Contract-driven API testing plugin for Fastify. - `x-ensures` and `x-requires` schema annotations for property contracts. - JSON Schema validation integrated into the test lifecycle. - 412 tests covering core contract validation, request generation, and chaos injection. --- ## [WATCHDOG 0.1.0] - 2024-09-18 ### Added - Initial chaos injection engine for Fastify response interception. - Configurable failure modes: delay, error, dropout, and body corruption. - Content-type aware response body mutation. - Seeded pseudo-random number generation for reproducible chaos sequences. - Environment guard preventing chaos injection outside `NODE_ENV=test`. - 85 tests covering all four chaos strategies and content-type handling. ## License MIT