Implements the Stable and Experimental JPA persistence platform designs against real PostgreSQL, adapted to this repository's fail-closed 19-leaf registry. The design models the platform as 25 Gradle projects. `src/settings.gradle` throws unless the registry holds exactly 19 leaves, so the plan's modules become packages inside `:adapter:outbound:persistence-jpa` (starter in `:app-bootstrap`, testkit in its own source set). The full mapping, the renames this repository's naming gate required, and every deliberate substitution are recorded in `docs/jpa/repository-adaptation.md`. Seven Docker-backed lanes replace the plan's seven JVM test suites. Each fails closed: a lane that discovers nothing, or a container that cannot start, is an error rather than a skip. Three defects the contracts found against a real server: - `CommitFailureClassifier` treated only SQLSTATE 40003, class 08, and transport breaks as completion-unknown. A backend terminated mid-commit reports 57P01, and the commit record may already be in the WAL — so a possibly-committed transaction could be re-run. 57P01/57P02/57P03 now classify as completion-unknown. - `SchemaTenantMigrationOrchestrator` recorded `MigrateResult`'s target version, which is empty for a tenant already current, reporting migrated tenants as unmigrated during a partial rollout. It now reads the applied version back from the tenant's schema history. - `JpaStreamExecutor` checked only the declared return type for reactive publishers, and `RegisteredPostgreSqlCopyLoader` passed the COPY timeout to `SET`, which is parsed before parameter binding. `JpaModuleBoundaryTest` enforces the plan's module map as package rules; `verifyCleanArchitectureDependencies` governs edges between leaves and cannot see these. Its first assertion is that the import is non-empty, because every rule under it is a `noClasses()` rule and would pass vacuously on an empty import. Verified: 128 container tests across all seven lanes, 1183 unit tests, `:adapter:outbound:persistence-jpa:check`, `:app-bootstrap:check`, `verifyCleanArchitectureDependencies`, `verifyOneTypePerFile`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
80 lines
3.6 KiB
Markdown
80 lines
3.6 KiB
Markdown
# JPA Persistence Platform — Support Matrix
|
|
|
|
The machine-readable source for `JpaReleaseManifest`. A release gate parses this file, so a version
|
|
or gate that stops being named here stops being claimed — and the build fails rather than the
|
|
document quietly drifting from the code.
|
|
|
|
## Database
|
|
|
|
| Database | Support | Evidence |
|
|
|---|---|---|
|
|
| PostgreSQL 16 | Stable | full contract suite, release lane |
|
|
| PostgreSQL 17 | Stable | full contract suite, release lane |
|
|
| PostgreSQL 18 | Stable | full contract suite, release lane |
|
|
| PostgreSQL 19 | Experimental | compatibility lane only; promotion requires an ADR |
|
|
| H2 | Local convenience | **never** evidence of PostgreSQL behaviour |
|
|
|
|
H2 is not a second production target. It reports different SQLSTATEs for the same violation, has no
|
|
`SKIP LOCKED` guarantee the platform relies on, no JSONB operators, no range types, and no
|
|
concurrent index builds. A green H2 run is evidence that the code compiles and runs, and nothing
|
|
more.
|
|
|
|
## Specification and provider
|
|
|
|
| Component | Stable | Experimental |
|
|
|---|---|---|
|
|
| Jakarta Persistence | 3.2 | 4.0 (lane) |
|
|
| Hibernate ORM | 7.4 declared baseline | 8 (lane) |
|
|
| Spring Boot | repository BOM | — |
|
|
|
|
The Hibernate row needs a note. The design declares 7.4 as the Stable provider; this repository's
|
|
Spring Boot BOM resolves 7.1.x. `HibernateProviderPolicy` holds both — the declared baseline as a
|
|
constant, the resolved version read from Hibernate itself — and `driftsFromDeclaredBaseline()` makes
|
|
the difference visible instead of asserting a constant against itself. See
|
|
[repository-adaptation.md](repository-adaptation.md) §4.
|
|
|
|
## Capability support levels
|
|
|
|
| Capability | Level |
|
|
|---|---|
|
|
| Full-transaction retry | Stable |
|
|
| Commit completion evidence | Stable |
|
|
| Keyset pagination | Stable |
|
|
| JDBC batch | Stable |
|
|
| Flyway schema gate | Stable |
|
|
| Runtime role verification | Stable |
|
|
| Observability | Stable |
|
|
| PostgreSQL native write (`ON CONFLICT`/`RETURNING`) | Advanced |
|
|
| PostgreSQL work claim (`SKIP LOCKED`) | Advanced |
|
|
| PostgreSQL JSONB | Advanced |
|
|
| PostgreSQL array and range | Advanced |
|
|
| Bulk DML | Advanced |
|
|
| Hibernate `StatelessSession` | Advanced |
|
|
| PostgreSQL `COPY` | Admin (J4) |
|
|
| Hibernate second-level cache | Advanced |
|
|
| Hibernate Envers | Advanced |
|
|
| Multi-tenancy (column, RLS, schema, database) | Experimental |
|
|
| Consistency-aware read replica | Experimental |
|
|
|
|
## Release gates
|
|
|
|
Each row is a way the platform could pass its tests and still be wrong in production.
|
|
|
|
| Gate | Kind | What it prevents |
|
|
|---|---|---|
|
|
| `postgresql-contract` | gate | a release whose only database evidence came from H2 |
|
|
| `completion-unknown-no-retry` | gate | automatically re-running a write that may already have committed |
|
|
| `osiv-disabled` | gate | lazy loading from the view layer, one query per rendered row |
|
|
| `flyway-validate` | gate | Hibernate mutating a deployed schema, or running against one it was not built for |
|
|
| `runtime-role-no-ddl` | gate | the application's own credential being able to alter or drop schema objects |
|
|
| `hibernate-7.4-fetch-pagination` | gate | a paged collection fetch silently reading the whole table and paginating in memory |
|
|
|
|
## Explicitly unsupported
|
|
|
|
- Reactive JPA. JPA is a blocking specification; a reactive facade over it moves the blocking call
|
|
onto an event loop rather than removing it.
|
|
- Hibernate as the production schema writer. `ddl-auto` never mutates a deployed schema.
|
|
- A platform-owned generic CRUD repository. Domains own their repositories (design §10.1).
|
|
- Automatic reconciliation of a completion-unknown transaction. The platform records; the domain
|
|
resolves.
|