109 lines
5.8 KiB
Markdown
109 lines
5.8 KiB
Markdown
# JPA Persistence Platform — Support Matrix
|
|
|
|
**This document is a rendering. The machine-readable source is
|
|
[`src/config/jpa/release-registry.json`](../../src/config/jpa/release-registry.json).**
|
|
|
|
`JpaReleaseManifest` used to parse this file with regular expressions: every `PostgreSQL NN` it
|
|
mentioned became a supported version, whatever table or sentence produced the match. An Experimental
|
|
major joined the Stable list, a version named once in prose counted as supported, and demoting a
|
|
major changed nothing so long as the string survived somewhere in the document. Now the registry
|
|
declares a support level per major as a field, each gate names the Gradle task that produces its
|
|
evidence, and this document describes what the registry says.
|
|
|
|
## Database
|
|
|
|
| Database | Support | Evidence |
|
|
|---|---|---|
|
|
| PostgreSQL 16 | Stable | full contract suite, release lane (own matrix job) |
|
|
| PostgreSQL 17 | Stable | full contract suite, release lane (own matrix job) |
|
|
| PostgreSQL 18 | Stable | full contract suite, release lane (own matrix job) |
|
|
| PostgreSQL 19 | Experimental | compatibility lane only; promotion requires an ADR |
|
|
| H2 | Local convenience | **never** evidence of PostgreSQL behaviour |
|
|
|
|
Each major gets its **own release job**, because for a while it did not. The release lane passed
|
|
`-Pjpa.matrix.versions=16,17,18` to a `JpaPlatformContractSupport.start()` that used
|
|
`selectedVersions().get(0)`, so the whole integration suite ran against PostgreSQL 16 and this table
|
|
recorded 17 and 18 as fully covered on the strength of a three-assertion smoke test. `start()` now
|
|
refuses a multi-version selection outright, `jpa-release.yml` fans out to one job per major, and a
|
|
promotion job requires all three majors' evidence to carry the same commit SHA — so a removed major
|
|
removes the release, not the evidence for it.
|
|
|
|
**Provider baseline.** The gates run against the Hibernate version the Spring Boot BOM resolves —
|
|
**7.1.8.Final** — which the registry records as `stable-tested-baseline`. This document previously
|
|
called 7.4 the Stable baseline and the pagination gate was named `hibernate-7.4-fetch-pagination`,
|
|
so every run of that gate produced evidence labelled with a provider it had never executed against.
|
|
7.4 is recorded as `compatibility-target`; it becomes the baseline when a full lane has actually run
|
|
on it.
|
|
|
|
H2 is not a second production target. It reports different SQLSTATEs for the same violation, 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.
|
|
|
|
`SKIP LOCKED` needs its own sentence, because two documents said different things about it. The
|
|
module's `CLAUDE.md` records a measurement: H2 2.4.240 accepts `FOR UPDATE SKIP LOCKED` and does
|
|
genuinely skip locked rows, which is why the outbox claim SQL is identical on both vendors. This
|
|
document previously said H2 has no such guarantee. Both are right about different questions, and
|
|
the distinction is the point: **observed behaviour in the version we measured is not a production
|
|
guarantee, and it is never PostgreSQL contract evidence.** The measurement is why the claim SQL
|
|
needs no vendor branch; the absence of a guarantee is why every concurrency contract still runs
|
|
against a real PostgreSQL.
|
|
|
|
## 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 |
|
|
| `collection-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.
|