Zone Asset Manifest
The Context
GET /shards returns zone connection metadata: address, port, cert_hash, and desync_index_url. Clients have no way to discover which SharedFiles are hosted at a zone without first opening a WebTransport or WebSocket connection to it.
The Problem Statement
Discovery requires a live connection. Clients cannot make pre-connection routing or interest decisions based on zone content. A client that wants to find zones containing a specific asset type must connect to each candidate zone in turn.
Describe how your proposal will work with code, pseudo-code, mock-ups, or diagrams
Add a read-only endpoint GET /shards/:id/assets. This requires 20260421-asset-zone-locality.md to be implemented first (SharedFile must carry a zone_id).
Response shape:
{
"data": {
"assets": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "KitsuneAvatarV2",
"mime_type": "model/gltf-binary",
"baked_url": "https://versitygw.example.com/chunks/abc123.caidx",
"tags": ["avatar", "vrm"],
"is_public": true
}
]
}
}Only assets with a non-null baked_url are returned — assets still in the baking pipeline are not surfaced. No authentication is required for assets where is_public is true.
Context function:
# Uro.VSekai
def list_zone_assets(zone_id) do
SharedFile
|> where([f], f.zone_id == ^zone_id and not is_nil(f.baked_url) and f.is_public == true)
|> select([f], [:id, :name, :mime_type, :baked_url, :tags])
|> Repo.all()
endThe existing GET /shards response is unchanged. No existing client breaks.
Route addition in router.ex:
get "/shards/:id/assets", ZoneController, :assetsThe Benefits
Clients can filter and rank zones by content before connecting. The endpoint is stateless and cacheable. No new data model is required beyond the zone_id FK on SharedFile.
The Downsides
The asset list reflects the state at query time. A zone that adds an asset between a client’s manifest fetch and its connection will not surface that asset in the cached response. Polling or the zone_updated WebSocket event covers this.
The Road Not Taken
Embedding the asset list directly in GET /shards would return it for all zones in a single request but multiplies payload size with the number of assets per zone. Clients interested in only connection metadata pay the full asset enumeration cost. A separate endpoint keeps the two concerns independent.
The Infrequent Use Case
A zone with no baked assets returns "assets": []. A zone whose assets are all private (is_public: false) also returns an empty list to unauthenticated clients. Authenticated requests with sufficient ReBAC permission return private assets; this gating is deferred to a follow-on decision.
In Core and Done by Us
Uro.VSekai.list_zone_assets/1— query SharedFile by zone_id and baked_urlUro.ZoneController.assets/2— new actionrouter.ex— new route- Requires
20260421-asset-zone-locality.md
Status
Status: Proposed
Decision Makers
- iFire
Further Reading
20260421-asset-zone-locality.md— zone_id FK prerequisite20260421-zone-registration-and-discovery.md— base zone API20260421-content-addressed-asset-delivery.md— baked_url pipeline