# Federated Creative Trade Protocol ## 連合プロトコル仕様書 **略称:** FCTP **版:** 0.6.0-draft **状態:** 設計草案 **日付:** 2026-11-02 *** ## 1. 総則 ### 1.1 目的 FCTPは、独立したゲームサーバーが、創作物、交易品、船舶および領域に関する情報を交換し、相互に連合できるようにすることを目的とする。 FCTPは、参加するActorがそれぞれの管理対象について独立した状態と操作規則を保持し、要求、宣言およびイベントを交換することによって相互作用する、分散的な管理モデルを採用する。 FCTPは、参加サーバー間におけるゲームルールの統一、状態の一致、またはサーバーをまたぐトランザクションの一貫性の確保を目的としない。各Actorは、受信した情報の解釈、採用および内部状態への反映を、自らの判断と規則に基づいて行う。 FCTPは、これらの判断を統一するのではなく、異なる判断と管理規則を持つActor間で情報を交換するための共通の表現と通信方法を規定する。 ### 1.2 適用範囲 FCTPは、独立したゲームサーバー間における以下の情報交換を規定する。 - 主体と領域の発見 - アセット、レシピ、交易品種の参照 - 権限に関する署名付き宣言 - 航路と港の公開情報 - 船舶の入域・離岸要求 - 着岸・離岸・出域・船倉変更・航行中イベント - 出域記録に基づく船倉照合 - クライアントによる遠隔リソースの認証付き取得 FCTPメッセージはActivityStreams 2.0のオブジェクトとして表現し、ActivityPubのサーバー間配送を使用する。 ### 1.3 規範語 本仕様では以下を用いる。 - **MUST**(しなければならない):適合実装の必須要件 - **MUST NOT**(してはならない):禁止事項 - **SHOULD**(するべきである):原則として実装する要件 - **MAY**(してもよい):実装または運用方針による選択事項 ### 1.4 役割 **Home**:プレイヤーの認証情報および参加資格を管理するサーバー。Home Authorityは、Player Actorの識別子のoriginに対して2.5の手順で解決されるActorである。同一のoriginに属するPlayer Actorの識別子は、同一のHome Authorityを用いる。Home AuthorityのURIは、Player Actorのoriginと異なるoriginを持ってよい。 **Registry**:船舶の船籍を管理し、その船舶について連合要求を送信・受信するActor。 **Territory**:島または海域を管理するActor。自身の領域における入域、港湾操作、航行イベントを処理する。 **Player**:プレイヤーを表すActor。 **Asset**:交易品、装備品、タイルなどの表示を行うためのメディアファイルと表示方法の指定。 **Recipe**:交易品種の生産条件。 **Variety**:交易品種の識別対象。 **Item**:交易品の個体。 **Vessel**:積み下ろし可能な船倉をもつ、領域内および領域間の輸送装置。 **Port**:港。 **Boundary**:領域の境界の地理的地点を表すシンボル。 **Route**:領域間または領域内の航路。Port もしくは Boundaryの二点間を接続する。 Registry, Territory, Player について、一つのActivityPubサーバーが複数のActorを運用してよい。 *** ## 2. 基本表現 ### 2.1 識別子 公開されるActor、オブジェクト、要求、イベント、宣言にはURIを割り当てる。 FCTPメッセージでは、識別子を文字列として表現する。 同一IDを持つイベントは、同一の宣言または事象を指す。 署名付きオブジェクトの内容を変更する場合は、新しいIDを発行する。 ### 2.2 識別と配送 ActorはActivityPubのInboxおよびOutboxを持つ。 Actorの識別子はWebFingerで発見可能でなければならない。Playerを表すhandleには、'.'を含んではならない。Registryを表すhandleは、@.registry@domain であり、Territoryを表すhandleは@.territory@domain であり、Homeを表すhandleは、@.home@domainでなければならない。WebFingerのresourceおよびJRDのsubjectは、これらのhandleを `acct:` URIとして表現する。 FCTPの要求とイベントは、対象ActorのInboxに配送する。 永続的なオブジェクトはURIから取得できなければならない。 船舶に関するイベントは、ActivityPubの `Create` Activityとして配送する。 アセット・交易品種・アクターに関するイベントは、イベントの性質に適合するActivityとして配送する。 要求に対する応答は、要求IDを参照する独立したFCTPオブジェクトとして配送する。 Home Authorityの発見手順は2.5で定義する。 ### 2.3 プロトコル名前空間とJSON-LDコンテキスト FCTPの拡張語彙には、名前空間 `https://fctp.example/ns#` を仮使用する。 FCTPオブジェクトは、JSON-LDの `@context` にActivityStreams 2.0のコンテキストおよびFCTPのコンテキストを指定する。 FCTPのコンテキストURIには `https://fctp.example/context` を仮使用する。 FCTPのコンテキストは、FCTPで使用する型およびプロパティのJSON-LD上の解釈を定義する。 正式版では、これらのURIを恒久的なURIに変更する。 ### 2.4 共通データ型 以下のTypeScript風定義は規範的なデータモデルを表す。`URI` は絶対URI、`Instant` はRFC 3339形式の時刻、`UInt` は非負整数を意味する。は、W3C Data Integrityで定義されるProof構造を参照する。 ```typescript type URI = string; type Instant = string; type UInt = number; interface Ref { id: URI; } interface Identified { id: URI; } interface Named { name: string; } interface Signed { proof: ; } interface Media { url: URI; mediaType: string; digest?: string; } type Quantity = Item | Stack; interface CargoManifest { entries: Quantity[]; } ``` `CargoManifest` は積荷の構成のみを保持する。Item はURIにより識別可能な交易品の個体を表し、Stackは品種・性質・数量によってのみ区別されるバルクの交易品を表す。 ### 2.5 Home Authorityの発見 Player ActorのHome Authorityは、以下の手順で解決しなければならない。 1. Playerのhandleを `@@` として解析する。`` は `host` または `host:port` である。 2. `O` を `https://` とする。 3. `O` の `/.well-known/nodeinfo` を取得する。 4. `rel` がNodeInfo 2.1のschema URIであるlinkを選択する。 5. NodeInfo documentを取得する。 6. `metadata.homeAccountName` を `homeAccountName` とする。存在しない場合、または文字列でない場合は `home-unresolved` を返す。 7. WebFinger resource `acct:@` を構成する。 8. `/.well-known/webfinger` を `resource=` として取得する。 9. JRDの `subject` が `acct:` resourceと一致することを要求する。 10. `rel="self"` のlinkが一つ存在し、その `href` が絶対HTTPS URIであることを要求する。 11. `href` のActorを取得する。 12. Actorの `id` が `href` と一致することを要求する。 13. Actorの `role` が `home` であることを要求する。 14. 得られたActorを、`O` に対するHome Authorityとする。 `metadata.homeAccountName` はHome handleのlocal partであり、先頭の `@` およびauthorityを含まない。例: `system.home`。 `homeAccountName` が存在しない場合は `home-unresolved`、self link、Actor ID、またはroleの不一致は `home-mismatch` とする。 *** ## 3. Actorと領域 ### 3.1 Actorの種別 FCTPは次のActor役割を定義する。 ```typescript type ActorRole = | "player" | "home" | "registry" | "territory"; interface FCTPActor extends Identified { inbox: URI; outbox: URI; role: ActorRole; publicKeys: URI[]; capabilities?: string[]; webfinger?: string; } ``` `webfinger` はFEP-2c59で定義される逆方向発見用のプロパティである。`webfinger` はWebFingerによる検証後にのみ信頼する。`webfinger` を公開するActor文書は、FEP-2c59のcontextを含まなければならない。 ### 3.2 Territory ```typescript interface Territory extends FCTPActor, Named { role: "territory"; resources: { ports: URI; routes: URI; areas: Area[]; map?: URI; }; } ``` `ports` と `routes` はCollectionのURIを指す。 `map` は領域の空間表現を発見するためのURIである。 Territoryは、入域要求を受信し、所在地イベントを発行する主体である。 ### 3.3 Actorの移転 Actorを移転する場合、移転を実行する前に、移転先のActorにおいてalsoKnownAs フィールドに移転元を含むべきである。 移転を実行する段階において、移転元のActorにおいて、moveToフィールドに移転先を指定し、ActivityPubの `Move` イベントを配送しなければならない。 Moveイベントを受信したサーバーは、移転を反映する前に、alsoKnownAsフィールドとの整合性を検証しなければならない。 ### 3.4 PortとRoute ```typescript interface Port extends Identified, Named { territory: URI; area: URI; listings: URI; } interface Boundary extends Identified, Named { territory: URI; } interface Area extends Identified, Named { territory: URI; } interface Route extends Identified { name?: string; from: URI; to: URI; distance?: number; } ``` `Route.from` および `Route.to` は、PortまたはBoundaryのURIを指す。 ### 3.5 航路の開設・更新・廃止 Territoryが航路および港を開設・更新・廃止する場合、Territoryを購読するActorに対し、当該オブジェクトを対象として、ActivityPubのイベント(Create, Update, Delete) を配送すべきである。 ### 3.6 航路の開設申し込み Territory Actorは、購読している他のTerritoryに対し、以下のメッセージを配送することで、領域間航路の開設を申し込むことができる。 ``` interface RouteRequest extends Identified, Signed { applyFrom: URI; applyTo: URI; object: Route; } ``` 申し込みを受けたTerritoryは、航路の開設を許諾または拒否することができる。航路の開設を許可する場合は、相手のTerritoryを購読し、以下のRouteRequestApprovalを申請者および購読者に配送すべきである。 航路の開設を許可しない場合は、RouteRequestDenialを申請者に配送すべきである。 ``` interface RouteRequestApproval extends Identified { request: RouteRequest; object: Route; } interface RouteRequestDenial extends Identified { request: URI; reason?: string; } ``` 領域間航路の廃止を行いたい場合、接続しているどちらかのTerritoryは航路の削除アクティビティを配送する。有効な削除アクティビティを受信したActorは、航路が廃止されたものとして取り扱うべきである。航行中の船舶が存在する航路が廃止された場合、その船舶は航路の出発地に戻されるべきである。 ## 4. アセット ### 4.1 Asset ```typescript interface Asset extends Identified, Named { creator: URI[]; // Player Actor holder: URI; // Assetを管理するActor media: Media[]; } ``` `creator` は当該アセットの作者として登録された主体を示す。 `holder` はアセット利用許可を発行し、アセットを更新できる主体として申告される。 `media` の定義および解釈については、サーバー・クライアント間プロトコルによって別途指定される。 ### 4.2 アセット更新の購読 Home Actor は、アセット更新を購読することができる。Home Actorがアセットをキャッシュし、所属するプレイヤーに遠隔サーバーのアセットを配信する場合は、holder を購読しなければならない。 Home Actor は、アセット更新を購読中止することができる。購読中止を受信した場合、holder は更新情報の配信を停止しなければならない。 ### 4.3 アセット更新の配送 アセットの更新は、holder により、署名付きの `Update` により配送される。`Update`は、holder の更新を含めることができる。 ### 4.4 アセット利用許可の配送 ```typescript interface AssetGrant extends Identified { asset: URI; variety: URI; grantee: URI; } ``` アセット利用許可は、holderにより署名付きの `Create` により配送される。granteeには、varietyのholderが指定されるが、varietyのholderが変更された場合にはこの利用許可は失効する。 ## 5. 品種 品種オブジェクトは以下のように定義される。 ``` interface Variety extends Identified, Named { holder: URI; asset?: URI; production?: Production[]; mass: number; version: string; } interface Production { type: "mine" | "manufacture"; ingredients?: Quantity[]; location?: Area[]; tool?: URI; duration: UInt; yield: Yield[]; } interface Yield { probability: number; count: UInt; data: Record; } ``` `probability` は相対重み `w` であり、`0 <= w < Infinity` を満たす。採掘あるいは製作の結果は、`w` に比例する確率で選択される。 ### 5.1 品種の作成 Player は、Varietyを作成し、購読者に署名付きで配送することができる。 ### 5.2 品種の更新 品種が更新された場合、holder は `Variety` に対する `Update` を署名付きで配送する。 ### 5.3 ItemとStack 固有のアイテムの特定や、一定の固有性質をもつ交易品の束を定義できる。 ``` interface Item extends Identified { variety: URI; data: Record; } interface Stack { variety: URI; count: UInt; data: Record; } ``` ## 6. 署名付きメッセージ FCTPの署名付き宣言は、W3C Verifiable Credential Data Integrity 1.0に従うData Integrity Proofを含むJSON-LDオブジェクトとして表現する。適合実装は eddsa-rdfc-2022 暗号スイートをサポートしなければならない。 公開鍵はActorのpublicKeysフィールドにより取得できなければならない。`verificationMethod` はActorの `publicKeys` に含まれなければならない。 ## 7. リソース取得 ### 7.1 適用範囲 本章は、クライアントおよびプレイヤー在籍サーバーが、他のサーバーの管理するリソースを取得するためのインターフェースを規定する。 本章が定めるリソースは、次のとおりとする。 - 領域の港および航路の一覧 - 港の出品情報 - 領域の地図 - 地図内の配置物 - これらに関連するアセット、レシピおよび交易品の情報 リソースサーバーは、リソースごとにアクセス認可を要求できる。 リソースはHTTPS URIで識別し、HTTP GETによって取得する。認可が必要な場合には第10章を適用する。 ### 7.2 リソース参照 リソースへの参照はURIによって表現する。 Territory Actorは以下の構造を持つ。 ```typescript interface TerritoryResources { ports: URI; routes: URI; areas: Area[]; map?: URI; } ``` "ports" と "routes" は、それぞれ港および航路のCollectionを指す。 "area" は、Territoryに含まれる地域区分を表す。 "map" は地図リソース記述子のURIを指す。 Portは以下の構造を持つ。 ```typescript interface PortResources { area: URI; listings: URI; } ``` "listings" は出品情報のCollectionを指す。 CollectionにはActivityStreamsのCollectionおよびCollectionPageを使用する。 ### 7.3 出品情報 ```typescript interface Listing { id: URI; port: URI; seller: URI; offered: CargoManifest; requested?: CargoManifest; description?: string; } ``` "offered" は出品対象の品種、数量および個体を表す。 "requested" は希望する交換対象を表す。贈与などの場合には省略できる。 出品情報は、対応する港を管理するリソースサーバーから取得する。 出品情報の取得は取引の成立を意味しない。出品の有効性および取引の成立は、操作を処理するサーバーが判定する。 ### 7.4 地図リソース 地図は、描画方式とリソースの取得方法を記述する "MapDescriptor" によって表現する。 ```typescript interface MapDescriptor { id: URI; representations: MapRepresentation[]; } interface MapRepresentation { format: URI; resources: MapResource[]; metadata?: Record; } interface MapResource { role: string; url: URI; mediaType: string; } ``` "MapDescriptor" はJSON-LDで記述する。 "representations" は、取得可能な地図表現の集合である。 "format" は、地図表現の形式を識別するURIである。 "resources" は、当該形式の地図を構成するリソースを表す。 "role" は、形式内で各リソースが担う役割を識別する文字列である。 "url" はリソースの取得先である。 "mediaType" は取得されるデータのメディア型である。 "metadata" の構造と各 "role" の意味は、対応する "format" によって定義する。 同じ地図に対して複数の表現を提供してよい。 地図表現にはJSON、画像、バイナリデータその他の形式を使用できる。画像とパレット情報など、複数のリソースを組み合わせる形式も許容する。 クライアントは、自身が対応する "format" を選択してリソースを取得する。 リソースサーバーは、取得要求ごとに認可を判定できる。 ### 7.5 配置物 地図上の配置物は、地図表現内で識別できるオブジェクトとして扱う。 配置物に対応する交易品、アセット、レシピ等への参照はURIで表現する。 配置物の座標、占有領域、描画順序、参照情報の符号化方法は、地図表現の "format" によって定義する。 ### 7.6 クライアントによる取得 クライアントは、リソースのURIに対してHTTP GETを実行する。 認証なしの取得が認められている場合、リソースサーバーは要求されたリソースを返す。 認証が必要な場合、クライアントは第10章で定義する外交用トークンを提示する。 リソースサーバーは、提示されたトークンに対する自らの認可ポリシーに基づいてアクセスを判定する。 ### 7.7 在籍サーバーによる代理取得 リソースサーバーは、プレイヤー在籍サーバーがクライアントに代わってリソースを取得することを認めなければならない(MUST)。 代理取得には、クライアントによる直接取得と同一のリソースURIを使用する。 認証が必要な場合、在籍サーバーは対象プレイヤーの外交用トークンを提示する。 リソースサーバーは、同一の外交用トークンと同一のリソース要求に対して、クライアントからの直接取得と在籍サーバーからの代理取得に同じアクセス権限を適用しなければならない(MUST)。 在籍サーバーは取得したリソースをクライアントに提供できる。 在籍サーバーによるキャッシュおよびその更新方法は、在籍サーバーの実装に委ねる。 ### 7.8 HTTP応答 リソースサーバーは、以下のHTTP応答コードを使用する。 コード| 意味 "200 OK"| リソース取得成功 "304 Not Modified"| 条件付き取得で変更なし "401 Unauthorized"| 必要な認証情報がない、または認証に失敗した "403 Forbidden"| 認証された主体に対して取得を認可しない "404 Not Found"| 対象リソースが見つからない "406 Not Acceptable"| 要求されたメディア型を提供できない リソースサーバーはHTTPの標準的なキャッシュ制御ヘッダーを使用できる。 ## 8. 船舶 ### 8.1 Vessel ```typescript interface Vessel extends Identified { registry: URI; possessor: URI; capacity: number; data?: Record; } ``` `registry` はRegistry Actorを指す。 `possessor` は占有者となるPlayer Actorを指す。 `capacity` は船の積載可能質量である。 ### 8.2 船籍サーバーと所在地サーバー Registryは船舶に関する入域・離岸要求を発行する。 Territoryは自領域内の船舶操作を成立させ、その結果をRegistryへ配送する。 Registryは受信したイベントを自らの船舶状態に採用するかを決定する。 Territoryは、船の入域から出域まで、その領域で認識する船倉を独立して管理する。 ### 8.3 旅程 ```typescript interface Journey { events: URI[]; exitEvidence?: URI; } ``` `Journey.events` はRegistryが提示する旅程イベント記録である。配列は、Registryがイベントが発生した順序として申告したい順にソートされていなければならない。 `Journey.exitEvidence` は、後続の入域審査で提示する出域イベントを参照する。 *** ## 9. 船舶要求とイベント ### 9.1 EntryRequest ```typescript interface EntryRequest extends Identified { type: "EntryRequest"; vessel: Vessel; cargo: CargoManifest; journey: Journey; destination: { territory: URI; port: URI; route: URI; }; } ``` 発行主体は `vessel.registry` である。 Registryは、船舶データ、船の占有者、申告船倉、旅程、宛先港、進入航路を含む入域要求をTerritoryへ配送する。 入域要求には宛先港への着岸要求を含む。 ### 9.2 EntryRejected ```typescript interface EntryRejected extends Identified { type: "EntryRejected"; request: URI; territory: URI; reason?: string; } ``` Territoryが入域を拒否した場合、Registryへ配送する。 ### 9.3 BerthingEvent ```typescript interface BerthingEvent extends Identified { type: "BerthingEvent"; vessel: URI; territory: URI; port: URI; request: URI; effectiveAt: Instant; } ``` 入域を認可したTerritoryは、着岸時刻を計算する。 着岸が成立した時刻に `BerthingEvent` を発行し、Registryへ配送する。 ### 9.4 CargoOperationEvent ```typescript interface CargoOperationEvent extends Identified { type: "CargoOperationEvent"; vessel: URI; territory: URI; port: URI; operation: "load" | "unload"; cargo: CargoManifest; effectiveAt: Instant; } ``` `cargo` は、当該操作によって実効した品種・数量を示す。 Territoryは、域内船倉と整合しない操作を拒否できる。 Territoryは、要求された操作の内容を修正して実効させることができる。 操作成立後、Territoryは所在地管理船倉を更新し、実効した結果をRegistryへ配送する。 Registryは通知内容を採用するかを決定する。 CargoOperationEventは、Territoryが自律的に発生させることもできるし、船舶の占有者の要求に応じて発生させることもできる。 船舶の占有者の要求は、占有者クライアントからTerritoryへのリソース操作リクエスト、もしくはHomeサーバーによるリクエストの代理によって行う。 ### 9.5 DepartureRequest ```typescript interface DepartureRequest extends Identified { type: "DepartureRequest"; vessel: URI; territory: URI; port: URI; route?: URI; } ``` RegistryがTerritoryへ配送する。 ### 9.6 DepartureEvent ```typescript interface DepartureEvent extends Identified { type: "DepartureEvent"; vessel: URI; territory: URI; port: URI; request: URI; effectiveAt: Instant; } ``` Territoryが離岸を成立させたときに発行し、Registryへ配送する。 ### 9.7 VoyageEvent ```typescript interface VoyageEvent extends Identified { type: "VoyageEvent"; vessel: URI; territory: URI; kind: string; details?: Record; effectiveAt: Instant; } ``` Territoryは、域内航行中に発生した事象をRegistryへ配送できる。 `kind` には `shipwreck` を定義する。 ### 9.8 ExitEvent ```typescript interface ExitEvent extends Identified, Signed { type: "ExitEvent"; vessel: URI; territory: URI; route: URI; entryRequest: URI; departureEvent?: URI; cargo: CargoManifest; effectiveAt: Instant; } ``` Territoryは、出域時点で自身が認識する船倉を `cargo` に記録する。 `ExitEvent` はTerritoryが署名し、Registryへ配送する。 Registryは、出域イベントを後続の `EntryRequest.journey.exitEvidence` に指定できる。 ### 9.9 イベントの意味 各イベントは、`actor` がその内容を成立した事実として表明する記録である。 `effectiveAt` はイベント発行主体が認識する成立時刻である。 RegistryとTerritoryの船倉記録は一致しなくてよい。 Territoryで成立した操作は、Registryによる通知の採否と独立している。 ## 10. 遠隔クライアント認可 10.1 役割 本章では、以下の主体を定義する。 Home プレイヤーの在籍サーバー。プレイヤーにnative tokenを発行し、外交用トークンを導出する。 Resource Server 取得対象のリソースや、リソース操作権限を管理し、外交用トークンに対しアクセス許可を行うサーバー。アセットの作者が在籍するHomeや、プレイヤーが占有する船舶が入域するTerritoryが該当する。 Client プレイヤーが利用するクライアント。 HomeとResource ServerはActivityPub Actorとして識別する。 ### 10.2 外交用トークンの導出 外交用トークンを以下のように定義する。 D = HMAC-SHA256( key = T, message = UTF8(U) ) ここで、 - "T" はHomeがクライアントに発行したnative tokenのバイト列である。 - "U" はResource Server Actorの "id" URIである。 - "D" は32バイトの外交用トークンである。 "U" には、Actor文書の "id" に記載されたURI文字列をそのまま使用する。HMACへの入力時にURLの書き換えや再正規化を行わない。 外交用トークンのHTTP表現には、パディングなしのbase64文字列を用いる。 type DiplomaticToken = string; ### 10.3 外交用トークン認証情報の配送 Homeは、Resource Serverに対して、プレイヤーの外交用トークンのダイジェストを配送することができる。TokenDigest/TokenRevokeの送信元は、対象のPlayer Actorについて2.5で解決されるHome Authorityと一致しなければならない。 "tokenDigest" は以下で計算する。 tokenDigest = BASE64(SHA256(D)) interface TokenDigest { tokenDigest: string; actor: URI; revision: number; } interface TokenRevoke { tokenRevoke: "revoke"; actor: URI; revision: number; } Home Server は、クライアントに対してトークンの再発行を行った場合、クライアントが現在利用中のResource Serverに対し TokenDigestを配送すべきである。 また、クライアントがResource Serverに対してダイジェストの配送を依頼した場合、TokenDigestを配送すべきである。 Resource Serverは、同じ actor に対する複数の TokenDigest/TokenRevoke メッセージを受信した場合、小さなrevisionを持つメッセージを破棄し、最も大きなrevisionをもつTokenDigest/TokenRevokeを認証情報として用いなければならない。 TokenRevoke が最も大きいrevisionを持つ場合、Resource Serverは認証情報を破棄しなければならない。ただし、revisionは保持すべきである。 Home Serverは、同一のactorおよびrevisionに対して内容の異なるTokenDigest/TokenRevokeを送信してはならない。 Resource Serverは、同一のactorおよびrevisionに対して内容の異なるTokenDigest/TokenRevokeを受信した場合、プロトコルエラー `token-revision-conflict` として扱わなければならない。 ### 10.4 クライアントによる使用 Clientは、Home から取得した native トークンから外交用トークンを導出して、リモートサーバーのリソースを取得したり、リソース操作を指示できる。以下のHTTPヘッダを用いる。 Authorization: Bearer Clientとサーバー間のリソースの取得及び操作の仕様については、別のプロトコルで定める。 ## 11. 配送とエラー ### 11.1 HTTP受信 ActivityPubによる配送の成功は、FCTP要求の業務上の認可・成立とは区別する。 受信側は、Activity IDおよびFCTPオブジェクトIDによって重複配送を識別する。 ### 11.2 プロトコルエラー 構文またはプロトコル上の不整合について、以下のエラーコードを定義する。 |コード|意味| |---|---| |`invalid-object`|必須データが欠落または不正| |`unsupported-type`|オブジェクト型に未対応| |`unsupported-version`|プロトコル版に未対応| |`invalid-signature`|署名検証失敗| |`unverifiable-signature`|鍵等を取得できず検証不能| |`unresolved-reference`|必須参照を解決できない| |`home-unresolved`|Home Authorityを解決できない| |`home-mismatch`|Home Authorityのself link、Actor IDまたはroleが一致しない| |`token-revision-conflict`|同一actorおよびrevisionで内容の異なるTokenDigest/TokenRevokeを受信した| 入域拒否、グラント拒否、操作拒否は、それぞれ対応する業務上の応答または所在地の処理結果として表現する。 ### 11.3 再配送 同じイベントを再配送する場合、イベントIDおよび署名対象本文を維持する。 新しい内容を表明する場合は新しいイベントIDを発行する。 *** ## 12. 適合プロファイル ### 12.1 Core - ActivityPubによるイベント配送 - Actorとオブジェクトの参照 - 基本データ型 - 署名付き宣言の取得・検証 ### 12.2 Creative Assets - Asset - Variety / Item参照 ### 12.3 Territory Topology - Territory - Port - Route ### 12.4 Territory Resources - Listing - MapDescriptor ### 12.5 Vessel Federation - EntryRequest / EntryRejected - BerthingEvent - CargoOperationEvent - DepartureRequest / DepartureEvent - VoyageEvent - ExitEvent - 署名付き出域証拠 ### 12.6 Remote Client Access - TokenDigest/TokenRevoke サーバーは対応するプロファイルをActorの `capabilities` に公開する。 ## 付録A:代表的な連合シーケンス ### A.1 アセットとレシピ 1. Playerがアセットを登録する。 2. アセット保持者が、特定のvarietyとそのholderに対して `AssetGrant` を発行する。 3. 品種保持者が `Update` を発行する。 4. 利用先サーバーが署名付きメッセージを検証し、採用するレシピ版とアセットの利用許可を評価する。 ### A.2 船舶の移動 1. Registryが `EntryRequest` をTerritoryへ配送する。 2. Territoryが入域を審査する。 3. 拒否時は `EntryRejected` を配送する。 4. 受理時はTerritoryが船と申告船倉を域内管理対象として登録する。 5. 着岸時に `BerthingEvent` を配送する。 6. 港湾操作の成立時に `CargoOperationEvent` を配送する。 7. Registryが `DepartureRequest` を配送する。 8. 離岸時にTerritoryが `DepartureEvent` を配送する。 9. 出域時にTerritoryが船倉状態を含む `ExitEvent` に署名して配送する。 10. Registryは後続の入域要求で、その `ExitEvent` を証拠として提示できる。 ### A.3 遠隔リソース取得 1. Playerのhandleから2.5の手順でHome Authorityを解決する。 2. Homeがnative tokenから、アクセス先Actor向けの外交用トークンを導出する。 3. HomeがResource Serverへ `TokenDigest` を配送する。 4. クライアントがResource Serverの港・地図等をHTTPで取得する。 *** ## 付録B:外部規格 本仕様で利用する外部規格は以下とする。 - ActivityPub — https://www.w3.org/TR/activitypub/ - ActivityStreams 2.0 — https://www.w3.org/TR/activitystreams-core/ - ActivityStreams Vocabulary — https://www.w3.org/TR/activitystreams-vocabulary/ - WebFinger — https://www.rfc-editor.org/rfc/rfc7033 - NodeInfo 2.1 — https://nodeinfo.diaspora.software/spec-2.1/ - FEP-2c59 — https://w3id.org/fep/2c59