Generate the browser contract from ProductApi

This commit is contained in:
ms2k 2026-07-20 03:20:08 +09:00
commit c9642f4067
2 changed files with 2572 additions and 130 deletions

View file

@ -9,7 +9,7 @@ mutation protocol remains in [`Nuthatch.tla`](../protocol/Nuthatch.tla).
| Contract | Implementation owner | Owning gate |
| --- | --- | --- |
| HTTP | `src/Nuthatch/Api.hs`, `src/Nuthatch/App.hs`, `src/Nuthatch/Http/Server.hs`, `src/Nuthatch/Http/Auth.hs`, `src/Nuthatch/Http/Error.hs`, `src/Nuthatch/Browse.hs`, `src/Nuthatch/Transfer.hs` | `make check-product` |
| HTTP | `src/Nuthatch/Api.hs`, `src/Nuthatch/App.hs`, `src/Nuthatch/Http/Server.hs`, `src/Nuthatch/Http/Auth.hs`, `src/Nuthatch/Http/Error.hs`, `src/Nuthatch/Http/Contract.hs`, `src/Nuthatch/Browse.hs`, `src/Nuthatch/Transfer.hs`, `web/src/generated/contract.ts`, `web/src/transport.ts` | `make check-product` |
| SQL | `sql/`, `src/Nuthatch/Db.hs`, `src/Nuthatch/Protocol.hs` | `make check-storage-foundation` |
| Identity encoding | `src/Nuthatch/Paths.hs` | `make test` |
| Content identity | `src/Nuthatch/Streaming.hs`, `src/Nuthatch/S3.hs` | `make check-streaming` |
@ -42,6 +42,12 @@ of rewriting them. Root values are the `personal` and `shared` enum values;
clients never submit complete object keys. Operation ids are 1 through 128
URL-safe ASCII characters from the unreserved set.
`Nuthatch.Http.Contract` traverses `ProductApi` and its explicit wire DTO
mappings to generate the checked TypeScript product contract. The handwritten
browser transport implements that generated interface and exclusively owns
fetch, credential, encoding, binary-body, response-header, retry, and
non-success decoding policy.
Upload requests stream `application/octet-stream`, require
`X-Declared-Size`, `X-Content-SHA256`, `X-CSRF-Token`, and an operation id, and
return a typed mutation result with the advertised terminal idempotency window.

View file

@ -13,6 +13,20 @@ examples, and Hedgehog through Tasty Hedgehog for generated properties.
Hedgehog failures include the seed needed to replay the shrunk counterexample.
Generators represent valid and invalid domains with distinct types.
## Browser product contract
`make check-web-contract` regenerates the TypeScript product contract and
shared JSON fixtures into a temporary directory and requires byte identity
with the checked artifacts. Host tests round-trip every generated wire DTO,
validate explicit TypeScript mappings against representative Aeson shapes,
and derive complete operation error sets from their Haskell constructors.
The same gate runs every handwritten browser product method against an
in-process Servant `ProductApi`. Browser unit tests separately cover
same-origin credentials, encoding, binary bodies, response headers, declared
and undeclared failures, network failures, and the no-automatic-retry policy.
`make check-product` runs this gate before its kind product lane.
## Model correspondence
`make check-model-correspondence` runs before the kind protocol-conformance