v0.22.1 — assigned primary keys are required on create (coordinated PATCH)
Coordinated PATCH — npm 0.22.1 · PyPI 0.22.1 · NuGet 0.22.1 · Maven Central 7.22.1.
Completes v0.22.0's assigned-primary-key fix in the ports that shared its semantic half. npm and NuGet are version-parity bumps — TypeScript shipped the fix in 0.22.0, C# never had the defect, and neither port's published surface changed.
Fixed — an assigned primary key is required on create (Python, Java, Kotlin)
Generated-output change — regenerate to pick it up; three-way merge preserves hand edits.
An entity whose primary key carries no identity.primary @generation — a natural key, or an id issued by something upstream — had its create shape read the key's optionality off @required, like any other field. A key not marked @required was therefore optional in the generated create/validation artifact, so a create body carrying no primary key at all was accepted and could only fail at the database.
An assigned key with no @default is now required in Python's <Entity>Create Pydantic model, Java's <Entity>Dto (@NotNull) and Kotlin's generated data class (a non-null property, so a body omitting it cannot bind).
Unchanged: an increment/uuid key stays optional or omitted entirely (the server supplies it), and a key carrying a @default stays optional (the column has that default). In Kotlin the TPH-base and derived-read-only arms still force nullable.
C# was already correct — its DTO predicate treats any primary-key field as required. It was initially mis-reported as affected by reading RequiredCreateKeys in the routes generator, which is the raw-JSON presence check: a different tier with a different answer. The corpus settled it.
Added — the corpus can now see it
fixtures/validation-conformance/ gains a second entity, Ledger, whose primary key is assigned, plus assigned-pk-present / assigned-pk-missing. cases.json entries take an optional entity key (absent means Account), and all five runners dispatch on it.
The corpus was structurally blind here: Account's key is @generation: increment, which every port drops from the create shape entirely, so no existing case could express the opposite. More generally, every model in this repository generates its primary keys — which is why a defect present in four of five ports survived every gate until an external smoke test authored a model the repo does not contain.
The key is a field.string deliberately: a value-typed key (Guid, Long) cannot express "absent" distinctly from "default" in a DataAnnotations-style artifact, so that case belongs to api-contract-conformance, which sees raw JSON.
See CHANGELOG.md for full detail.