docs: refine operation interfaces and batching

This commit is contained in:
2026-09-10 02:09:16 +09:00
parent b42b4150e5
commit 82c558cf44
10 changed files with 279 additions and 129 deletions
+100 -46
View File
@@ -1,16 +1,19 @@
# WIP IDL
WIP IDLは、Operationのinput / outputを記述するための小さなinterface definition languageである。
WIP IDLは、Objectが実装するInterfaceを記述するための小さなinterface definition languageである。
WIP IDLのsourceそのものをschemaのcanonicalな交換形式とする。HostとClientの間でJSON SchemaやIDLを変換したJSON ASTを交換することは前提としない。Clientはsourceをparseして内部表現を構築し、必要に応じてAI Tool schemaやGUI formへ投影する
一つのWIP IDL documentが一つのInterfaceを定義する。Documentに宣言された関数の集合が、そのInterfaceのOperation集合となる。Operation名、parameter、return type、documentationはIDL内の一つの宣言としてまとめ、別のOperation descriptorへ重複して記述しない
WIP IDLのsourceそのものをInterface定義のcanonicalな交換形式とする。HostとClientの間でJSON SchemaやIDLを変換したJSON ASTを交換することは前提としない。Clientはsourceをparseして内部表現を構築し、必要に応じてAI Tool schemaやGUI formへ投影する。
この文書では、WIP IDLの初期文法と型を定義する。
## 設計方針
- Operation境界の型だけを表現する。
- 一つのdocumentで一つのInterfaceを定義する。
- Document内のOperation declarationを、そのInterfaceのOperation一覧とする。
- Operationを関数として、parameterとreturn typeを一体で表現する。
- 文法を小さく保ち、一般的なschema validation languageにはしない。
- Operationのinputは名前付きfieldを持つrecordとする。
- Wire上の値表現はTransport Bindingが定める。
- JSON SchemaはWIPの交換形式にせず、必要なClientが生成する。
- Worldspaceのエントリは、そのpathを表す`entry`型として扱う。
@@ -19,7 +22,16 @@ WIP IDLのsourceそのものをschemaのcanonicalな交換形式とする。Host
WIP IDL sourceはUTF-8 textとする。ASCII space、tab、LFによる空白は、tokenを分離する場合を除いて意味を持たない。
`//`から行末まではcommentとし、parserは無視する。
`//`から行末までは通常のcommentとし、parserは無視する。
`///`から行末まではdocumentation commentとする。Operationまたはtype declarationの直前に連続するdocumentation commentは、そのdeclarationのdocumentationとしてparserが保持する。
```wip
/// Returns entries related to the target Object.
operation get_related_items() -> {
items: [entry],
};
```
IdentifierはASCIIの英字または`_`で始まり、以降にASCIIの英数字または`_`を含められる。
@@ -29,7 +41,7 @@ identifier = (ALPHA | "_") { ALPHA | DIGIT | "_" };
Keyword、primitive type名、Worldspace固有型名はidentifierとして使用できない。
Named typeにはUpperCamelCase、Operation、field、enum case、union caseにはsnake_caseを使用する。
Named typeにはUpperCamelCase、Operation、parameter、field、enum case、union caseにはsnake_caseを使用する。
## Grammar
@@ -38,17 +50,21 @@ Named typeにはUpperCamelCase、Operation、field、enum case、union caseに
```ebnf
document = { declaration } ;
declaration = type-declaration | operation-declaration ;
declaration = [ documentation ],
( type-declaration | operation-declaration ) ;
documentation = doc-comment, { doc-comment } ;
type-declaration = "type", type-name, "=", type-definition, ";" ;
type-definition = type-expression | enum-type | union-type ;
operation-declaration =
"operation", identifier, "{",
"input", ":", type-expression, ";",
"output", ":", type-expression, ";",
"}" ;
"operation", identifier,
"(", [ parameter, { ",", parameter }, [ "," ] ], ")",
"->", type-expression, ";" ;
parameter = identifier, [ "?" ], ":", type-expression ;
type-expression =
primitive-type
@@ -86,13 +102,13 @@ worldspace-type = "entry" ;
type-name = identifier ;
```
同じdocument内でtype名またはOperation名を重複して宣言してはならない。Named typeは同じdocument内で宣言されたtypeを参照する。
同じdocument内でtype名またはOperation名を重複して宣言してはならない。同じOperation内でparameter名を重複してはならない。Named typeは同じdocument内で宣言されたtypeを参照する。
## Primitive types
| Type | 意味 | WIP over HTTPSでの表現 | 制約 |
| --- | --- | --- | --- |
| `unit` | 値を持たない | JSON `null` | Optional fieldの省略とは区別する |
| `unit` | 値を持たない | JSON `null` | Optional parameter / fieldの省略とは区別する |
| `boolean` | 真偽値 | JSON boolean | — |
| `integer` | 符号付き整数 | 小数部を持たないJSON number | `-9007199254740991`以上、`9007199254740991`以下 |
| `number` | IEEE 754 binary64値 | JSON number | NaN、positive infinity、negative infinityは不可 |
@@ -102,7 +118,7 @@ type-name = identifier ;
`integer`の範囲は、異なる言語のClient間で正確に交換できる範囲に制限している。この範囲を超える整数は`integer`としてencodeしない。`i64``u64``bigint`等の追加型とlosslessなwire表現は将来の拡張として扱う。
`json`は外部APIの応答など構造を事前に固定できない値のためのescape hatchであり、通常のOperation interfaceではより具体的な型を優先する。
`json`は外部APIの応答など構造を事前に固定できない値のためのescape hatchであり、通常のOperationではより具体的な型を優先する。
## Composite types
@@ -119,13 +135,13 @@ type-name = identifier ;
Recordは名前付きfieldの集合である。
```wip
type Query = {
text: string,
limit?: integer,
type QueryResult = {
items: [entry],
next_cursor?: string,
};
```
`?`を持たないfieldはrequired、`?`を持つfieldはoptionalである。Optionalはrecord fieldにのみ適用し、一般化しない。
`?`を持たないfieldはrequired、`?`を持つfieldはoptionalである。Optionalはparameterまたはrecord fieldにのみ適用し、一般化しない。
WIP over HTTPSではrecordをJSON objectとしてencodeする。Optional fieldに値がない場合はfield自体を省略する。FieldをJSON `null`にすることは省略と同じ意味ではなく、そのfieldの型が`unit`または`json`として`null`を許す場合に限る。
@@ -210,7 +226,7 @@ Payloadを持たないcaseには`value`を含めない。
Wire上では通常の`string`と同じ表現だが、WIP IDL上で`entry`と宣言された位置にある値だけをClientがエントリとして認識する。通常の`string`やopaqueな`json`に含まれるpathらしい文字列を、Clientがエントリとして推測してはならない。
Operation Resultから`entry`を発見したClientは、そのpathを一時的に利用し、必要に応じて`fetch`または`fetch_tree`する。複数のpathを効率的に取得するためのbatchingや、取得結果をinvoke responseへ同梱する最適化は、`entry`型のwire表現とは分離する
Operation Resultから`entry`を発見したClientは、そのpathを一時的に利用し、必要に応じて`fetch`または`fetch_tree`する。複数のpathを効率的に取得する場合は、Clientが必要なpathを選択した後、Transport Bindingが提供するbatchを利用する。Operation Resultへエントリ公開情報を先行同梱しない
Operationが返したpathは、Operationの実行対象の子に限定されない。親、兄弟、関連Objectなど、Worldspace内の任意のエントリを指してよい。Operationの実行対象と返されたpathの間に、暗黙のTree edgeや意味的関係を推論してはならない。
@@ -218,7 +234,7 @@ Operationが返したpathは、Operationの実行対象の子に限定されな
## Operation declarations
Operationはinputとoutputをそれぞれ一つ宣言する。
Operationは名前付きparameterとreturn typeを一つの関数宣言として定義する。
```wip
type Relation = enum {
@@ -227,55 +243,93 @@ type Relation = enum {
related,
};
operation get_related_item {
input: {
relation: Relation,
limit?: integer,
};
output: {
items: [entry],
next_cursor?: string,
};
}
/// Returns entries related to the target Object.
operation get_related_items(
relation: Relation,
limit?: integer,
) -> {
items: [entry],
next_cursor?: string,
};
```
Operationのinputは、直接またはNamed typeを介してrecordへ解決されなければならない。位置引数は定義しない。
Operationのparameterは、WIP over HTTPSでは一つのJSON objectへencodeする。Parameter名がobjectのfield名になる。位置引数は定義しない。
引数を持たないOperationは空のrecordをinputにする
引数を持たないOperationは空のparameter listで宣言し、空のJSON objectをargumentsとして渡す
```wip
operation refresh {
input: {};
output: unit;
}
operation refresh() -> unit;
```
Outputには任意のtype expressionまたはNamed typeを使用できる。ただし、将来fieldを追加する可能性があるOperationではrecord outputを推奨する。
Return typeには任意のtype expressionまたはNamed typeを使用できる。ただし、将来fieldを追加する可能性があるOperationではrecordを推奨する。
Operationのnameやdescriptionなど、input / output型以外のinterface metadataとの対応付けは[Operation schema](../2.2-operation.md)で定義する
`///` documentation commentは、AIやユーザーがOperationの用途を判断するための短いdescriptionとして扱う。長文documentationをIDLへ埋め込むことは想定しない
## Schema exchange
## Effect annotation(検討案)
HostはOperation interfaceとともに、次のschema情報をClientへ提供する
Operationがdomain-levelな副作用や失敗を発生させ得ることを、関数宣言上のeffect rowとして表す案を検討する。この節は確定仕様ではなく、前掲のEBNFにもまだ含めない
構文は、return typeの後に`! { ... }`を付ける形を候補とする。
```wip
operation get_item(
id: string,
) -> Item ! {};
operation update_item(
id: string,
value: Item,
) -> Item ! {
write,
fail<UpdateError>,
};
```
| Annotation | 意味の候補 |
| --- | --- |
| `! {}` | 宣言上、domain-levelな副作用およびfailureを持たない |
| `write` | 外部から観測可能な副作用を発生させ得る |
| `fail<E>` | `E`型のdomain failureを返し得る |
| annotationなし | Effect情報が未指定 |
Network error、authorization失敗、target消失、Protocol decode errorなど、すべてのremote callで起こり得るProtocol errorは`fail<E>`に含めない。`fail<E>`はOperation固有のdomain failureだけを表す候補とする。
Effect annotationは、ClientによるOperationの説明や、HTTP batchへ安全に含められるOperationの判定材料として利用できる可能性がある。ただし、具体的なbatch可否規則はまだ確定しない。
この案はKokaのeffect rowやUnisonのability requirementのように、関数が起こし得るeffectをsignatureへ表す記法を参考にしている。ただしWIP IDLへ導入するのは宣言上のannotationだけであり、effect handler、`perform`、continuation、resume、handlerへのnetwork転送、algebraic effect runtimeは導入しない。
## Interface identity and sharing
一つのWIP IDL documentが一つのInterfaceを定義する。ObjectはOperation定義ではなく、そのInterfaceへの参照を持つ。
複数のObjectが同じInterface参照を共有できる。Clientは未知のInterfaceだけを`fetch_interface`で取得し、参照ごとにIDL sourceとparse済み表現をcacheできる。
Hostは主体のroleや権限に応じて異なるOperation集合を投影する場合、異なるWIP IDL documentとInterface参照を返してよい。Interfaceは頻繁に変化するOperationの実行可否を表すものではない。
Interface参照をcontent-addressed digestにすることが想定されるが、参照形式、sourceのcanonicalization、digest algorithmはTransport Bindingで定義する。
## Interface exchange
HostはInterfaceについて、少なくとも次をClientへ提供する。
| 項目 | 内容 |
| --- | --- |
| Interface reference | Objectが保持し、`fetch_interface`の対象となる参照 |
| Language identifier | 初期versionは`wip-idl/1` |
| Source | WIP IDL source、またはsourceを取得するための参照 |
| Source | WIP IDL source |
| Digest | Cacheと同一性確認に利用するdigest |
交換されるschemaの正本はWIP IDL sourceである。HostはJSON SchemaやIDL ASTを併記する必要はない。
交換されるInterface定義の正本はWIP IDL sourceである。HostはJSON SchemaやIDL ASTを併記する必要はない。
ClientはIDLを内部ASTへparseし、必要に応じてAI provider用JSON Schema、GUI form、言語固有の型などを生成できる。
Sourceのcanonicalization規則、digest algorithm、参照方法の詳細はTransport Bindingで定義する
ClientはObjectのInterface参照をcacheと比較し、未知のInterfaceだけを`fetch_interface`する。複数のInterface取得はTransport Bindingでbatchできる。HostはClientのcache状態を推測せず、ObjectのresponseへInterface定義を先行同梱しない
## 未解決事項
- Sourceにdescriptionやdocumentation commentを含めるか
- Sourceのcanonicalizationとdigestの厳密な計算方法
- Interface参照の具体的な形式とscope。
- String length、numeric range、pattern等のconstraintを導入するか。
- Recursive named typeを許可するか。
- `i64``u64``bigint``decimal`等を追加するか。
- Sourceのcanonicalizationとdigestの厳密な計算方法。
- `entry`が参照するpathのcanonicalization規則。