# Rust API Model ## Status WIP HostをRustで実装する際、Interfaceの宣言とObjectの実装をどう組み合わせて公開するか。このdraftは、そのための概念的なAPI modelを提案する。 Trait名、attribute、derive、generated type名、method signatureは説明用であり、具体的なRust API syntaxは確定していない。Ownership、lifetime、async runtime、error type、macro crate構成も未決定である。 Protocol上の確定事項は[Core Model](../2-core-model.md)、[Object tree / Schema](../2.1-object-tree-schema.md)、[Operation and Interface](../2.2-operation-and-interface.md)、[Protocol](../3-protocol.md)に従う。動的なObject projectionの運用要件は[Dynamic Worldspace Projection](dynamic-worldspace-projection.md)、対応するTypeScript modelは[TypeScript API Model](typescript-api-model.md)を参照する。 ## 目的 Rust APIでは、Interfaceをtraitで宣言し、structで実装するmodelを自然に表現できるようにする。ただし、structが実装しているInterfaceと、ある時点で公開するInterfaceは分けて選べるようにする。 1. Rust traitでWIP Interfaceを宣言する。 2. Rust structが、Protocol Objectとして公開するmetadataを提供する。 3. 同じstructが、必要に応じて公開する0個以上のInterface traitを実装する。 4. Objectを返す時点で、公開するInterfaceのordered setを明示的に選択する。 5. Trait declarationからInterface Descriptor、Value codec、validation、Operation dispatchに必要なcodeを生成する。 6. Struct instanceをWorldspace全体について常駐させず、`observe`と`call_operation`の解決時にdata-drivenに生成できる。 Protocol上でObjectとInterfaceを関連付けるのは`Object.interfaces`だけである。Operation implementationを呼び出すためのRust内部codeはSDK / Host Runtimeの実装詳細として扱い、新しいProtocol conceptは導入しない。 ## Conceptual model ### Interface trait WIP Interfaceは、Rust traitとして宣言する。 ```rust #[wip::interface] trait FileInterface { /// Reads bytes from the file. async fn read( &self, /// Byte offset from the beginning of the file. offset: Option, /// Maximum number of bytes to return. length: Option, ) -> Bytes; /// Replaces the file contents. async fn write( &self, content: Bytes, ) -> WriteResult; } ``` このcodeはconceptual syntaxであり、具体的なAPIとして確定したものではない。`Option`の対応範囲、`Bytes` wrapper、documentationの取得方法、async methodとerrorの具体形は別途決定する。 Trait declarationとProtocol上の宣言は、次のように対応付ける。 - 一つのtrait declarationを、一つのInterface Descriptorを生成するRust側definitionとして扱う。 - Trait名はgenerated Rust itemやlocal registrationを識別するために使用できるが、Protocol `InterfaceDescriptor`のfieldや構造化されたInterface参照としてそのまま公開しない。 - Trait methodをOperation Declarationとして扱う。 - ReceiverはProtocol parameterに含めない。 - Method parameterを名前付きOperation parameterとして扱う。 - Return typeをOperation return typeとして扱う。 - Rust typeをDescriptorの`TypeExpr`とProtocol `Value`へ対応付ける。 - Documentationをtrait、method、parameter、return、関連typeから取得できるようにする。 したがって、Descriptorのshapeを決めるのはtrait declarationである。各structがそのtraitをどう実装するかによって、Descriptorは変化しない。 ### Object implementation その時点でWorldspaceへ投影するObjectは、Host内部ではRust structとして表現できる。 ```rust struct File { name: String, path: PathBuf, reference: Option, validator: Option>, } ``` 公開metadataを提供するために、structが概念上の`WipObject` traitを実装する形を想定する。 ```rust impl WipObject for File { fn name(&self) -> &str { &self.name } fn description(&self) -> Option<&str> { None } fn reference(&self) -> Option<&str> { self.reference.as_deref() } fn validator(&self) -> Option<&[u8]> { self.validator.as_deref() } } ``` `WipObject`は、Protocol Objectの公開metadataのうち、publication時に選ぶInterface集合以外を提供する。返す値のownershipやborrow形式は未決定である。 Structが保持する情報のすべてを公開metadataにするわけではない。次の情報は`WipObject`がProtocol metadataとして返す値に含めないが、implementing structのprivate fieldとして保持してよい。 - Absolute path。PathはObjectのfieldではなく、Worldspace resolutionのcontextである。 - Children。ChildrenはTree上の配置contextである。 - 固定されたInterface集合。InterfaceはObjectを公開する時点で追加する。 - Backend connection、file descriptor、credential等のHost-private state。 たとえば、structの`path`やbackend handleはHost内部のOperation implementationで使用できる。ただし、`WipObject`のmetadataやProtocol Objectへ自動的にserializeする対象にはしない。 ### Interface implementation Object implementationに使うstructは、公開したいInterface traitを実装する。 ```rust impl FileInterface for File { async fn read( &self, offset: Option, length: Option, ) -> Bytes { // self.pathが示す現在のfileを読む } async fn write( &self, content: Bytes, ) -> WriteResult { // self.pathが示す現在のfileへ書く } } ``` Trait implementationが提供するのはOperationのbehaviorである。Interface Descriptorの生成元は、このimplementationではなくInterface trait declarationとする。 また、traitを実装しただけでInterfaceを公開することにはしない。Rustには、あるtypeが実装しているtraitを列挙する一般的なreflectionがなく、一つのstructが複数のInterface traitを実装することもあるためである。 ### Object publication ObjectをWorldspaceへ返す時点で、struct instanceと、公開する0個以上のInterface Declarationを明示的に組み合わせる。Interfaceは追加順を保持するordered setとし、同じDefinitionの重複追加は認めない。 次のconceptual syntaxでは、解決した`File`に公開するInterfaceを追加している。 ```rust let file = File::resolve(path).await?; let object = PublishedObject::new(file) .expose(FileInterfaceDefinition); ``` 各`InterfaceDefinition`は、`#[wip::interface]`が生成するconceptualなcompanion definitionを表す。実際の名前も、associated item、module、valueのどの形で生成するかも未決定である。 Publication APIが各Definitionの追加に要求するboundは、概念的には次の形になる。 ```rust impl PublishedObject { fn expose(self, interface: I) -> Self where I: InterfaceDefinition; } impl InterfaceDefinition for FileInterfaceDefinition { // generated registration and dispatch metadata } ``` このboundで、公開する値がObject metadataを提供し、追加する各InterfaceのOperation implementationも提供することをcompile timeに確認できる。Interfaceを一つも追加しないObjectも表現できる。 `PublishedObject`はHost SDK内のconceptual typeであり、Protocol typeには追加しない。Host Runtimeはこの値からProtocol Objectを構築する。 ```rust Object { name: object.name(), description: object.description(), interfaces: selected_interface_references, r#ref: object.reference(), validator: object.validator(), } ``` `selected_interface_references`には、Hostが各generated Interface Definitionの登録または公開時に割り当てる構造化参照`{ scope, name }`を、publication APIへの追加順で並べる。同じ`(scope, name)`の重複は拒否し、Objectの配置pathに対する祖先制約も検証する。Macroが参照をcompile timeに固定することは要求しない。 `observe`でObjectに含めるのは、Descriptor自体ではなく、このInterface参照のordered setだけである。Clientが各参照を`fetch_interface`すると、Host Runtimeはtrait declarationから生成したDescriptorと、存在する場合はInterface validatorを返す。 同じ参照とvalidatorの組に対応するDescriptorは、Host上で共有およびcacheできる。このため、Object instanceごとにDescriptorを再生成したり再送したりする必要はない。 ## Macroが生成する責務 `#[wip::interface]`には、宣言からDescriptorを生成するだけでなく、Valueの変換・検証とdispatchに必要なcodeを提供する役割を想定する。 - Interface Descriptorを構築するdefinition。 - Trait methodとOperation Declarationの対応情報。 - ArgumentsのProtocol `Value` decoder。 - ResultのProtocol `Value` encoder。 - Argumentsとresultのruntime validation。 - Operation名から対応するtrait methodを呼び出すdispatch code。 - 任意の`T: WipObject + InterfaceTrait`について、そのInterfaceを`PublishedObject`へ追加するための型付きentry point。 - HostがInterface参照、optional validator、Descriptorを登録、取得、cacheするためのidentity。 対象structがInterface traitを実装しているかは、publication時のgeneric boundで確認する。MacroがRust codebase内のtrait implementationを探索したり列挙したりすることは要求しない。 Generated dispatch codeはRust SDK内部の実装詳細である。Host内部のdispatch mechanismやRust type名等はProtocolへ公開しない。 ## Rust typeとProtocol type Interface traitで使うRust typeには、Descriptorの`TypeExpr`とProtocol `Value`への対応付けが必要となる。概念的には、deriveまたは明示的なcodec implementationを使うことを想定する。 ```rust #[derive(WipType)] struct WriteResult { bytes_written: i64, } ``` ```rust #[derive(WipType)] enum ReadResult { Data { content: Bytes }, EndOfFile, } ``` このsyntaxも未決定である。Typeの対応付けでは、少なくとも次を表現できる必要がある。 - Unit、Boolean、Integer、Number、String、Bytes、Json、Entry。 - Record、List、Enum、Union。 - Descriptor内のNamed type。 - Requiredとoptionalなfieldおよびparameter。 - Documentation。 Rustの`Option`をoptional field / parameter以外でも許可するかは、まだ決めていない。EnumをProtocol EnumまたはUnionへどう対応付けるか、newtypeをどう扱うかも未決定である。 型の対応付けとは別に、Protocol boundaryでの検証も必要となる。Rust SDKは、integerのProtocol相互運用範囲、finite number、unknown field、Union shape、Entry path等をそこで検証しなければならない。 ## Dynamic Worldspaceでのlifecycle ### `observe` Projection implementationはrequest時にbackend dataを解決し、その時点のstruct instanceを生成する。 ```rust async fn resolve_file(path: &WipPath) -> Result { let stat = filesystem.stat(path).await?; let file = File { name: stat.name, path: stat.path, reference: make_reference(&stat), validator: make_validator(&stat), }; Ok(PublishedObject::new(file) .expose(FileInterfaceDefinition)) } ``` Host Runtimeは`PublishedObject`からProtocol Objectを返す。Responseを生成した後は、この`File` instanceを破棄してよい。Worldspace内の全fileに対応するinstanceを保持する必要はない。 Requested depthが正の場合は、Directory listingで発見した各entryについて、その時点のstruct instanceを生成して公開できる。Providerがdirectory全体を先に収集し、`Vec`として返すことは要求しない。ただし、一つのparentのobservationを成功させるには、公開されたindexable childrenをclean exhaustionまで列挙する必要がある。 ```rust let mut entries = filesystem.discover_children(path, budget).await?; while let Some(entry) = entries.next().await? { let Some(child) = project_current_object( entry.path(), context, ).await? else { continue; }; observation.push_child(child)?; } ``` `discover_children`、`budget`、`observation`は具体APIではなく、conceptualな表記である。Childの発見と公開には、次のsemanticsを要求する。 - 各childを現在の主体についてprojectし、非公開Objectとそのsubtreeを返さない。 - 公開されたindexable childrenをすべて列挙し、clean exhaustionで終了する。 - Backend failure、cancellation、resource budget超過をclean exhaustionとして扱わず、部分的なsuccess responseを返さない。 - Requested depthに達したnodeではchild discoveryを行わず、`children`を未観測として省略する。 - 異なるconcrete published typeを、Providerから共通のreturn typeとして扱える。 具体的なreturn type、internal streaming、backpressure、type erasure、error propagationは未決定である。 ### `call_operation` Call時には現在のObjectを解決し直す。HostはrequestのTargetと`InterfaceTarget`をHost Runtimeへ渡し、Runtimeは一つのatomic execution boundaryに入ってから、`target.path`を現在のObject implementationとstableなbackend対象へ解決する。 ```rust runtime.call_current( target, interface, operation, arguments, context, |path, context| resolve_current_projection(path, context), ).await ``` `resolve_current_projection`と`runtime.call_current`を実際のAPIとして採用するかは決めていない。ResolverはRuntimeが開始したexecution boundary内で呼ばれ、そのboundary中にObject identityとbackend対象を安定して保持するhandleまたはtransaction contextを含む値を返す必要がある。上のexampleは、次の要件を表す。 - 過去の`observe`で作成したstruct instanceを保持していなくてもOperationを実行できる。 - Call時の現在の主体、Object visibility、Object metadata、Interface集合を同じProjection pathで再解決し、Objectが非公開なら`NotFound`を返す。 - Requestの`interface.reference`が現在の`Object.interfaces`に含まれ、self-scopeを含む祖先制約を満たすことを確認する。指定された`interface.scope_ref`と現在のscope Objectの`ref`も照合し、満たせない場合は`InterfaceMismatch`を返す。`scope_ref`の省略だけでは拒否しない。 - 現在のInterfaceにOperationが宣言されていなければ`OperationNotFound`、Operationを公開しつつ実行だけを拒否する場合は`PermissionDenied`を返す。 - `interface.validator`を現在のInterface validatorへ照合する。Mutable Interfaceにvalidatorがなければ`InterfaceValidatorRequired`、不一致なら`InterfaceValidatorMismatch`を返す。 - 現在のProjected Object、Object validator、選択されたInterfaceとそのvalidator、Descriptor、Operation、Rust側のObject implementation、実際のbackend対象を一つのexecution boundary内で一致させる。 - Object validatorが指定されている場合は、現在のObject identityと保護対象状態の両方へ照合し、同じexecution boundary内でOperationを実行する。 - Pathが別Objectを指す場合は、provider-local revisionや内容が同じでもObject validatorを一致させない。 - Providerのvalidatorがobject-localなrevisionだけの場合、HostはObject identityを含む形へnamespace化またはwrapできなければならない。 - Object validatorが省略され、Operationがvalidatorを要求する場合は、実行せず`ValidatorRequired`を返す。 - Object validatorなしの実行をOperationが許可する場合は、実行時にpathが指す現在Objectへ無条件に実行する。 - Macro-generated dispatchが、選択されたInterface traitのmethodを現在のstruct instanceに対して呼び出す。異なるInterfaceの同名Operationをmergeまたは曖昧に解決しない。 - Operation実行後の現在状態に対応するvalidatorを、必要に応じて`CallOperationResponse`へ返せる。 Object validatorとObject identityの関連付けに、Client-facingな`ref`は必須ではない。ProviderまたはHostはHost-privateなidentityを使用できる。ただし、identity confirmation、Object validator比較、Interface membershipとvalidator比較、DescriptorとOperation implementationの固定、authorization、Operation実行は、一つのatomic boundaryで行う。 実行後のvalidatorをどこから取得するかも未決定である。同じstruct instanceから再計算する方式、Operation resultとともに返す方式、backendを再観測する方式が考えられるが、いずれもresultを生成した実行後状態とvalidatorを対応させる必要がある。 Structが`PathBuf`だけを保持している場合、validator比較後にpathを無条件で開き直すと、対象差し替えに対するatomicityを保証できないことがある。Rust APIには、file descriptor、transaction、conditional update、lock等でbackend固有のatomicityを実現できることを求める。そのための抽象化は未決定である。 ## 複数Interfaceの実装 一つのstructは、複数のInterface traitを実装できる。 ```rust impl ReadOnlyFileInterface for File { // ... } impl WritableFileInterface for File { // ... } ``` そのうち、現在の主体へ公開する0個以上のInterfaceをpublication時に選び、表示したい順に追加する。 ```rust let mut object = PublishedObject::new(file) .expose(ReadOnlyFileInterfaceDefinition); if authorization.can_write() { object = object.expose(WritableFileInterfaceDefinition); } object ``` Protocol Objectの`interfaces`は追加順を保持するordered setであり、同じInterface参照の重複は拒否する。各Interface Descriptorは独立したOperation集合を宣言するため、複数のtrait implementationを一つのDescriptorへ暗黙にmergeしない。 異なるInterfaceが同じOperation名を宣言しても、dispatchはrequestの`InterfaceTarget.reference`とOperation名の組で一意に決まる。表示上のqualified表記は[Text Viewの参照表記](../4.2-text-view.md#参照表記)に従い、signature全体をProtocol request fieldへparseし直さない。 Rust traitのsupertrait、trait alias、複数traitの組み合わせをDescriptor生成にどう対応付けるかは未決定である。これらによって、Protocol上のInterface inheritanceを暗黙に導入することはしない。 ## 固定Interface向けのsugar 一つのRust typeを常に同じInterface集合で公開する場合は、次のようなsugarを追加してよい。 ```rust #[wip::object(interfaces = [ReadOnlyFileInterface, WritableFileInterface])] struct File { // ... } ``` 別のconceptualな形として、`WipObject`のassociated itemにdefault Interface集合を指定することも考えられる。 ただし、core modelの基礎はexplicit publicationとする。主体、policy、resource kind等によって、同じstructへ異なるInterface subsetを追加できる必要があるため、固定Interface集合をcore modelにはしない。 Sugarを使う場合も、対象typeが指定したすべてのInterface traitを実装していることと、同じInterfaceを重複していないことを確認する必要がある。 ## HostへのInterface登録 Generated Interface Definitionには、Hostへの登録を通じて構造化されたInterface参照を割り当てる必要がある。参照の絶対scopeとlocal name、および配置pathへの祖先制約は[2.2. Operation and Interface](../2.2-operation-and-interface.md#interfaceの識別とscope)に従う。 Self-scopeは許可され、scopeはそのpathのObjectに紐づく。Scope Objectのoptionalな`ref`はProtocolの`scope_ref`として観測・検証する。`ref`がなければidentityを追跡できないことも許容し、scopeの移動追跡や独立したscope validatorは導入しない。 登録方法としては、conceptualにはeager registrationとlazy registrationの両方が考えられる。次の例はscope / nameを渡す具体構文を省略しており、暗黙のroot scopeを定めてはいない。登録時のcontextと引数の具体APIも引き続き未決定である。 ```rust let file_read_interface = host.register_interface(ReadOnlyFileInterfaceDefinition)?; let file_write_interface = host.register_interface(WritableFileInterfaceDefinition)?; let object = PublishedObject::new(file) .expose(file_read_interface) .expose(file_write_interface); ``` また、Hostが最初のpublication時に各definitionをinternする方式でもよい。どちらの登録方法でも、次の条件を満たす必要がある。 - MutableなInterface参照では`fetch_interface`がvalidatorを返し、同じ参照とvalidatorの組から異なるDescriptorを返さない。 - Validatorを返さないInterface参照は、その参照の有効期間中Descriptorをimmutableにする。 - Descriptorを更新する場合は同じ参照へ新しいvalidatorを発行するか、新しいInterface参照を使用する。 - Objectの`interfaces`へ設定した各Interface参照のDescriptorを、その主体から`fetch_interface`できる。 - 一つのObjectへ同じInterface参照を重複して追加しない。 - 構造的に同じDescriptorを同じ参照へdeduplicateすることは要求しない。 - Rust type名やprocess-local addressを、そのままportableなProtocol semanticsとして扱わない。 ## Request contextとauthorization Operation implementationが必要とする情報は、Object instanceだけとは限らない。Request contextとして、次の情報も必要になり得る。 - 現在の主体。 - Cancellationとdeadline。 - Tracing / audit context。 - Host serviceやbackend connectionへのaccess。 - Resource limit。 このcontextをmethod parameter、receiver wrapper、generated context、task-local stateのどれで渡すかは未決定である。どの形でも、Protocol parameterとして宣言された値とHostが注入するcontextは明確に区別する必要がある。 Interface集合はObject publication時に選択するだけでなく、Operation call時にもmembership、Interface validator、authorizationを再評価できなければならない。以前の`observe`で公開したInterface集合だけを根拠に、現在のOperation実行を許可することはできない。 Resultのvisibility checkも、通常のstructural Value validationとは別に必要となる。Hostは、Operation resultのRecord、List、Union等にnestedしたすべての`Entry`について、現在の主体にそのpathを認識させてよいかを再帰的に確認できなければならない。この確認をMacro-generated code、Projection、Host Runtimeのどこで行うかは未決定である。 Argumentとして受け取った`Entry` pathについても、pathの所持をauthorizationの証明にはしない。参照先へ作用する時点で、現在の主体について認可する。 ## Error model Rust methodのerror表現には、次の四種類を区別できることを求める。 - Protocol validationまたはdispatch failure。 - Effectがcommitされていないと保証できるHost / backend implementation failure。 - Operationの未実行またはrollbackを保証できない`OperationOutcomeUnknown`。 - Interfaceがreturn typeとして宣言したdomain failure。 現在のProtocolはdomain failureをOperation resultのUnion caseとして表す。Rustの`Result`をdomain Union、Host error、またはその両方のどれに対応付けるかは未決定である。 Rust panic、result encode failure、宣言型に違反するimplementation resultを、Macroがdomain failureへ自動変換することは認めない。Host Runtimeは、effectがcommitされていないと保証できる場合だけ`Internal`へmappingし、保証できなければ`OperationOutcomeUnknown`へmappingする。Clientへ送信済みかどうか不明なtransport切断についても、自動retryはしない。 ## 要件 このdraftのRust API modelに求める要件は、少なくとも次のとおりである。 - Interface Descriptorをtrait declarationから生成し、trait implementationごとに変化させない。 - Structが`WipObject`と、追加する各Interface traitを実装していることをcompile timeに確認する。 - 0個以上のInterfaceをpublication時に明示し、実装済みtraitの自動列挙に依存しない。 - Objectのpath、children、Interface集合をstructへ恒久的に固定しない。 - Struct instanceをrequest scopeで生成および破棄できる。 - 全Object instanceの事前登録を要求しない。 - Direct childrenを現在の主体についてprojectし、非公開Objectとそのsubtreeを除外しつつlazyに発見し、success responseではclean exhaustionまで列挙する。 - Backend failure、cancellation、resource budget超過をclean exhaustionとして扱わず、部分的なobservationをsuccess responseとして返さない。 - 同じstructへ複数のInterfaceを同時に追加でき、追加順を保持し、重複を拒否できる。 - 異なるInterfaceの同名Operationを、Interface参照とOperation名の組でdispatchできる。 - Protocol boundaryでarguments、result、Object、Descriptorを検証する。 - Operation result内のnestedな`Entry`へ、現在の主体についてvisibility checkを適用できる。 - Host-private fieldをProtocol ObjectまたはValueへ暗黙にserializeしない。 - Call時の現在の主体、Object visibility、Object validator、Interface membershipとvalidator、Descriptor、Operation、Rust側implementation、backend対象を一貫したexecution boundaryで扱う。 - 非公開Object、Interface非membership、非公開Operation、公開済みOperationの実行拒否をそれぞれ`NotFound`、`InterfaceMismatch`、`OperationNotFound`、`PermissionDenied`へ対応付ける。 - Interface validatorの必須・不一致を`InterfaceValidatorRequired`、`InterfaceValidatorMismatch`へ対応付ける。 - Object validatorを現在のObject identityと保護対象状態へ結び付け、別Objectに同じprovider-local revisionがあっても一致させない。 - Object validator比較、identity confirmation、Interface membershipとvalidator比較、DescriptorとOperation実装の固定、authorization、Operation実行を同じatomic boundaryで行う。 - Object validatorを要求するOperationへの省略を`ValidatorRequired`として拒否できる。 - Provider、Host Runtime、macro-generated codeのerrorを、effect未commitを保証できる`Internal`と、保証できない`OperationOutcomeUnknown`へ安全に対応付けられる。 - InvalidなObject、Descriptor、Operation resultをsuccess responseとして送信せず、Host-side validation failureをdomain failureへ変換しない。 - Rust SDK固有の型やlifetimeをProtocol semanticsとして要求しない。 ## 非目標 次の事項は、このdraftでは決定しない。 - 最終的なcrate、module、trait、attribute、deriveの名前。 - Proc macroの内部実装。 - 特定のasync runtime。 - Object instanceの常駐registryまたはactor model。 - Rust trait objectをwireへ公開すること。 - Rust trait inheritanceをProtocol Interface inheritanceとして扱うこと。 - Backend entityとRust structまたはProtocol Objectの一対一対応。 - Client SDKのtyped proxy API。 ## 未決定事項 - `WipObject`の具体的なmethodとmetadata ownership。 - Object metadata取得をsyncまたはasyncのどちらにするか。 - Publication APIがObject instanceをown、borrow、`Arc`化するか。 - Generated Interface Definitionの具体的なRust表現。 - Interface登録とscope / local name割当のlifecycle。 - Trait、Operation、parameter名のrename規則。 - Rust doc commentとProtocol Documentationの対応。 - Supported Rust typeと`TypeExpr`の対応。 - `Option`を許可する位置。 - Generic method、associated type、lifetime parameterをInterface traitで許可するか。 - `&self`、`&mut self`、owned receiverのどれをOperationで許可するか。 - Async methodをnative syntax、generated boxed future、別macroのどれで扱うか。 - Request contextとProtocol parameterのAPI上の分離。 - Nestedな`Entry` resultのvisibility checkをMacro-generated code、Projection、Host Runtimeのどこで行うか。 - Domain failure、Host error、panicのRust上の表現。 - Macro-generated dispatchとHost Runtimeの責務境界。 - Published ObjectをProviderから返す際のtype erasure。 - Validator比較とOperation実行を囲むbackend-specificなatomicity abstraction。 - Provider-local validatorをObject identityへnamespace化またはwrapするHost API。 - Operation実行後validatorをObject instance、Operation implementation、Providerのどこから取得するか。 - 主体ごとに異なるInterface combinationを追加したPublished Objectのconcrete return typeをどう統一するか。 - Rust client APIを同じtrait declarationから生成するか。 これらの選択は、静的service objectに使えるだけでは足りない。Filesystem、database row、virtual aggregate、主体別Interface compositionも、同じAPIで実装できるかを評価して決定する。