docs: define canonical transport bindings

This commit is contained in:
2026-10-02 01:51:10 +09:00
parent b70444c389
commit d7e60d2659
7 changed files with 881 additions and 435 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
WIP Core Modelは、ClientがHostの提供するWorldspaceを観測し、Objectを発見し、Interfaceに従って操作するための意味論を定義する。 WIP Core Modelは、ClientがHostの提供するWorldspaceを観測し、Objectを発見し、Interfaceに従って操作するための意味論を定義する。
具体的なrequest / response structは[3. Protocol](3-protocol.md)、HTTPとJSONへの対応付けは[WIP over HTTPS](draft/wip-over-https.md)で定義する。 具体的なrequest / response structは[3. Protocol](3-protocol.md)、Transport Bindingの共通要件は[5. Transport Bindings](5-transports.md)、HTTPとJSONへの対応付けは[5.1. WIP over HTTP](5.1-wip-over-http.md)で定義する。
## 基本構造 ## 基本構造
@@ -132,6 +132,6 @@ Clientが保持するKnown SpaceとDiscoverable Spaceは、過去の観測から
Core ModelとProtocol structは、HTTP、TCP、WebSocket等の特定transportを要求しない。 Core ModelとProtocol structは、HTTP、TCP、WebSocket等の特定transportを要求しない。
通信方式、concrete encoding、endpoint、batch packagingへの対応付けはTransport Bindingとして定義する。標準bindingは[WIP over HTTPS](draft/wip-over-https.md)で扱う。 通信方式、concrete encoding、endpoint、batch packagingへの対応付けはTransport Bindingとして定義する。共通要件は[5. Transport Bindings](5-transports.md)、標準bindingは[5.1. WIP over HTTP](5.1-wip-over-http.md)で扱う。
この分離により、Worldspaceの意味論、Client / Host間のlogical contract、通信方式を独立して進化させる。 この分離により、Worldspaceの意味論、Client / Host間のlogical contract、通信方式を独立して進化させる。
+11 -8
View File
@@ -4,7 +4,7 @@ WIP Protocolは、ClientとHostの間で交換するlogical data modelと、Core
この章のstructはRust風の記法を使用するが、Rust固有のmemory layoutやserialization libraryを要求しない。TypeScriptを含む他言語でも同じ型、必須性、validation semanticsを実装できなければならない。 この章のstructはRust風の記法を使用するが、Rust固有のmemory layoutやserialization libraryを要求しない。TypeScriptを含む他言語でも同じ型、必須性、validation semanticsを実装できなければならない。
HTTP endpoint、JSON fieldへのencoding、status code、batch packagingはTransport Bindingの責務とし、[WIP over HTTPS](draft/wip-over-https.md)で扱う。 HTTP endpoint、JSON fieldへのencoding、status code、batch packagingはTransport Bindingの責務とし、共通要件を[5. Transport Bindings](5-transports.md)、標準bindingを[5.1. WIP over HTTP](5.1-wip-over-http.md)で扱う。
## Protocol dataの分類 ## Protocol dataの分類
@@ -153,6 +153,8 @@ Hostは、どの状態変化によってObject validatorを無効にするかに
Object validatorはAIやユーザーへ公開するApplication dataではない。Client runtimeがObject observationとともに保持するprotocol metadataである。 Object validatorはAIやユーザーへ公開するApplication dataではない。Client runtimeがObject observationとともに保持するprotocol metadataである。
ここでいうObjectの「現在状態」は、Hostがvalidatorによってobservation consistencyを保護する対象を指す。WIP Objectはprotocol-level projectionであり、Application stateを格納する共通containerではない。WIPは状態遷移modelを定義せず、OperationをObject stateに対するread / writeとして分類しない。
### 同じ`ref`を持つObjectの整合性 ### 同じ`ref`を持つObjectの整合性
同じWorldspace内で同じ`ref`を持つObjectは、一つの共有された現在状態を表す。 同じWorldspace内で同じ`ref`を持つObjectは、一つの共有された現在状態を表す。
@@ -525,7 +527,7 @@ Hostは一つのlinearization pointで、現在のObject identityと状態、Obj
Argumentsとresultのvalidationは、固定したInterface Descriptorの同じOperation declarationを使用する。Authorizationも固定したObject、Interface、主体のcontextに対して評価する。 Argumentsとresultのvalidationは、固定したInterface Descriptorの同じOperation declarationを使用する。Authorizationも固定したObject、Interface、主体のcontextに対して評価する。
状態を変更するOperationでは、Object validatorの比較とbackendへのcommitをatomicに行う。Responseの`validator`は、そのcommit後の同じObject状態に対して発行する。Read-only Operationでもresultを観測した時点のObject validatorを返してよい。Object validatorを提供しない場合は省略する。 Hostが`target.validator`をbackendへのcommit条件として使用する場合、validatorの比較とcommitをatomicに行う。Responseの`validator`は、Operation完了後にHostがそのObjectについて発行する現在のvalidatorである。Operationが何を行ったか、またはApplication dataを変更したかをvalidatorの有無や値から推測しない。Object validatorを提供しない場合は省略する。
Validatorの比較はopaque bytesの完全一致で行う。Clientはvalidatorの生成方法または内容に基づいて分岐してはならない。 Validatorの比較はopaque bytesの完全一致で行う。Clientはvalidatorの生成方法または内容に基づいて分岐してはならない。
@@ -602,7 +604,7 @@ Validatorおよび観測関連errorの回復対象は次のとおりである。
同じOperationを再試行するなら、先に新しい観測を取得しなければならない。 同じOperationを再試行するなら、先に新しい観測を取得しなければならない。
- `InvalidRequest`または`InvalidArguments`では、Clientは同じrequestを変更せずに再送しない。 - `InvalidRequest`または`InvalidArguments`では、Clientは同じrequestを変更せずに再送しない。
- `ResourceLimitExceeded`では、Clientはrequest sizeやobservation depth等を削減できるが、`call_operation`を自動再実行しない。 - `ResourceLimitExceeded`では、Clientはlogical request shapeやobservation depth等を削減できるが、`call_operation`を自動再実行しない。
`call_operation`が`OperationOutcomeUnknown`以外のProtocol failureを返した場合、HostはOperationのeffectがcommitされていないことを保証する。`OperationOutcomeUnknown`は、HostがOperationの未実行またはrollbackを保証できず、validなsuccess responseも返せないことを示す。Clientは対象Objectをstaleとして扱い、Operationを自動再実行せず、再観測またはdomain固有の照会手段を利用者へ提示する。 `call_operation`が`OperationOutcomeUnknown`以外のProtocol failureを返した場合、HostはOperationのeffectがcommitされていないことを保証する。`OperationOutcomeUnknown`は、HostがOperationの未実行またはrollbackを保証できず、validなsuccess responseも返せないことを示す。Clientは対象Objectをstaleとして扱い、Operationを自動再実行せず、再観測またはdomain固有の照会手段を利用者へ提示する。
@@ -623,7 +625,7 @@ Transport BindingはProtocol Resultをstatus code、response envelope、stream t
HostとClientは、untrusted inputによるresource exhaustionを避けるため、少なくとも次へ上限を設ける。 HostとClientは、untrusted inputによるresource exhaustionを避けるため、少なくとも次へ上限を設ける。
- Pathとして解釈するstring、validator、name、description、documentationの長さ。 - Pathとして解釈するstring、validator、name、description、documentationの長さ。
- Interface Descriptor全体のbyte数。 - Interface Descriptor内のdeclaration、documentation、field等の総量。
- ObjectごとのInterface参照数。 - ObjectごとのInterface参照数。
- Type declaration、Operation、parameter、field、caseの数。 - Type declaration、Operation、parameter、field、caseの数。
- TypeExprとValueのnesting depth。 - TypeExprとValueのnesting depth。
@@ -631,9 +633,9 @@ HostとClientは、untrusted inputによるresource exhaustionを避けるため
- `observe`のdepthとresponse node数。 - `observe`のdepthとresponse node数。
- Protocol error messageの長さ。 - Protocol error messageの長さ。
各実装はこれらにboundedな上限を設定する。Request fieldだけで判定できる上限違反は、interaction固有のtarget resolutionまたはOperation dispatchより前に`ResourceLimitExceeded`として拒否する。Hostがread-only responseを構築する途中でresponse node数やbyte数等の上限超過を検出した場合も、success responseの代わりに`ResourceLimitExceeded`を返してよい。 各実装はこれらにboundedな上限を設定する。Request fieldだけで判定できる上限違反は、interaction固有のtarget resolutionまたはOperation dispatchより前に`ResourceLimitExceeded`として拒否する。Hostが取得responseを構築する途中でresponse node数やlogical collection size等の上限超過を検出した場合も、success responseの代わりに`ResourceLimitExceeded`を返してよい。
`call_operation`では、dispatch後にresult size、encoding、backend budget等の問題を検出しても、effectがcommitされていないと保証できる場合だけ`ResourceLimitExceeded`または`Internal`を返す。未実行またはrollbackを保証できない場合は`OperationOutcomeUnknown`とする。Client側のresponse byte limit超過やresponse不達はProtocol failureへ変換せず、Transport failureとして扱う。現在のProtocolではlimit negotiationを定義しない。 `call_operation`では、dispatch後にresultのlogical size、validation、backend budget等の問題を検出しても、effectがcommitされていないと保証できる場合だけ`ResourceLimitExceeded`または`Internal`を返す。未実行またはrollbackを保証できない場合は`OperationOutcomeUnknown`とする。Transport implementationまたはdeploymentのmessage-size上限、response不達等はProtocol failureへ変換せず、Transport failureとして扱う。
## Batch ## Batch
@@ -641,7 +643,7 @@ BatchはCore interactionではなくTransport Bindingのoptimizationである。
Transport Bindingは、複数の`ObserveRequest`と`FetchInterfaceRequest`を一つのphysical requestへまとめてよい。それぞれのlogical requestは独立して成功または失敗し、個別に実行した場合と同じ意味を持たなければならない。Subrequest間で先行resultを後続requestのfieldとして参照してはならない。 Transport Bindingは、複数の`ObserveRequest`と`FetchInterfaceRequest`を一つのphysical requestへまとめてよい。それぞれのlogical requestは独立して成功または失敗し、個別に実行した場合と同じ意味を持たなければならない。Subrequest間で先行resultを後続requestのfieldとして参照してはならない。
`call_operation`は副作用、順序、部分的成功の意味が不明確になるため、Coreの標準batch対象にしない。 `call_operation`はOperation executionのordering、partial completion、replayを定義する新しいinteractionになるため、Coreの標準batch対象にしない。OperationをObject stateへのeffectで分類してbatch対象を推測しない。
## Transport Bindingの要件 ## Transport Bindingの要件
@@ -654,6 +656,7 @@ Transport Bindingは、この章のlogical structについて次を定義する
- Protocol failureのmapping。 - Protocol failureのmapping。
- Object validator、Interface validator、Operation preconditionのmapping。 - Object validator、Interface validator、Operation preconditionのmapping。
- Batch packagingを提供する場合はitemの対応付けと部分的failure。 - Batch packagingを提供する場合はitemの対応付けと部分的failure。
- Message size、timeout、concurrency等のtransport固有limit。
Transport固有のmessage size、timeout、concurrency、security、connection policyはTransport実装とdeploymentの責務であり、BindingがWIP Protocolとして値またはnegotiationを定義する必要はない。
Transport Bindingは、logical typeの区別またはvalidation semanticsを失ってはならない。 Transport Bindingは、logical typeの区別またはvalidation semanticsを失ってはならない。
+2 -2
View File
@@ -132,10 +132,10 @@ ClientはHostが返すProtocol errorの`code`で回復actionを決定し、人
同じOperationを再試行するなら、先に新しい観測を取得しなければならない。 同じOperationを再試行するなら、先に新しい観測を取得しなければならない。
- `InvalidRequest`または`InvalidArguments`では同じrequestを変更せずに再送しない。 - `InvalidRequest`または`InvalidArguments`では同じrequestを変更せずに再送しない。
- `ResourceLimitExceeded`ではrequest sizeやobservation depth等を削減できるが、Operationを自動再実行しない。 - `ResourceLimitExceeded`ではlogical request shapeやobservation depth等を削減できるが、Operationを自動再実行しない。
- `PermissionDenied`では公開済みOperationが実行拒否されたことを示し、Object自体が閲覧禁止で存在するとは推測しない。 - `PermissionDenied`では公開済みOperationが実行拒否されたことを示し、Object自体が閲覧禁止で存在するとは推測しない。
`OperationOutcomeUnknown`では、Operationが未実行またはrollback済みであることが保証されない。ClientはOperationを自動再実行せず、対象Objectをstaleとして再観測するか、domain固有の照会手段を提示する。`Internal`、Transport timeout、connection lossの場合も、Effect annotationがない現在のProtocolではOperationを自動再実行しない。Response不達はProtocol errorへ変換せず、Transport failureとOperation outcomeが不明な状態をClient内部で保持する。 `OperationOutcomeUnknown`では、Operationが未実行またはrollback済みであることが保証されない。ClientはOperationを自動再実行せず、対象Objectをstaleとして再観測するか、domain固有の照会手段を提示する。`Internal`、Transport timeout、connection lossの場合もOperationを自動再実行しない。Response不達はProtocol errorへ変換せず、Transport failureとOperation outcomeが不明な状態をClient内部で保持する。WIPはOperationをObject stateへのeffectで分類してretry可否を推測しない。
HTTP authentication failureとWorldspace endpoint全体のaccess denialはTransport layerのfailureであり、WIPの`PermissionDenied`へ変換しない。 HTTP authentication failureとWorldspace endpoint全体のaccess denialはTransport layerのfailureであり、WIPの`PermissionDenied`へ変換しない。
+79
View File
@@ -0,0 +1,79 @@
# 5. Transport Bindings
WIP Transport Bindingは、[3. Protocol](3-protocol.md)のlogical data modelとCore interactionを、具体的な通信方式とwire representationへ対応付ける。
標準bindingは[5.1. WIP over HTTP](5.1-wip-over-http.md)で定義する。
## 責務
Transport Bindingは、少なくとも次を定義する。
- Endpointまたはpeerの指定方法。
- Requestとresponseのframing、および一つのlogical interactionとの対応付け。
- Protocol primitive、Object、Interface Descriptor、Operation Valueのconcrete encoding。
- Required field、optional field、list、record、bytes等のwire representation。
- SuccessとProtocol failureのwire representation。
- Transport failureとProtocol failureの区別。
- ValidatorおよびOperation preconditionのmapping。
- Batchを提供する場合のitem correlation、独立性、部分的failure。
BindingはProtocolのlogical type、validation、error、visibility、Operation executionの意味を変更してはならない。Binding固有のstatus、header、stream event等を根拠として、新しいProtocol failureまたは回復actionを暗黙に追加してはならない。
## Logical interactionとphysical exchange
一つのCore interactionは、一つ以上のphysical messageを使用して実装できる。ただし、ClientとHostは各successまたはProtocol failureを、元のlogical requestおよびそのeffective Worldspace viewへ一意に対応付けられなければならない。
Transport Bindingは複数の取得interactionを一つのphysical requestへbatchしてよい。その場合も各logical interactionは、個別に実行した場合と同じrequest、response、failure semanticsを持つ。Batchは新しいCore interaction、transaction、共通snapshot、subrequest間のdata dependencyを導入しない。
## Effective Worldspace view
Endpoint、認証主体、tenant、capability、その他のdeployment contextによって、同じHostが異なるClient-facing Worldspaceを公開できる。
Clientは異なるeffective Worldspace viewのObject observation、Interface observation、validator、Known Spaceを混在させない。Transport connectionの再利用やmultiplexingによって、この分離を失ってはならない。
どのauthentication方式または通信securityを使ってviewを確立するかは、Transport実装とdeploymentの責務であり、WIPは標準化しない。
## Protocol failureとTransport failure
Hostがlogical interactionを受理して返す`ProtocolError`はProtocol failureである。Transport Bindingは、これを機械可読なwire representationへ対応付ける。
次はProtocol failureではない。
- Endpointまたはrouteへ到達できない。
- Transport implementationまたはdeploymentがrequestを拒否する。
- Unsupportedなmedia type、framing、content coding、Transport version。
- Connection loss、timeout、response不達。
- Intermediaryが生成した、validなProtocol error representationを持たないfailure。
- Clientがresponseを受信またはdecodeできない。
ClientはTransport failureから`ProtocolErrorCode`を推測しない。Transport authentication failureを`PermissionDenied`へ、未知routeを`NotFound`へ、timeoutを`Internal`または`OperationOutcomeUnknown`へ変換しない。
Protocol上の`OperationOutcomeUnknown`はHostが返すProtocol failureである。Response不達によってClient側でOperation outcomeを確定できない状態はTransport failureであり、Hostから同codeを受信したことにはしない。
## Dispatchとreplay
Transport Bindingは、physical exchangeの再送によって一つのlogical `call_operation`を複数回dispatchしてはならない。
RequestがHostへdispatchされた可能性のある状態でresponseを取得できなかった場合、Clientは`call_operation`を自動再実行しない。Connection close、timeout、local cancellationは、Host上の実行またはcommitを取り消した証拠ではない。
取得interactionを再送するか、どのtimeoutやretry policyを使用するかはClientとTransport実装の責務である。取得用policyを`call_operation`へ適用しない。
## Validator
Object validatorとInterface validatorはProtocol structのlogical fieldであり、Bindingはそれらをlosslessにencodeする。
Transport固有のcache validator、conditional request metadata、message identifier等は、WIP validatorと独立している。それらを理由にProtocol bodyのvalidatorを省略せず、ClientもTransport metadataをWIP validatorとして解釈しない。
## Transport運用との境界
通信scheme、TLS、peer authentication、proxy、gateway、HTTP cache、compression、connection管理、message size、timeout、concurrency、rate limit等はTransport実装またはdeploymentの関心であり、WIPは値、negotiation、運用profileを定義しない。
それらの設定によってrequestまたはresponseを交換できない場合はTransport failureである。HTTP status等がProtocol errorのcanonical mappingと偶然一致しても、validなProtocol error representationを受信しない限りProtocol failureへ変換しない。
WIPのlogical struct、observation completeness、TypeExpr / Value、Host execution等に対する`ResourceLimitExceeded`は[3. Protocol](3-protocol.md)で定義する。Transport implementation自身のmessage-size、timeout、queue、connection等の上限を同codeで包まない。
## Versioning
各Bindingは、wire互換性へ影響するmajor versionの選択方法を定義する。異なるmajor version間でroute、message、fieldを推測変換しない。
ProtocolまたはInterface Descriptorのversionと、Transport Bindingのversionは別である。Transport major versionが同じでも、Interface Descriptorの`format`は独立して検証する。
+786
View File
@@ -0,0 +1,786 @@
# 5.1. WIP over HTTP
WIP over HTTPは、[3. Protocol](3-protocol.md)のlogical data modelをHTTP request / responseとJSONへ対応付ける標準Transport Bindingである。[5. Transport Bindings](5-transports.md)の共通要件に従う。
## 目的と範囲
このbindingは、次のCore interactionをHTTPへ対応付ける。
- `observe`
- `fetch_interface`
- `call_operation`
さらに、独立した複数の`observe`と`fetch_interface`を一つのHTTP exchangeへまとめるretrieval batchを定義する。
HTTP version、communication scheme、TLS、authentication方式、connection reuse、multiplexing、proxy、gateway、cache、Host内部のframework、backend接続方式は規定しない。HTTP実装とdeploymentは、それらをWIPとは独立して選択する。
OperationがWebSocket等のendpointをApplication dataとして返すことは妨げない。そのendpoint上のprotocol、状態、lifecycleはWIPの規定対象外である。
## Endpoint
WIP endpointは、一つのWorldspace access surfaceを指すabsolute hierarchical base URLである。Endpoint URLのpath prefixはdeploymentが任意に選択できる。Clientはorigin直下、`/wip`等の既定prefix、またはWorldspace pathとの対応を仮定しない。
Endpoint URLは次を満たす。
- HTTP実装がrequest先として使用できるabsolute URLである。
- Authorityとhostを持つ。
- Queryとfragmentを持たない。
- Pathが`/`で終わるcanonical formである。
利用者から末尾`/`のないURLを受け付ける実装は、routeを解決する前に`/`を追加してcanonical formへ変換する。URL schemeと通信securityの選択はHTTP実装とdeploymentの責務であり、このbindingは制約しない。
各routeはendpoint URLをbase URLとして、次のrelative referenceをRFC 3986に従って解決する。すべてのinteractionは`POST`を使用する。
| Interaction | Method | Relative reference |
| --- | --- | --- |
| `observe` | `POST` | `v1/observe` |
| `fetch_interface` | `POST` | `v1/fetch_interface` |
| `call_operation` | `POST` | `v1/call_operation` |
| retrieval batch | `POST` | `v1/batch` |
`v1`はWIP over HTTP Bindingのmajor versionである。Interactionごとに独立したrouteを設定したり、固定suffixを別名へ置き換えたりしない。
例えば、次のendpointを指定した場合、
```text
http://gateway.example/tenants/acme/filesystem/wip/
```
`observe` routeは次になる。
```text
http://gateway.example/tenants/acme/filesystem/wip/v1/observe
```
Endpointのpath prefixはHTTP deployment上のroutingであり、Worldspace内のpathではない。Worldspace pathはrequest bodyのlogical fieldとして渡す。標準route URLはqueryを持たず、query付きURLまたは追加path segmentを同じrouteとして扱わない。
Clientは異なるcanonical endpoint間でKnown Space、Object observation、Interface observation、validatorを混在させない。同じendpointでも認証主体、tenant、capability、その他のsecurity contextによって異なるWorldspaceが見える場合、それらを異なるeffective Worldspace viewとして分離する。
## HTTP request metadata
標準routeへのrequestは次を満たす。
- Methodは`POST`。
- `Content-Type`は`application/json`または`application/json; charset=utf-8`。
- BodyはUTF-8のJSON text。
- 標準Clientは`Accept: application/json`を送る。
- Request URLは標準routeと完全に一致し、queryを持たない。
Media typeとparameter名の比較はHTTPの規則に従ってcase-insensitiveに行う。`charset`を指定する場合は`utf-8`だけを許可する。同じparameterの重複、UTF-8以外のcharset、その他のmedia type parameterを標準bindingでは使用しない。
`Accept`がないrequestをHostは受理してよい。`Accept`がある場合はHTTP content negotiationの規則を適用し、`application/json`に対するeffective quality valueが正である場合だけJSON responseを返す。
すべての実装はHTTP identity content codingを扱える。Requestまたはresponseのcontent codingはoptionalなHTTP機能であり、本bindingは特定の圧縮方式を必須にしない。Hostが対応しないrequest content codingはTransport-levelの`415 Unsupported Media Type`として拒否する。Clientが対応しないresponse content codingはTransport failureとして扱う。
## Routeとmetadataのfailure
Route、method、content negotiation、Transport authenticationはlogical WIP requestの外側にある。次のresponseはProtocol error envelopeを要求しない。
| 条件 | HTTP response |
| --- | --- |
| 未知route、query付きroute、追加path segment | `404 Not Found` |
| 既知routeへの`POST`以外のmethod | `405 Method Not Allowed`と`Allow: POST` |
| Unsupportedな`Content-Type`またはrequest content coding | `415 Unsupported Media Type` |
| JSON responseを拒否する`Accept` | `406 Not Acceptable` |
| Transport authenticationが必要 | `401 Unauthorized`、必要なら`WWW-Authenticate` |
| Endpoint access surface全体へのaccess拒否 | `403 Forbidden` |
Clientはこれらを`InvalidRequest`、`NotFound`、`PermissionDenied`等へ変換しない。
標準route、method、media type、authenticationが受理された後、bodyがmalformed JSONである、logical requestへdecodeできない、required fieldがない、未知fieldがある、またはfield semanticsに違反する場合、Hostは`400 Bad Request`と`invalid_request`のProtocol error envelopeを返す。
HTTP server、proxy、gateway、またはClientの運用設定によってmessage size、timeout、rate等の上限に達した場合はTransport failureである。HTTP statusが後述するProtocol error mappingと同じでも、validなProtocol error envelopeを持たないresponseをProtocol failureへ変換しない。
## HTTP response
単独interactionが成功した場合、Hostは`200 OK`を返し、response bodyへ対応するProtocol responseを直接encodeする。Success bodyを`result`等の共通envelopeで包まない。
Protocol failureの場合、Hostは非2xx statusを返し、bodyへ本章のProtocol error envelopeをencodeする。
WIP Hostが生成するbody付きresponseは`Content-Type: application/json`または`application/json; charset=utf-8`を持つ。Protocol successまたはProtocol failureのbodyはUTF-8 JSON textである。
HTTP statusは大分類とHTTP infrastructureのための補助情報であり、Protocol failureの意味を決定しない。Clientはstatus、reason phrase、人間向けmessageから`ProtocolErrorCode`を推測しない。
非2xx responseが、正しいContent-TypeとvalidなProtocol error envelopeを持たない場合、ClientはTransport failureとして扱う。これにより、proxyやgatewayが生成したresponseをHost由来のProtocol failureと誤認しない。
次は`InvalidResponse`である。
- `200 OK`以外の2xx statusにvalidなsuccess bodyがある。
- 2xx statusにProtocol error envelopeがある。
- 非2xx statusにvalidなsuccess bodyがある。
- Success bodyまたはProtocol error envelopeがschema、request correlation、interactionごとのcode制約に違反する。
## JSON共通規則
JSON encodingには次の規則を適用する。
- JSON textはUTF-8でencodeする。
- RecordはJSON object、listはJSON arrayで表す。
- Field名と列挙stringはcase-sensitiveである。
- 同じJSON object内のduplicate memberを拒否する。
- 本章がschemaを定義するobjectでは、許可していないmemberを拒否する。Descriptorの未知formatとTypeExpr `Json`のobjectには、それぞれ後述する例外を適用する。
- Required fieldは必ず存在する。
- Protocol structのoptional fieldはmemberの省略で表し、`null`で置き換えない。
- JSON objectのmember順に意味を持たせない。
- Protocol listのarray順は保持する。
- StringへUnicode normalizationを適用しない。
- JSON syntaxが表現できないNaNと正負Infinityを使用しない。
本章のschema表で`optional`と記していないfieldはrequiredである。
`Vec<u8>`はRFC 4648 Section 4のstandard base64 alphabetを使用し、必要な`=` paddingを含むcanonical base64 stringとしてencodeする。Whitespace、URL-safe alphabet、padding省略、同じoctet列に対する別表現を受理しない。
Path、Interface参照、Object identity、名前、validatorの意味はJSON scalar自体ではなくfieldの位置によって決まる。
| Logical field | JSON encoding |
| --- | --- |
| Path / `entry` | canonical absolute Worldspace pathのstring |
| Object、Operation、Type、Field、Parameter、Case名 | string |
| Interface参照 | string |
| `ref` | string |
| `format` | string |
| Object / Interface validator | canonical base64 string |
JSON serializationのwhitespace、escapeの選択、object member順をcanonical化しない。同じlogical valueがbyte-for-byte同一のJSONになることを要求しない。
## ObjectとObjectObservation
`Object`は次のJSON objectとしてencodeする。
| Field | JSON type | Presence |
| --- | --- | --- |
| `name` | string | required |
| `description` | string | optional |
| `interfaces` | stringのarray | required |
| `ref` | string | optional |
| `validator` | canonical base64 string | optional |
例:
```json
{
"name": "123",
"description": "First item",
"interfaces": [
"item-interface-v1",
"item-marker-interface-v1"
],
"ref": "item:123",
"validator": "aXRlbS12YWxpZGF0b3I="
}
```
`interfaces`のarray順はHostの立項順を保持し、重複を含まない。
`ObjectObservation`は次のJSON objectとしてencodeする。
| Field | JSON type | Presence |
| --- | --- | --- |
| `object` | `Object` | required |
| `children` | `ObjectObservation`のarray | optional |
`children`の省略は未観測を、空arrayは観測済みで直接のindexable childが存在しないことを表す。Requested depthより浅いnodeでは`children`を必ず含め、depth境界のnodeでは省略する。Success responseはrequested depthまで完全であり、truncated markerやpartial successを返さない。
## Interface Descriptor
### Format discriminator
標準v1のInterface Descriptor formatは`wip-interface/1`である。このformatでは以下のJSON grammarを使用する。
ClientはDescriptor objectのstring `format`を先に読み、対応しないformatを`UnsupportedDescriptorFormat`として扱える。未知formatでもDescriptorはJSON objectであり、string `format`を必ず持つ。それ以外のmemberはそのformat固有であるため、Clientは`wip-interface/1`のschemaで存在、欠落、型を判定せず、内容をOperationへ使用しない。標準v1 Hostは`wip-interface/1`を返す。
### Documentation
`Documentation`は次のJSON objectである。
| Field | JSON type | Presence |
| --- | --- | --- |
| `summary` | string | required |
| `details` | string | optional |
### Descriptor root
`InterfaceDescriptor`は次のJSON objectである。
| Field | JSON type | Presence |
| --- | --- | --- |
| `format` | string。標準v1では`wip-interface/1` | required |
| `documentation` | `Documentation` | optional |
| `types` | `TypeDeclaration`のarray | required |
| `operations` | `OperationDeclaration`のarray | required |
`types`と`operations`のarray順はdeclaration順を保持する。
### TypeDeclaration
| Field | JSON type | Presence |
| --- | --- | --- |
| `name` | string | required |
| `documentation` | `Documentation` | optional |
| `definition` | `TypeExpr` | required |
### TypeExpr
すべての`TypeExpr`はstring `kind`を持つJSON objectとしてencodeする。`kind`ごとの正確なmemberは次のとおりである。
| TypeExpr | `kind` | その他のmember |
| --- | --- | --- |
| Unit | `unit` | なし |
| Boolean | `boolean` | なし |
| Integer | `integer` | なし |
| Number | `number` | なし |
| String | `string` | なし |
| Bytes | `bytes` | なし |
| Json | `json` | なし |
| Entry | `entry` | なし |
| Named | `named` | required string `name` |
| Record | `record` | required `FieldDeclaration` array `fields` |
| List | `list` | required `TypeExpr` `items` |
| Enum | `enum` | required `EnumCase` array `cases` |
| Union | `union` | required `UnionCase` array `cases` |
例:
```json
{
"kind": "list",
"items": {
"kind": "named",
"name": "ItemSummary"
}
}
```
Primitive kindのobjectへ別memberを追加してはならない。例えばUnitは`{"kind":"unit"}`だけで表す。
### FieldDeclaration
| Field | JSON type | Presence |
| --- | --- | --- |
| `name` | string | required |
| `required` | boolean | required |
| `documentation` | `Documentation` | optional |
| `type` | `TypeExpr` | required |
### EnumCase
| Field | JSON type | Presence |
| --- | --- | --- |
| `name` | string | required |
| `documentation` | `Documentation` | optional |
### UnionCase
| Field | JSON type | Presence |
| --- | --- | --- |
| `name` | string | required |
| `documentation` | `Documentation` | optional |
| `payload` | `TypeExpr` | optional |
`payload`の省略はpayloadを持たないcaseを表す。
### OperationDeclaration
| Field | JSON type | Presence |
| --- | --- | --- |
| `name` | string | required |
| `documentation` | `Documentation` | optional |
| `parameters` | `ParameterDeclaration`のarray | required |
| `returns` | `ReturnDeclaration` | required |
### ParameterDeclaration
| Field | JSON type | Presence |
| --- | --- | --- |
| `name` | string | required |
| `required` | boolean | required |
| `documentation` | `Documentation` | optional |
| `type` | `TypeExpr` | required |
### ReturnDeclaration
| Field | JSON type | Presence |
| --- | --- | --- |
| `documentation` | `Documentation` | optional |
| `type` | `TypeExpr` | required |
Descriptorの名前一意性、Named参照、cycle、型整合性等は[3. Protocol](3-protocol.md)に従って検証する。JSON shapeが正しいことだけではvalidなDescriptorにならない。
完全なDescriptorの例:
```json
{
"format": "wip-interface/1",
"documentation": {
"summary": "Reads items and their relationships."
},
"types": [
{
"name": "Relation",
"definition": {
"kind": "enum",
"cases": [
{ "name": "parent" },
{ "name": "sibling" }
]
}
},
{
"name": "RelatedItem",
"definition": {
"kind": "union",
"cases": [
{
"name": "found",
"payload": { "kind": "entry" }
},
{ "name": "not_found" }
]
}
}
],
"operations": [
{
"name": "get_related_item",
"parameters": [
{
"name": "relation",
"required": true,
"type": {
"kind": "named",
"name": "Relation"
}
}
],
"returns": {
"type": {
"kind": "named",
"name": "RelatedItem"
}
}
}
]
}
```
## Operation Value
Operationのargumentsとresultは、選択したInterface Descriptorの`TypeExpr`に従ってJSONへencodeする。Raw `Value` variantを示す共通tagged envelopeは使用しない。
| TypeExpr | JSON encoding |
| --- | --- |
| Unit | `null` |
| Boolean | boolean |
| Integer | 小数部と指数部を持たないJSON number。`-9007199254740991`から`9007199254740991`まで |
| Number | finiteなJSON number |
| String | string |
| Bytes | canonical base64 string |
| Json | JSONの`null`、boolean、number、string、array、object |
| Entry | canonical absolute Worldspace pathのstring |
| Named | 同じDescriptor内の参照先TypeExprと同じencoding |
| Record | declarationされたfieldをmemberとするobject |
| List | items TypeExprに従うarray |
| Enum | 宣言されたcase名のstring |
| Union | `$case`と、必要なら`value`を持つobject |
`Json`内部でもnumberは相互運用可能なsafe integerまたはfinite binary64として扱い、Bytesの特別なencodingは適用しない。小数部と指数部を持たずsafe integer範囲にあるJSON numberはlogical `Integer`、それ以外のfiniteなJSON numberはlogical `Number`としてdecodeする。`Json`内のbase64らしいstringをBytesと推測しない。
RecordとOperation argumentsでは、`required = false`のfieldまたはparameterを省略できる。省略と`null`は異なる。TypeExprがUnit、Json、またはそれらへ解決されるNamedである場合、存在するmemberの`null`はその型のvalueであり、省略を表さない。それ以外の型で`null`を使用してはならない。
Record valueはdeclarationされていないmemberを持たない。Operation argumentsはparameter名をmember名とするJSON objectであり、位置引数を使用しない。引数のないOperationは空objectを使用する。
Enumはcase名だけをstringで表し、object envelopeを使用しない。
Payloadを持つUnionは次の形である。
```json
{
"$case": "found",
"value": "/items/123"
}
```
Payloadを持たないUnionは`value`を省略する。
```json
{
"$case": "not_found"
}
```
Union objectは`$case`と必要な`value`以外のmemberを持たない。Payloadありcaseでは`value`がrequired、payloadなしcaseでは`value`は禁止される。
ClientはDescriptorに従ってvalueをdecodeし、`entry`と宣言された位置のstringだけをWorldspace entryとして認識する。通常のStringやopaqueなJsonに含まれるpathらしいstringをentryとして推測しない。
## `observe`
### Request
`POST v1/observe`のbodyは次のJSON objectである。
| Field | JSON type | Presence |
| --- | --- | --- |
| `path` | canonical absolute Worldspace pathのstring | required |
| `depth` | `0`以上`4294967295`以下のinteger | required |
```json
{
"path": "/items",
"depth": 1
}
```
### Success response
Success bodyはrootの`ObjectObservation`を直接encodeする。
```json
{
"object": {
"name": "items",
"description": "Item collection",
"interfaces": ["item-collection-interface-v1"],
"validator": "cm9vdC12YWxpZGF0b3I="
},
"children": [
{
"object": {
"name": "123",
"description": "First item",
"interfaces": ["item-interface-v1"],
"ref": "item:123",
"validator": "aXRlbS12YWxpZGF0b3I="
}
}
]
}
```
Responseのpath、name、depth、children completenessはrequestと[3. Protocol](3-protocol.md)に従って検証する。完全なresponseをresource budget内で構築できない場合、Hostはpartial successではなく`resource_limit_exceeded`を返す。
## `fetch_interface`
### Request
`POST v1/fetch_interface`のbodyは次のJSON objectである。
| Field | JSON type | Presence |
| --- | --- | --- |
| `interface` | Interface参照のstring | required |
```json
{
"interface": "item-interface-v1"
}
```
### Success response
| Field | JSON type | Presence |
| --- | --- | --- |
| `interface` | Interface参照のstring | required |
| `descriptor` | Interface Descriptor object | required |
| `validator` | canonical base64 string | optional |
```json
{
"interface": "item-interface-v1",
"descriptor": {
"format": "wip-interface/1",
"types": [],
"operations": []
},
"validator": "aW50ZXJmYWNlLXZhbGlkYXRvcg=="
}
```
Responseの`interface`はrequestと完全一致しなければならない。Descriptorとvalidatorは一つのInterface observationとして扱う。
## `call_operation`
### Request
`POST v1/call_operation`のbodyは次のJSON objectである。
| Field | JSON type | Presence |
| --- | --- | --- |
| `target` | `Target` object | required |
| `interface` | `InterfaceTarget` object | required |
| `operation` | Operation名のstring | required |
| `arguments` | 選択したOperation declarationに従うobject | required |
`Target`は次のfieldを持つ。
| Field | JSON type | Presence |
| --- | --- | --- |
| `path` | canonical absolute Worldspace pathのstring | required |
| `validator` | canonical base64 string | optional |
`InterfaceTarget`は次のfieldを持つ。
| Field | JSON type | Presence |
| --- | --- | --- |
| `reference` | Interface参照のstring | required |
| `validator` | canonical base64 string | optional |
```json
{
"target": {
"path": "/items/current",
"validator": "b2JqZWN0LXZhbGlkYXRvcg=="
},
"interface": {
"reference": "item-interface-v1",
"validator": "aW50ZXJmYWNlLXZhbGlkYXRvcg=="
},
"operation": "get_related_item",
"arguments": {
"relation": "sibling"
}
}
```
`interface.reference`と`operation`は別fieldである。表示用の`<interface-reference>.<operation-name>`を一つのfieldへencodeしない。
HostはDescriptorに依存しない`target`、`interface`、`operation`のshapeを検証し、Protocolのerror precedenceに従って現在のObjectとInterface observationを固定した後、そのDescriptorに従って`arguments`をdecodeする。
### Success response
| Field | JSON type | Presence |
| --- | --- | --- |
| `result` | Operation return TypeExprに従うJSON value | required |
| `validator` | 実行後のObject validatorを表すcanonical base64 string | optional |
```json
{
"result": {
"$case": "found",
"value": "/items/123"
},
"validator": "bmV3LW9iamVjdC12YWxpZGF0b3I="
}
```
`result`はrequestで指定し、Hostがprecondition確認時に固定したOperation declarationのreturn TypeExprに従ってencodeする。
## Validator
Object validatorとInterface validatorは対応するJSON body fieldへcanonical base64としてencodeする。
- `Object.validator`
- `Target.validator`
- `FetchInterfaceResponse.validator`
- `InterfaceTarget.validator`
- `CallOperationResponse.validator`
単独request / responseとbatch itemは同じ表現を使用する。
WIP validatorを`ETag`、`If-Match`、その他のHTTP headerだけへ移してbody fieldを省略してはならない。Host、gateway、HTTP cacheは通常のHTTP representation metadataとして`ETag`等を追加してよいが、その値はWIP validatorと独立している。ClientはHTTP metadataをObject identity、Interface observation、Operation preconditionとして解釈しない。
## Protocol error envelope
単独interactionのProtocol failureとbatch全体のProtocol failureは、次のexactなJSON objectとしてencodeする。
```json
{
"error": {
"code": "invalid_arguments",
"message": "Required argument `relation` is missing"
}
}
```
Top-level objectは`error`だけを持つ。`error` objectは次のfieldだけを持つ。
| Field | JSON type | Presence |
| --- | --- | --- |
| `code` | 下表のstableなsnake_case string | required |
| `message` | boundedな人間向け診断string | required |
Clientは`message`で分岐しない。Hostは秘密情報、credential、非公開Object、backend path、内部stack traceをmessageへ含めない。
`ProtocolErrorCode`のwire spellingとcanonical HTTP statusは次のとおりである。
| Protocol error code | Wire spelling | HTTP status |
| --- | --- | --- |
| `InvalidRequest` | `invalid_request` | `400 Bad Request` |
| `NotFound` | `not_found` | `404 Not Found` |
| `InterfaceNotFound` | `interface_not_found` | `404 Not Found` |
| `InterfaceMismatch` | `interface_mismatch` | `409 Conflict` |
| `OperationNotFound` | `operation_not_found` | `404 Not Found` |
| `InvalidArguments` | `invalid_arguments` | `422 Unprocessable Content` |
| `ValidatorRequired` | `validator_required` | `428 Precondition Required` |
| `ValidatorMismatch` | `validator_mismatch` | `412 Precondition Failed` |
| `InterfaceValidatorRequired` | `interface_validator_required` | `428 Precondition Required` |
| `InterfaceValidatorMismatch` | `interface_validator_mismatch` | `412 Precondition Failed` |
| `PermissionDenied` | `permission_denied` | `403 Forbidden` |
| `ResourceLimitExceeded` | `resource_limit_exceeded` | `422 Unprocessable Content` |
| `Internal` | `internal` | `500 Internal Server Error` |
| `OperationOutcomeUnknown` | `operation_outcome_unknown` | `500 Internal Server Error` |
`resource_limit_exceeded`は、observation completeness、logical nesting、collection件数等、WIP Protocolが扱うlogical requestまたはresponseの上限超過を表し、`422 Unprocessable Content`を使用する。HTTP implementationやdeploymentのmessage-size上限超過をこのcodeへ変換しない。
Rate limitまたはdeployment concurrency limitによる`429 Too Many Requests`はTransport / deployment concernである。ValidなProtocol error envelopeがない限り`ResourceLimitExceeded`へ変換しない。
Hostはinteractionごとに[3. Protocol](3-protocol.md)で許可されたcodeだけを返す。ClientがvalidなProtocol error envelopeを取得した場合、HTTP statusがcanonical mappingと一致しなくても回復actionは`code`に従い、statusから別codeを推測しない。Status mismatchはBinding違反として診断してよい。
`InvalidResponse`と`UnsupportedDescriptorFormat`はClient-local classificationであり、Hostがerror envelopeで返してはならない。Domain failureもProtocol errorへ変換せず、Operation return typeに従うApplication dataとしてencodeする。
## HTTP authentication boundary
Authentication方式、credential、mTLS、proxy、gateway等はHTTP implementationとdeploymentの関心であり、本bindingは規定しない。
HTTP layerがWIP interactionを開始せずに返す`401 Unauthorized`または`403 Forbidden`は、validなProtocol error envelopeを持たないTransport failureである。Clientはそれらを`PermissionDenied`へ変換しない。
WIP interactionを開始した後のObject、Interface、Operation visibilityとauthorizationはProtocol semanticsに従う。Protocolの`PermissionDenied`はvalidなWIP error envelopeを持つ`403 Forbidden`であり、HTTP layerのaccess rejectionと区別する。
## HTTP replay
`3xx` response自体はWIP successまたはProtocol failureではなく、Transport failureである。Endpoint discovery、redirect、proxy routingをどう扱うかはHTTP implementationとdeploymentの責務である。
ただし、それらの機構によって一つのlogical `call_operation` requestを複数回dispatchしてはならない。Dispatch後にredirect responseを受け取った場合も、methodとbodyを維持して別endpointへ自動再送しない。
## Dispatchとretry
RequestがHostへ送信されていないとTransport実装が証明できるfailureはnot dispatchedである。送信開始後にresponseを取得できない場合、ClientはHostがrequestを受理した可能性を否定しない。
`observe`と`fetch_interface`を再送するか、どのtimeout、retry、cancellation policyを使用するかはClientとHTTP実装の責務である。Response ownershipとProtocol上のcache semanticsは[4. Client](4-client.md)に従う。
`call_operation`には次を適用する。
- Redirect、connection retry、HTTP stackのautomatic replay、proxy retryによって再送しない。
- `Retry-After`またはHTTP statusだけを理由に再送しない。
- Response不達またはlocal cancellationを、Operationが未実行またはrollback済みである証拠として扱わない。
- `internal`または`operation_outcome_unknown`を受信しても自動再実行しない。
- 同じOperationを利用者が改めて実行する場合は、Protocolの回復規則に従って必要なObjectまたはInterfaceを再観測する。
HTTP implementationとdeploymentは、失敗した`POST v1/call_operation`を透過的にreplayしない。
## Retrieval batch
Retrieval batchは、複数の独立した`observe`と`fetch_interface`を一つのHTTP requestへまとめるpackagingである。新しいCore interaction、transaction、共通snapshot、実行順序を導入しない。
### Request envelope
`POST v1/batch`のbodyは次のexactなJSON objectである。
```json
{
"requests": [
{
"id": "entry-123",
"method": "observe",
"arguments": {
"path": "/items/123",
"depth": 0
}
},
{
"id": "item-interface",
"method": "fetch_interface",
"arguments": {
"interface": "item-interface-v1"
}
}
]
}
```
Top-level objectはrequiredな`requests` arrayだけを持つ。各itemは次のfieldだけを持つ。
| Field | JSON type | Presence |
| --- | --- | --- |
| `id` | string | required |
| `method` | `observe`または`fetch_interface` | required |
| `arguments` | 対応interactionのrequest object | required |
`id`は一つのbatch request内で一意であり、そのphysical exchange内のcorrelationにだけ使用する。永続的identity、ordering key、idempotency key、WIP validatorとして解釈しない。空の`requests` arrayはvalidであり、Hostは空の`responses` arrayを返す。
`call_operation`はこのretrieval batchへ含めない。`v1/batch`のmethod集合は`observe`と`fetch_interface`だけであり、Operation executionを分類または推測して拡張しない。
### Request validation
次はbatch全体の`invalid_request`である。
- Top-level envelopeを解釈できない。
- `requests`がない、arrayでない、または未知top-level fieldがある。
- Itemに`id`、`method`、`arguments`がない、または未知item fieldがある。
- `id`がstringでない、または重複する。
- `method`が未知である。
既知の`method`を持つitemの`arguments`が、そのlogical requestとして不正な場合はbatch全体を拒否しない。その`id`のsubresponseへ`invalid_request`を返す。他itemは独立して処理する。
Batch requestを交換可能な件数やsizeはHTTP implementationとdeploymentの運用事項であり、本bindingは規定しない。それらの都合でbatch requestを交換できない場合はTransport failureであり、`resource_limit_exceeded`へ変換しない。各valid subrequestについてProtocol上のlogical limitを超えた場合は、そのitemへ`resource_limit_exceeded`を返せる。
### Response envelope
Validなbatch envelopeへは、一部または全部のitemがProtocol failureでも`200 OK`を返す。
```json
{
"responses": [
{
"id": "entry-123",
"result": {
"object": {
"name": "123",
"interfaces": ["item-interface-v1"]
}
}
},
{
"id": "item-interface",
"error": {
"code": "interface_not_found",
"message": "Interface is not currently published"
}
}
]
}
```
Top-level objectはrequiredな`responses` arrayだけを持つ。各subresponseはstring `id`と、`result`または`error`のちょうど一方を持つ。その他のmemberを持たない。
- `result`は対応するinteractionを単独で呼んだ場合のsuccess bodyと同じJSON valueである。
- `error`はenvelopeで包まない直接の`{"code": ..., "message": ...}` objectである。
- ItemごとのHTTP statusを含めない。
- Item error codeは対応interactionで許可されたものに限る。
Response array順に意味を持たせず、`id`でcorrelateする。Hostはrequestに含まれた各`id`についてちょうど一つのsubresponseを返す。Response IDは重複せず、要求されていないIDを追加せず、要求されたIDを欠落させない。Clientはexact correlationに違反するresponse全体を`InvalidResponse`として拒否する。
Hostはsubrequestを直列または並列に実行してよい。各subrequestは個別に実行した場合と同じ意味を持つ。Batchはatomicではなく、共通snapshot、実行順序、read-your-previous-resultを保証しない。先行resultを後続argumentsから参照する構文はない。
### Top-level batch failure
Batch envelopeをitem列として解釈できない場合、またはitem処理を開始する前後にbatch response全体を構築できないHost failureが起きた場合は、通常のtop-level Protocol error envelopeを返す。
Top-level batch failureで許可するcodeは次だけである。
| Code | Status |
| --- | --- |
| `invalid_request` | `400 Bad Request` |
| `internal` | `500 Internal Server Error` |
Batchは取得interactionだけを含むため、physical exchangeが失敗した場合、Clientは必要なitemをboundedなpolicyで再取得できる。どのitemがHostで完了したかを推測してKnown Spaceへ反映しない。
## HTTP facilitiesとの境界
HTTP cache、proxy、gateway、compression、connection管理、TLS、message size、timeout、concurrency、rate limit等の設定と運用は、本bindingの規定対象外である。
HTTP cache metadataはWIP ClientのKnown Space、Interface cache、Object validator、Interface validatorとは別の機構である。`ETag`、`If-Match`、Age、Last-Modified等をWIP observationまたはvalidatorとして解釈しない。それ以外のHTTP cache policyはHTTP implementationとdeploymentが決定する。
HTTP implementationまたはdeploymentの都合でrequestまたはresponseを交換できない場合、ClientはTransport failureとして扱う。WIPはそれらの運用設定を規定せず、そのfailureを`resource_limit_exceeded`その他のProtocol errorへ包み直さない。
## 非目標
本bindingは次を定義しない。
- Host内部のAPI、database、filesystem、queueとの接続方法。
- Endpoint discovery service。
- 固定のauthentication scheme。
- HTTP cacheを使ったWorldspace同期。
- Operation idempotency keyまたはexactly-once execution。
- Operation cancellation protocol。
- Streaming、subscription、server push、WebSocket binding。
- `call_operation`のbatching。
- Domain failureの共通HTTP mapping。
+1 -13
View File
@@ -1,6 +1,6 @@
# 未解決事項 # 未解決事項
主要な未解決事項を、canonicalなCore文書とTransport Bindingへのindexとしてまとめる。 主要な未解決事項を、canonicalなCore文書へのindexとしてまとめる。
## 2.2. Interface / Operation ## 2.2. Interface / Operation
@@ -12,7 +12,6 @@
- Descriptor version間の互換性規則。 - Descriptor version間の互換性規則。
- 現在plain textであるDocumentationへmarkup、localization、構造化exampleを追加するか。 - 現在plain textであるDocumentationへmarkup、localization、構造化exampleを追加するか。
- Signature Viewのfull renderingをどこまで標準化するか。 - Signature Viewのfull renderingをどこまで標準化するか。
- Effect annotationを採用するか。
- 現在Unionで表すDomain failureへ専用declarationを追加するか。 - 現在Unionで表すDomain failureへ専用declarationを追加するか。
## 3. Protocol ## 3. Protocol
@@ -28,18 +27,7 @@
- String length、numeric range、pattern等のconstraintを導入するか。 - String length、numeric range、pattern等のconstraintを導入するか。
- 現在拒否するrecursive named typeを許可するか。 - 現在拒否するrecursive named typeを許可するか。
- `i64`、`u64`、`bigint`、`decimal`等を追加するか。 - `i64`、`u64`、`bigint`、`decimal`等を追加するか。
- `json` escape hatchをすべてのTransport Bindingへ要求するか。
### Interaction / Error ### Interaction / Error
- `observe`のdepthへ相互運用上の共通上限を定義するか。
- ProtocolErrorへstructured detailを追加するか。 - ProtocolErrorへstructured detailを追加するか。
- Resource limitを固定値またはcapability negotiationのどちらで定義するか。
## WIP over HTTPS
対象: [WIP over HTTPS](wip-over-https.md)
- Protocol primitive、Object、Interface Descriptor、ValueのJSON encoding。
- Batch件数、request / response byte size、timeoutの具体的な上限。
- Effect annotationを採用した場合に、副作用のない`call_operation`をbatch対象へ加えるか。
-410
View File
@@ -1,410 +0,0 @@
# WIP over HTTPS
WIP over HTTPSは、[WIP Protocol](../3-protocol.md)のlogical data modelをHTTPS上へ対応付ける標準Transport Bindingである。
## 目的
Protocolの意味論を変えずに、既存のWeb infrastructureを利用してClientとHostを接続する。
## 方針
初期の標準bindingはHTTPS上のrequest / responseのみを規定する。TLS、認証、Proxy、Gateway、Observability、Caching、connection reuse、multiplexing、compression等の既存機構を利用してよいが、特定のHTTP versionや実装方式を必須にしない。
OperationがWebSocket等のendpointを通常のApplication dataとして返すことは妨げない。そのendpoint上のprotocol、状態、lifecycleはWIPの規定対象外であり、ClientとHost固有実装の責務とする。
双方向socket transportをWIP bindingとして標準化する場合は、将来の独立した拡張として定義する。
## Binding対象
少なくとも、Protocolの以下のinteractionをHTTP request / responseへ対応付ける。
- `observe`
- `fetch_interface`
- `call_operation`
HTTP method、endpoint、content type、success / error response、Protocol errorのHTTP status、validator mapping、authenticationの位置付けは以下で定義する。Batch表現の残る詳細も、このbinding仕様側で定義する。
## Endpointとroute
WIP endpointは、一つのWorldspace access surfaceを指すabsolute HTTPS URLである。Endpoint URLのpath prefixはdeploymentが任意に選択できる。Clientはorigin直下や`/wip`等の既定prefixを仮定しない。
Endpoint URLはqueryとfragmentを持たず、pathが`/`で終わるcanonical formとする。利用者から末尾`/`のないURLを受け付ける実装は、routeを解決する前に`/`を追加してcanonical formへ変換する。
各routeはendpoint URLをbase URLとして、次のrelative pathをRFC 3986に従って解決する。すべてのinteractionは`POST`を使用する。
| Interaction | HTTP method | Relative path |
| --- | --- | --- |
| `observe` | `POST` | `v1/observe` |
| `fetch_interface` | `POST` | `v1/fetch_interface` |
| `call_operation` | `POST` | `v1/call_operation` |
| batch | `POST` | `v1/batch` |
`v1`はWIP over HTTPS Bindingのmajor versionである。Interactionごとに独立したrouteを設定したり、固定suffixを別名へ置き換えたりしない。
例えば、次のendpointを指定した場合、
```text
https://gateway.example/tenants/acme/proxies/filesystem/wip/
```
`observe` routeは次になる。
```text
https://gateway.example/tenants/acme/proxies/filesystem/wip/v1/observe
```
Endpointのpath prefixはHTTP deployment上のroutingであり、Worldspace内のpathではない。Worldspace pathは常に各WIP requestのlogical fieldとして渡す。Hostまたはreverse proxyは異なるbase pathに複数のWorldspaceやproxy surfaceをmountできるが、一つのendpointに属するinteractionはすべて同じbase URL配下へ公開する。
Clientは異なるcanonical endpoint間でKnown Space、Object observation、Interface cacheを混在させない。同じendpointであっても認証またはsecurity contextによって異なるWorldspaceが見える場合、それらの観測状態を共有しない。
## HTTP message
Requestおよびbodyを持つresponseは`Content-Type: application/json`を使用し、JSON textをUTF-8でencodeする。Clientは`Accept: application/json`を送信する。
WIP routeで受信したbodyがmalformed JSONである、logical request structへdecodeできない、required fieldがない、未知fieldがある、またはfield semanticsに違反する場合、Hostは`400 Bad Request`と`invalid_request` envelopeを返す。Unsupported media typeは`415 Unsupported Media Type`、受理できない`Accept`は`406 Not Acceptable`とし、これらTransport BindingのfailureをProtocol errorへ変換しない。
単独interactionが成功した場合、Hostは`200 OK`を返し、response bodyへ対応するProtocol responseを直接encodeする。単独interactionのsuccess bodyを`result`等の追加envelopeで包まない。
Protocol failureの場合、Hostは非2xx statusを返し、response bodyへ後述するProtocol error envelopeをencodeする。HTTP statusは成功と失敗の大分類および既存HTTP infrastructureのための補助情報であり、Protocol failureの機械可読な意味を決定しない。ClientはHTTP status、reason phrase、または人間向けmessageからProtocol error codeや回復actionを推測しない。
非2xx responseが有効なProtocol error envelopeを含まない場合、Clientは特定のProtocol errorへ変換せず、HTTPまたはTransport Bindingのfailureとして扱う。これにより、reverse proxyやgatewayが生成したresponseをHost由来の`NotFound`、`PermissionDenied`等と誤認しない。
Clientに再観測、WIP request修正、Operationの権限要求、resource削減等の具体的なactionを求めるProtocol failureは、HTTP statusだけで表さず、対応する`ProtocolErrorCode`としてProtocolに定義する。
## Authentication
WIP over HTTPSは特定のauthentication schemeを要求せず、HTTP authentication、mTLS、gateway、reverse proxy等の既存infrastructureを使用できる。AuthenticationはWIP interactionを実行する主体とsecurity contextを確立するTransport / deployment concernであり、WIP Protocolの`ProtocolErrorCode`を追加して表現しない。
Credentialが欠落または無効でWIP interactionを開始できない場合、HTTP layerは`401 Unauthorized`と、使用するschemeに応じた`WWW-Authenticate`を返してよい。HTTP layerは、特定のWIP endpointが表すWorldspace access surface全体へのaccessを認めない場合に、そのendpointへのrequestを`403 Forbidden`等で拒否してよい。ClientはこれらをProtocol failureへ変換せず、Transport authentication / authorization failureとして扱う。
HTTP layerによるWorldspace全体のaccess controlを通過してWIP interactionを開始した後は、個別Objectへのaccess拒否を「Objectは存在するが閲覧禁止」という状態として公開しない。その主体へ公開しないObjectはClient-facing Worldspaceに存在しないものとして扱い、`observe`と`call_operation`では`NotFound`を返す。個別Objectの存在を示唆する`PermissionDenied`や、Protocol error envelopeを持たない`403 Forbidden`へ置き換えない。
Authentication後に確立された主体に対するInterface / Operation visibilityとOperation authorizationもWIP Protocol semanticsに従う。現在公開されていないInterfaceには`InterfaceNotFound`、現在のInterfaceに宣言されていないOperationには`OperationNotFound`を返す。`PermissionDenied`は、現在公開されているOperationの存在を示したうえで、その主体による実行だけを拒否する場合に使用する。
## JSON encodingの基本規則
ProtocolのrecordはJSON object、listはJSON array、optional fieldの省略はJSON fieldの省略としてencodeする。
Protocol structの`String`はJSON string、`Vec<u8>`はRFC 4648 Section 4のbase64 stringへ対応付ける。Path、Interface参照、Object identity、名前等の意味はJSON typeではなくfieldの位置によって決まる。
| Field | JSON encoding | 解釈 |
| --- | --- | --- |
| `path` | string | canonical absolute Worldspace path |
| `name`、Operation / Type / Field / Parameter / Case名 | string | 各struct内の名前 |
| `interfaces` | stringのarray | Objectが公開するInterface参照のordered set |
| `interface`、`InterfaceTarget.reference` | string | 一つのInterfaceへのopaqueな参照 |
| `format` | string | Descriptor format identifier |
| `ref` | string | opaqueなObject identity |
| `validator` | RFC 4648 Section 4のbase64 string | opaqueな条件付き操作用value |
すべてのWIP validatorは、対応するProtocol struct上のfieldとしてJSON bodyへencodeする。HTTP headerへ移したことを理由にbody fieldを省略してはならない。Client runtimeはvalidatorをopaqueに扱い、AIやユーザーへ直接管理させない。
未知のJSON fieldを許可する箇所はProtocol側で明示する。Object、Interface Descriptor、request / response、Protocol errorの未宣言fieldは既定で拒否する。
## Objectとchildrenの観測
`observe` requestは起点pathとdepthを渡す。
```json
{
"path": "/items",
"depth": 1
}
```
Responseはrootの`ObjectObservation`を直接返す。各nodeは`object`とoptionalな`children`を持ち、各Objectのpathはrequest pathとchildrenの`name`から導出する。ValidatorはObjectのfieldとしてencodeする。
```json
{
"object": {
"name": "items",
"description": "Item collection",
"interfaces": [
"sha256:item-collection-interface"
],
"validator": "cm9vdC12YWxpZGF0b3I="
},
"children": [
{
"object": {
"name": "123",
"description": "First item",
"interfaces": [
"item-interface-v1",
"item-marker-interface-v1"
],
"ref": "item:123",
"validator": "aXRlbS12YWxpZGF0b3I="
}
}
]
}
```
`depth = 0`ではroot nodeの`children`を省略する。Nodeのdepthがrequestの`depth`より小さい場合は`children`を必ずencodeし、観測済みでemptyなら空arrayを使用する。Nodeがrequested depthに達した場合は`children` fieldを省略する。Optional fieldの省略をJSON `null`で置き換えない。
Success responseはrequested depthまで完全であり、部分的なsuccess responseは返さない。完全なresponseをresource budget内で構築できない場合、Hostは`resource_limit_exceeded`を返す。
## Interfaceの取得
ObjectはOperation定義を直接含まず、Interface Descriptorへの参照のordered setを持つ。`fetch_interface`は、そのうち一つの参照に対応する現在のDescriptorとoptionalなvalidatorを返す。
Conceptual requestは次の形になる。
```json
{
"interface": "item-marker-interface-v1"
}
```
Responseは次の形になる。
```json
{
"interface": "item-marker-interface-v1",
"descriptor": {
"format": "wip-interface/1",
"documentation": {
"summary": "Marker capability provided by an item."
},
"types": [],
"operations": []
},
"validator": "aW50ZXJmYWNlLXZhbGlkYXRvcg=="
}
```
Interface DescriptorはJSON-compatibleなlogical structとしてProtocolで定義される。JSONはHTTPS上のencodingであり、Interface実装者が手書きするauthoring形式ではない。
`validator`はInterface参照と組み合わせて解釈するoptionalなopaque bytesである。同じ参照とvalidatorの組は同じDescriptorを表す。Descriptorを変更可能にするHostはvalidatorを返して変更時に更新し、validatorを返さない参照は有効期間中immutableにする。
ClientはObjectの各Interface参照をcacheと比較し、未知の参照だけを`fetch_interface`する。Validatorが存在する観測は`(interface, validator)`の組でcacheし、Interface validator mismatch等で更新が必要になった参照は再取得する。Validatorを返さない参照は、その参照の有効期間中Descriptorをimmutableとしてcacheできる。HostはClientのcache状態を推測せず、`observe` responseへDescriptorを先行同梱しない。複数のInterface取得はHTTP batchingでまとめられる。
## Operation valueのJSON encoding
`call_operation`のargumentsとresultは、選択したOperation declarationに従うJSON valueとしてencodeする。
`arguments`はOperationのparameter名をfield名とするJSON objectとする。位置引数は用いず、引数を持たないOperationには空のobjectを渡す。
Conceptual request bodyは次の形になる。
```json
{
"target": {
"path": "/items/current",
"validator": "b3BhcXVlLXZhbGlkYXRvcg=="
},
"interface": {
"reference": "item-interface-v1",
"validator": "b3BlcmF0aW9uLWludGVyZmFjZQ=="
},
"operation": "get_related_item",
"arguments": {
"relation": "sibling",
"limit": 10
}
}
```
`interface.reference`はOperationを宣言する一つのInterfaceを明示し、現在のObjectの`interfaces`に含まれなければならない。異なるInterfaceに同名Operationがあっても、Hostは`interface.reference`と`operation`の組で解決する。表示用の`<interface-reference>.<operation-name>`を一つのrequest fieldとして送らない。
`fetch_interface`がvalidatorを返した場合、Clientは観測したDescriptorに対応する値を`interface.validator`へコピーする。これはDescriptor cache versionではなくOperation executionのpreconditionであり、HostはObject、Object validator、Interface membership、Interface validator、Descriptor、Operation implementation、backend対象を一つのlinearization pointで固定して検証・実行する。
ResponseはOperation resultと、実行後の現在状態に対してHostが発行したoptionalなObject validatorを返す。
```json
{
"result": {
"item": "/items/123"
},
"validator": "bmV3LXZhbGlkYXRvcg=="
}
```
RawなProtocol ValueからJSONへのmappingはbindingで一意に定める。
| Protocol value | JSON encoding |
| --- | --- |
| `Unit` | `null` |
| `Boolean` | boolean |
| `Integer` | safe integer範囲のnumber |
| `Number` | finiteなnumber |
| `String` | string |
| `Bytes` | RFC 4648 Section 4のbase64 string |
| `Record` | object |
| `List` | array |
`Entry`、Enum、Union、`Json`はraw Valueのvariantではなく、Interface Descriptorがprimitiveおよびcompositeへ与える解釈である。
| TypeExpr | JSON encoding |
| --- | --- |
| `Entry` | canonical absolute pathのstring |
| Enum | case名のstring |
| Union | `$case`とoptionalな`value`を持つobject |
| `Json` | 任意のJSON value。ただし`Bytes`を含まない |
Optionalなparameterまたはrecord fieldはfieldの省略で表し、`null`とは区別する。
Payloadを持つUnionは次のようにencodeする。
```json
{
"$case": "found",
"value": "/items/123"
}
```
Payloadを持たないUnionは`value`を省略する。
```json
{
"$case": "not_found"
}
```
ClientはInterface Descriptorに従ってvalueをdecodeし、`entry`と宣言された位置にあるstringだけをエントリとして認識する。通常の`string`やopaqueな`json`に含まれるpathらしいstringをエントリとして推測してはならない。
## Validatorのencoding
WIP Protocolのlogical fieldには、ObjectおよびOperation responseのObject `validator`、Operation requestの`target.validator`、`FetchInterfaceResponse.validator`、Operation requestの`interface.validator`がある。Object validatorとInterface validatorは別のpreconditionであり、それぞれ対応するJSON body fieldへRFC 4648 Section 4のbase64 stringとしてencodeする。
単独request / responseとbatch subrequest / subresponseは同じvalidator表現を使用する。HostはWIP validatorを`ETag`、`If-Match`、その他のHTTP headerだけにencodeしてbody fieldを省略してはならず、ClientはそれらのheaderをWIP validatorとして解釈しない。
Host、gateway、またはHTTP cacheは通常のHTTP representation metadataとして`ETag`等を追加してよいが、その値はWIP validatorとは独立しており、WIPのObject identity、Interface observation、またはOperation preconditionを置き換えない。
## Protocol error
Protocol failureは、非2xx HTTP responseのJSON bodyへ次のenvelopeでencodeする。
```json
{
"error": {
"code": "invalid_arguments",
"message": "Required argument `relation` is missing"
}
}
```
`code`はProtocolが定義する`ProtocolErrorCode`をsnake_caseへ変換した安定した識別子、`message`は人間向けのboundedな診断である。Clientは`message`の内容で分岐しない。Clientがfailureの種類と回復actionを決定するときは`code`を使用し、HTTP statusだけから`NotFound`、`InterfaceMismatch`、validator failure等を推測しない。
単独interactionのProtocol error codeを次のHTTP statusへ対応付ける。
| Protocol error code | HTTP status |
| --- | --- |
| `invalid_request` | `400 Bad Request` |
| `not_found` | `404 Not Found` |
| `interface_not_found` | `404 Not Found` |
| `interface_mismatch` | `409 Conflict` |
| `operation_not_found` | `404 Not Found` |
| `invalid_arguments` | `422 Unprocessable Content` |
| `validator_required` | `428 Precondition Required` |
| `validator_mismatch` | `412 Precondition Failed` |
| `interface_validator_required` | `428 Precondition Required` |
| `interface_validator_mismatch` | `412 Precondition Failed` |
| `permission_denied` | `403 Forbidden` |
| `resource_limit_exceeded` | `413 Content Too Large`または`422 Unprocessable Content` |
| `internal` | `500 Internal Server Error` |
| `operation_outcome_unknown` | `500 Internal Server Error` |
`resource_limit_exceeded`がrequestまたはresponse representationのbyte size超過を表す場合は`413 Content Too Large`、observation depth、nesting、collection件数等のlogical limit超過を表す場合は`422 Unprocessable Content`を使用する。Rate limitまたはconcurrency limitによる`429 Too Many Requests`はTransport / deployment concernであり、Core interactionの`resource_limit_exceeded`へ自動変換しない。
HTTP statusはProtocol error codeを置き換えない。複数のcodeが同じstatusを使用し、同じcodeがresource limitの種類に応じて異なるstatusを使用できる。Hostは上記mappingに従わなければならないが、Clientが非2xx responseからvalidなProtocol error envelopeを取得できた場合、statusがmappingと一致しなくても回復actionは`code`に従い、statusから別のcodeを推測しない。Clientはstatus mismatchをTransport Binding違反として診断してよい。2xx responseのerror envelope、または非2xx responseのsuccess bodyは`InvalidResponse`として扱う。
`operation_outcome_unknown`はretryを促す`503 Service Unavailable`へmappingしない。Clientは`500`であってもcodeに従い、Operationを自動再実行せず対象をstaleとして扱う。`internal`についてもEffect annotationがない現在のProtocolではOperationを自動再実行しない。
`InvalidResponse`と`UnsupportedDescriptorFormat`はClient-localなclassificationであり、Hostがerror envelopeで返してはならない。非2xx responseが有効なProtocol error envelopeを含まない場合も、Clientは特定のProtocol errorへ変換せずTransport Binding failureとして扱う。
Clientに特定の回復actionを求める条件をHTTP statusだけで新設しない。その条件がTransport Binding固有のfailureではなくWIP interactionとして回復可能である場合、対応する`ProtocolErrorCode`をProtocolへ追加してからbindingする。
Domain failureをProtocol errorへ変換しない。Domain failureはOperation resultのApplication dataとしてencodeする。
## HTTP batching
WIP over HTTPSは、複数の独立したCore取得requestを一つのHTTP requestへまとめるbatch形式を提供する。Batchingは通信上のpackagingであり、Protocolへ新しいinteractionや意味論を追加しない。
ClientはKnown SpaceとInterface cacheをもとに必要なrequestだけを選択してbatchを構成する。HostはClientの既知状態を推測して、要求されていないObjectやInterface Descriptorをresponseへ追加しない。
Batchは上記の`POST v1/batch` routeを使用し、bodyに一意な`id`を持つsubrequestの配列を格納する。
```json
{
"requests": [
{
"id": "entry-123",
"method": "observe",
"arguments": {
"path": "/items/123",
"depth": 0
}
},
{
"id": "item-marker-interface",
"method": "fetch_interface",
"arguments": {
"interface": "item-marker-interface-v1"
}
}
]
}
```
Hostは各subrequestを、単独で受け取った場合と同じ規則で処理する。Responseは同じ`id`で対応付けたsubresponseの配列を返す。
```json
{
"responses": [
{
"id": "entry-123",
"result": {
"object": {
"name": "123",
"description": "First item",
"interfaces": [
"item-interface-v1",
"item-marker-interface-v1"
],
"ref": "item:123",
"validator": "b3BhcXVlLXZhbGlkYXRvcg=="
}
}
},
{
"id": "item-marker-interface",
"result": {
"interface": "item-marker-interface-v1",
"descriptor": {
"format": "wip-interface/1",
"types": [],
"operations": []
},
"validator": "aW50ZXJmYWNlLXZhbGlkYXRvcg=="
}
}
]
}
```
Batchには次の規則を適用する。
- Request内の`id`は一意なstringとする。
- Responseの順序に意味を持たせず、`id`でcorrelateする。
- 各subrequestは独立して成功または失敗し、一つの失敗によって他のresultを破棄しない。
- Batch全体はtransactionではなく、atomicity、共通snapshot、実行順序を保証しない。
- Hostはsubrequestを直列または並列に実行してよい。
- Subrequest間で、先行requestのresultを後続requestのargumentsとして参照できない。
- 各`result`は対応するProtocol interactionを単独で呼んだ場合と同じvalueとする。
- 各`error`は通常のProtocol errorと同じschemaを使用する。
- HostはClientが要求していないsubresponseを追加してはならない。
- 各subresponseは`result`または`error`の一方だけを持つ。
初期のbatch形式に格納できるのは`observe`と`fetch_interface`とし、`call_operation`は含めない。将来Effect annotationを採用する場合に、副作用を持たないと明示されたOperationをbatch対象へ加えるかを改めて検討する。
Batch envelopeがvalidである場合、Hostは一部または全部のsubrequestがProtocol failureでも`200 OK`を返す。各subresponseの`error`は対応するinteractionで許可されたProtocol errorの`code`と`message`を直接含み、itemごとのHTTP statusは持たない。
`requests`の欠落、duplicate `id`、未知の`method`、subrequest envelope自体のfield違反等によりbatch全体をsubrequest列として解釈できない場合、Hostは`400 Bad Request`とtop-levelの`invalid_request` error envelopeを返す。既知の`method`を持つsubrequestの`arguments`が対応するlogical requestとして不正な場合は、batch全体を拒否せず、その`id`のsubresponseへ`invalid_request`を返す。Batch requestのbyte size超過には`413 Content Too Large`、件数等のlogical limit超過には`422 Unprocessable Content`を使用し、いずれもtop-levelの`resource_limit_exceeded` error envelopeを返す。
Batch件数、request / response byte size、timeoutの具体的な上限はbindingの運用profileまたはHost configurationでboundedに定める。
## 非目標
WIP over HTTPSはHost内部のAPIやdata source接続方式を規定しない。また、WIP ProtocolそのものをHTTP依存のmodelへ変えることも目的としない。