From d7e60d26595f9de48548a34dc940848c75404424 Mon Sep 17 00:00:00 2001 From: Hare Date: Fri, 2 Oct 2026 01:51:10 +0900 Subject: [PATCH] docs: define canonical transport bindings --- 2-core-model.md | 4 +- 3-protocol.md | 19 +- 4-client.md | 4 +- 5-transports.md | 79 ++++ 5.1-wip-over-http.md | 786 +++++++++++++++++++++++++++++++++++++ draft/unresolved-issues.md | 14 +- draft/wip-over-https.md | 410 ------------------- 7 files changed, 881 insertions(+), 435 deletions(-) create mode 100644 5-transports.md create mode 100644 5.1-wip-over-http.md delete mode 100644 draft/wip-over-https.md diff --git a/2-core-model.md b/2-core-model.md index cb039e1..e98ec80 100644 --- a/2-core-model.md +++ b/2-core-model.md @@ -2,7 +2,7 @@ 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を要求しない。 -通信方式、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、通信方式を独立して進化させる。 diff --git a/3-protocol.md b/3-protocol.md index 0788c77..c39fdbc 100644 --- a/3-protocol.md +++ b/3-protocol.md @@ -4,7 +4,7 @@ WIP Protocolは、ClientとHostの間で交換するlogical data modelと、Core この章の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の分類 @@ -153,6 +153,8 @@ Hostは、どの状態変化によってObject validatorを無効にするかに 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の整合性 同じWorldspace内で同じ`ref`を持つObjectは、一つの共有された現在状態を表す。 @@ -525,7 +527,7 @@ Hostは一つのlinearization pointで、現在のObject identityと状態、Obj 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の生成方法または内容に基づいて分岐してはならない。 @@ -602,7 +604,7 @@ Validatorおよび観測関連errorの回復対象は次のとおりである。 同じOperationを再試行するなら、先に新しい観測を取得しなければならない。 - `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固有の照会手段を利用者へ提示する。 @@ -623,7 +625,7 @@ Transport BindingはProtocol Resultをstatus code、response envelope、stream t HostとClientは、untrusted inputによるresource exhaustionを避けるため、少なくとも次へ上限を設ける。 - Pathとして解釈するstring、validator、name、description、documentationの長さ。 -- Interface Descriptor全体のbyte数。 +- Interface Descriptor内のdeclaration、documentation、field等の総量。 - ObjectごとのInterface参照数。 - Type declaration、Operation、parameter、field、caseの数。 - TypeExprとValueのnesting depth。 @@ -631,9 +633,9 @@ HostとClientは、untrusted inputによるresource exhaustionを避けるため - `observe`のdepthとresponse node数。 - 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 @@ -641,7 +643,7 @@ BatchはCore interactionではなくTransport Bindingのoptimizationである。 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の要件 @@ -654,6 +656,7 @@ Transport Bindingは、この章のlogical structについて次を定義する - Protocol failureのmapping。 - Object validator、Interface validator、Operation preconditionのmapping。 - 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を失ってはならない。 diff --git a/4-client.md b/4-client.md index a0cae9e..a00dbaf 100644 --- a/4-client.md +++ b/4-client.md @@ -132,10 +132,10 @@ ClientはHostが返すProtocol errorの`code`で回復actionを決定し、人 同じOperationを再試行するなら、先に新しい観測を取得しなければならない。 - `InvalidRequest`または`InvalidArguments`では同じrequestを変更せずに再送しない。 -- `ResourceLimitExceeded`ではrequest sizeやobservation depth等を削減できるが、Operationを自動再実行しない。 +- `ResourceLimitExceeded`ではlogical request shapeやobservation depth等を削減できるが、Operationを自動再実行しない。 - `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`へ変換しない。 diff --git a/5-transports.md b/5-transports.md new file mode 100644 index 0000000..944473c --- /dev/null +++ b/5-transports.md @@ -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`は独立して検証する。 diff --git a/5.1-wip-over-http.md b/5.1-wip-over-http.md new file mode 100644 index 0000000..2ff02e7 --- /dev/null +++ b/5.1-wip-over-http.md @@ -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`は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である。表示用の`.`を一つの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。 diff --git a/draft/unresolved-issues.md b/draft/unresolved-issues.md index b825404..62580ce 100644 --- a/draft/unresolved-issues.md +++ b/draft/unresolved-issues.md @@ -1,6 +1,6 @@ # 未解決事項 -主要な未解決事項を、canonicalなCore文書とTransport Bindingへのindexとしてまとめる。 +主要な未解決事項を、canonicalなCore文書へのindexとしてまとめる。 ## 2.2. Interface / Operation @@ -12,7 +12,6 @@ - Descriptor version間の互換性規則。 - 現在plain textであるDocumentationへmarkup、localization、構造化exampleを追加するか。 - Signature Viewのfull renderingをどこまで標準化するか。 -- Effect annotationを採用するか。 - 現在Unionで表すDomain failureへ専用declarationを追加するか。 ## 3. Protocol @@ -28,18 +27,7 @@ - String length、numeric range、pattern等のconstraintを導入するか。 - 現在拒否するrecursive named typeを許可するか。 - `i64`、`u64`、`bigint`、`decimal`等を追加するか。 -- `json` escape hatchをすべてのTransport Bindingへ要求するか。 ### Interaction / Error -- `observe`のdepthへ相互運用上の共通上限を定義するか。 - 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対象へ加えるか。 diff --git a/draft/wip-over-https.md b/draft/wip-over-https.md deleted file mode 100644 index 863f7ec..0000000 --- a/draft/wip-over-https.md +++ /dev/null @@ -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`は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`の組で解決する。表示用の`.`を一つの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へ変えることも目的としない。