# ADR-JPA-005 — Contracts run against real PostgreSQL - Status: Accepted - Date: 2026-08-11 - Design: §40 ## Context An in-memory database makes tests fast and hermetic. A container makes them slow and requires Docker. ## Decision Every persistence contract runs against real PostgreSQL 16, 17, and 18 in containers. H2 remains a local-development convenience and never satisfies a contract. The lanes fail closed when Docker is absent rather than skipping. ## Consequences The behaviours these contracts verify either do not exist in H2 or differ there: SQLSTATE values for the same violation, `FOR UPDATE SKIP LOCKED` semantics, JSONB operators, range types, concurrent index builds, `search_path` privileges, and the generated SQL for a paged collection fetch. A green H2 run is evidence that the code compiles and runs — not that any of the above holds. Three versions rather than one because the platform claims three. A contract suite that ran only on 16 would make "Stable on 17 and 18" an assumption. Skipping on missing Docker is the failure mode this decision most wants to avoid: a skipped contract reports success, and CI eventually inherits that silence. `PostgreSqlContainerFactory.assertDockerAvailable()` throws instead. The cost is that the contract lanes need Docker and take minutes. The unit lane stays hermetic and fast, and is where most tests live; the container lanes verify the things only a real server can answer. ## Enforcement `PostgreSqlVersion.stable()`; `PostgreSqlContainerFactory`; release gate `postgresql-contract`.