openvibers/openvibe.contracts Commits

Contracts 0.122.0: OpenVibe.Inventory goes live (inventory.openvibe.network, site position 30); six inventory capabilities active with their routes (ADR-054, plan T21 step 2) (#69)

OP OpenVibers committed 9 Oct 2026 · ae11a100cb · 41 files, +1474 −94

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 4529caa2..c4635aac 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,17 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
++## 0.122.0 — 2026-10-09
++
++**OpenVibe.Inventory goes live (ADR-054, plan T21 step 2).**
++- `manifests/services/inventory.json`:
++ - status alpha, exposure `live` with `publicSite: service`, at site position 30 (Inventory);
++ - its lifecycle, health, ready and internal origin (127.0.0.1:5030);
++ - it consumes the two account events and owns `inventory.*`.
++- Six capabilities are active, each naming its routes: `inventory.item.read`, `inventory.item.list`,
++ `inventory.equip.manage`, `inventory.item.grant`, `inventory.item.consume` and `inventory.definition.manage`.
++ `inventory.definition.review` stays planned until creator submissions open.
++
## 0.121.0 — 2026-10-09
**The OpenVibe inventory, decided (ADR-054, plan T21 step 1).** A new authority, OpenVibe.Inventory, will own items
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex 1bdd1c09..4ee62eb3 100644
---- a/generated/openapi/actor.json
++++ b/generated/openapi/actor.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Actor API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex b822a660..4e8e8fcd 100644
---- a/generated/openapi/ai.json
++++ b/generated/openapi/ai.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.AI API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/billing.json b/generated/openapi/billing.json
iindex 98274632..4f7ca44a 100644
---- a/generated/openapi/billing.json
++++ b/generated/openapi/billing.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Billing API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex 79193869..2fb06e17 100644
---- a/generated/openapi/blog.json
++++ b/generated/openapi/blog.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Blog API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bot.json b/generated/openapi/bot.json
iindex fcee0ed6..dc8dfd35 100644
---- a/generated/openapi/bot.json
++++ b/generated/openapi/bot.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bot API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/chat.json b/generated/openapi/chat.json
iindex e413943b..3ef04df0 100644
---- a/generated/openapi/chat.json
++++ b/generated/openapi/chat.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Chat API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/community.json b/generated/openapi/community.json
iindex 88638af9..66eed0e5 100644
---- a/generated/openapi/community.json
++++ b/generated/openapi/community.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Community API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/coupons.json b/generated/openapi/coupons.json
iindex a4e5e7c0..368545c7 100644
---- a/generated/openapi/coupons.json
++++ b/generated/openapi/coupons.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Coupons API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/deals.json b/generated/openapi/deals.json
iindex 55bd7626..edcb49db 100644
---- a/generated/openapi/deals.json
++++ b/generated/openapi/deals.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Deals API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/events.json b/generated/openapi/events.json
iindex 7ed9778f..d47800b2 100644
---- a/generated/openapi/events.json
++++ b/generated/openapi/events.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Events API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/food.json b/generated/openapi/food.json
iindex 90ba76f1..efe2522c 100644
---- a/generated/openapi/food.json
++++ b/generated/openapi/food.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Food API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/games.json b/generated/openapi/games.json
iindex 5ea8198c..2cc20aeb 100644
---- a/generated/openapi/games.json
++++ b/generated/openapi/games.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Games API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/host.json b/generated/openapi/host.json
iindex abdcff60..eb764ee6 100644
---- a/generated/openapi/host.json
++++ b/generated/openapi/host.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Host API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/index.json b/generated/openapi/index.json
iindex 6f793622..4af8e050 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -92,6 +92,13 @@
"operations": 36,
"capabilities": 5
},
++ {
++ "service": "inventory",
++ "name": "OpenVibe.Inventory",
++ "origin": "https://inventory.openvibe.network",
++ "operations": 14,
++ "capabilities": 6
++ },
{
"service": "live",
"name": "OpenVibe.Live",
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
nnew file mode 100644
iindex 00000000..b2f9e43c
---- /dev/null
++++ b/generated/openapi/inventory.json
@@@ -0,0 +1,1294 @@
++{
++ "openapi": "3.1.0",
++ "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
++ "info": {
++ "title": "OpenVibe.Inventory API",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "license": {
++ "name": "MIT",
++ "identifier": "MIT"
++ }
++ },
++ "servers": [
++ {
++ "url": "https://inventory.openvibe.network"
++ }
++ ],
++ "paths": {
++ "/api/v1/definitions": {
++ "get": {
++ "operationId": "get_api_v1_definitions",
++ "summary": "Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /a",
++ "description": "**inventory.item.read** (public): Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds.",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.read"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.read"
++ ]
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.inventory.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ },
++ "post": {
++ "operationId": "post_api_v1_definitions",
++ "summary": "Create, edit, submit and retire definitions in the caller's namespace (POST /api/v1/definitions, PATCH /api/v1/definitions/:id with inventory.definition-request@1 → inventory.definition@1).",
++ "description": "**inventory.definition.manage** (first-party): Create, edit, submit and retire definitions in the caller's namespace (POST /api/v1/definitions, PATCH /api/v1/definitions/:id with inventory.definition-request@1 → inventory.definition@1). A creator's definition goes to review; a service's or app's is published when it asks.",
++ "tags": [
++ "inventory.definition"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.definition.manage"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "inventory-write",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.definition.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.definition-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.definition.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/definitions/{id}": {
++ "get": {
++ "operationId": "get_api_v1_definitions_id",
++ "summary": "Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /a",
++ "description": "**inventory.item.read** (public): Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds.",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.read"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.read"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.inventory.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ },
++ "patch": {
++ "operationId": "patch_api_v1_definitions_id",
++ "summary": "Create, edit, submit and retire definitions in the caller's namespace (POST /api/v1/definitions, PATCH /api/v1/definitions/:id with inventory.definition-request@1 → inventory.definition@1).",
++ "description": "**inventory.definition.manage** (first-party): Create, edit, submit and retire definitions in the caller's namespace (POST /api/v1/definitions, PATCH /api/v1/definitions/:id with inventory.definition-request@1 → inventory.definition@1). A creator's definition goes to review; a service's or app's is published when it asks.",
++ "tags": [
++ "inventory.definition"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.definition.manage"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "inventory-write",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.definition.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.definition-request.v1"
++ }
++ }
++ }
++ },
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.definition.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/equipped": {
++ "get": {
++ "operationId": "get_api_v1_equipped",
++ "summary": "Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /a",
++ "description": "**inventory.item.read** (public): Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds.",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.read"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.read"
++ ]
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.inventory.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/grants": {
++ "post": {
++ "operationId": "post_api_v1_grants",
++ "summary": "Grant an instance of a definition the caller issued (POST /api/v1/grants with inventory.grant-request@1 → inventory.instance@1; Idempotency by idempotency_key).",
++ "description": "**inventory.item.grant** (first-party): Grant an instance of a definition the caller issued (POST /api/v1/grants with inventory.grant-request@1 → inventory.instance@1; Idempotency by idempotency_key). Outside the issuer's namespace: 403 inventory.not_issuer. Sold out: 409 inventory.supply_exhausted. Never for money (ADR-054 §5).",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.grant"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "inventory-write",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.grant"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.grant-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.instance.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/instances/{id}/consume": {
++ "post": {
++ "operationId": "post_api_v1_instances_id_consume",
++ "summary": "Consume or revoke an instance of a definition the caller issued (POST /api/v1/instances/:id/consume | /revoke → inventory.instance@1).",
++ "description": "**inventory.item.consume** (first-party): Consume or revoke an instance of a definition the caller issued (POST /api/v1/instances/:id/consume | /revoke → inventory.instance@1).",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.consume"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "inventory-write",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.consume"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.instance.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/instances/{id}/revoke": {
++ "post": {
++ "operationId": "post_api_v1_instances_id_revoke",
++ "summary": "Consume or revoke an instance of a definition the caller issued (POST /api/v1/instances/:id/consume | /revoke → inventory.instance@1).",
++ "description": "**inventory.item.consume** (first-party): Consume or revoke an instance of a definition the caller issued (POST /api/v1/instances/:id/consume | /revoke → inventory.instance@1).",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.consume"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "inventory-write",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.consume"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.instance.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/kinds": {
++ "get": {
++ "operationId": "get_api_v1_kinds",
++ "summary": "Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /a",
++ "description": "**inventory.item.read** (public): Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds.",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.read"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.read"
++ ]
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.inventory.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/kinds/{id}": {
++ "get": {
++ "operationId": "get_api_v1_kinds_id",
++ "summary": "Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /a",
++ "description": "**inventory.item.read** (public): Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds.",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.read"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.read"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.inventory.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/me/equipped": {
++ "put": {
++ "operationId": "put_api_v1_me_equipped",
++ "summary": "Equip or clear a slot with an instance the person owns (PUT /api/v1/me/equipped with inventory.equip-request@1 → inventory.equipped@1).",
++ "description": "**inventory.equip.manage** (public): Equip or clear a slot with an instance the person owns (PUT /api/v1/me/equipped with inventory.equip-request@1 → inventory.equipped@1). One item per slot. Refuses an instance not owned or not in state owned (409 inventory.not_owned).",
++ "tags": [
++ "inventory.equip"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.equip.manage"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-write",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.equip.manage"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.equip-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.equipped.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/me/items": {
++ "get": {
++ "operationId": "get_api_v1_me_items",
++ "summary": "The person's own full inventory, consumed and revoked instances included (GET /api/v1/me/items → inventory.inventory@1).",
++ "description": "**inventory.item.list** (public): The person's own full inventory, consumed and revoked instances included (GET /api/v1/me/items → inventory.inventory@1). A service may read it acting for the person (on_behalf_of).",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.list"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.list"
++ ]
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.inventory.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/people/{subject}/equipped": {
++ "get": {
++ "operationId": "get_api_v1_people_subject_equipped",
++ "summary": "Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /a",
++ "description": "**inventory.item.read** (public): Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds.",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.read"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.read"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "subject",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.inventory.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "/api/v1/people/{subject}/items": {
++ "get": {
++ "operationId": "get_api_v1_people_subject_items",
++ "summary": "Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /a",
++ "description": "**inventory.item.read** (public): Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds.",
++ "tags": [
++ "inventory.item"
++ ],
++ "x-openvibe-capabilities": [
++ "inventory.item.read"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "inventory-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "inventory.item.read"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "subject",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/inventory.inventory.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "components": {
++ "schemas": {
++ "errors.problem.v1": {
++ "title": "Problem",
++ "description": "RFC 9457 problem details (application/problem+json) with a stable OpenVibe error code and trace identifiers. The legacy 'error' string is allowed during migration so existing clients keep working.",
++ "type": "object",
++ "required": [
++ "type",
++ "title",
++ "status",
++ "code"
++ ],
++ "additionalProperties": true,
++ "properties": {
++ "type": {
++ "type": "string",
++ "format": "uri-reference"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1
++ },
++ "status": {
++ "type": "integer",
++ "minimum": 400,
++ "maximum": 599
++ },
++ "detail": {
++ "type": "string"
++ },
++ "instance": {
++ "type": "string",
++ "format": "uri-reference"
++ },
++ "code": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z0-9_]+)*$"
++ },
++ "request_id": {
++ "type": "string"
++ },
++ "trace_id": {
++ "type": "string",
++ "pattern": "^[0-9a-f]{32}$"
++ },
++ "errors": {
++ "type": "array",
++ "items": {
++ "type": "object",
++ "required": [
++ "message"
++ ],
++ "properties": {
++ "path": {
++ "type": "string"
++ },
++ "message": {
++ "type": "string"
++ }
++ }
++ }
++ },
++ "error": {
++ "type": "string",
++ "description": "Deprecated compatibility field: same text as title/detail for clients that read {error}."
++ }
++ }
++ },
++ "inventory.definition-request.v1": {
++ "title": "InventoryDefinitionRequest",
++ "description": "Create or edit a definition in the issuer's namespace (inventory.definition.manage). A service's or app's definition is published when it asks; a creator's goes to staff review (in_review) first.",
++ "type": "object",
++ "required": [
++ "kind",
++ "name",
++ "art",
++ "rarity"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$",
++ "maxLength": 64
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80
++ },
++ "description": {
++ "type": "string",
++ "maxLength": 500
++ },
++ "art": {
++ "type": "object",
++ "additionalProperties": false,
++ "minProperties": 1,
++ "properties": {
++ "media_id": {
++ "type": "string",
++ "pattern": "^med_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "An OpenVibe.Media object (an image, an animation)."
++ },
++ "token": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80,
++ "description": "A token the kind's renderers know (a CSS class, a speech preset)."
++ },
++ "emoji": {
++ "type": "string",
++ "maxLength": 16
++ }
++ }
++ },
++ "rarity": {
++ "enum": [
++ "common",
++ "uncommon",
++ "rare",
++ "epic",
++ "legendary"
++ ]
++ },
++ "attributes": {
++ "type": "object"
++ },
++ "supply_cap": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 1
++ },
++ "aliases": {
++ "type": "array",
++ "maxItems": 8,
++ "uniqueItems": true,
++ "items": {
++ "type": "string",
++ "pattern": "^[a-z0-9][a-z0-9_.-]{0,63}$"
++ }
++ },
++ "publish": {
++ "type": "boolean",
++ "description": "Ask for publication (a creator's definition goes to review)."
++ }
++ }
++ },
++ "inventory.definition.v1": {
++ "title": "InventoryDefinition",
++ "description": "An item definition (ADR-054 §2): one item of a kind, issued by a service, an app or a creator, with an honest rarity, attributes valid against the kind and an optional supply cap. Published definitions can be granted; retired ones cannot, and their instances stay.",
++ "type": "object",
++ "required": [
++ "id",
++ "kind",
++ "name",
++ "art",
++ "rarity",
++ "attributes",
++ "issuer",
++ "supply",
++ "status",
++ "created_at",
++ "updated_at"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^itd_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "kind": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$",
++ "maxLength": 64
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80
++ },
++ "description": {
++ "type": "string",
++ "maxLength": 500
++ },
++ "art": {
++ "type": "object",
++ "additionalProperties": false,
++ "minProperties": 1,
++ "properties": {
++ "media_id": {
++ "type": "string",
++ "pattern": "^med_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "An OpenVibe.Media object (an image, an animation)."
++ },
++ "token": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 80,
++ "description": "A token the kind's renderers know (a CSS class, a speech preset)."
++ },
++ "emoji": {
++ "type": "string",
++ "maxLength": 16
++ }
++ }
++ },
++ "rarity": {
++ "enum": [
++ "common",
++ "uncommon",
++ "rare",
++ "epic",
++ "legendary"
++ ],
++ "description": "Shown as is; any odds that apply are shown with it, never hidden."
++ },
++ "attributes": {
++ "type": "object"
++ },
++ "issuer": {
++ "type": "string",
++ "pattern": "^(service:[a-z][a-z0-9-]*|app:app_[0-9A-HJKMNP-TV-Z]{26}|user:usr_[0-9A-HJKMNP-TV-Z]{26})$"
++ },
++ "aliases": {
++ "type": "array",
++ "maxItems": 8,
++ "uniqueItems": true,
++ "items": {
++ "type": "string",
++ "pattern": "^[a-z0-9][a-z0-9_.-]{0,63}$"
++ },
++ "description": "Earlier ids of the same item (Live's fx_rainbow, hat_crown, …)."
++ },
++ "supply": {
++ "type": "object",
++ "required": [
++ "cap",
++ "issued"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "cap": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 1,
++ "description": "null: unlimited."
++ },
++ "issued": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "status": {
++ "enum": [
++ "draft",
++ "in_review",
++ "published",
++ "retired"
++ ]
++ },
++ "credit": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "name": {
++ "type": "string",
++ "maxLength": 80
++ }
++ },
++ "description": "The creator of a community item (ADR-054 §6)."
++ },
++ "created_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "updated_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "published_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ },
++ "inventory.equip-request.v1": {
++ "title": "InventoryEquipRequest",
++ "description": "Equip an instance the person owns in one slot of its kind, or clear the slot (instance_id null). One item per slot; equipping replaces what was there.",
++ "type": "object",
++ "required": [
++ "kind",
++ "slot",
++ "instance_id"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$",
++ "maxLength": 64
++ },
++ "slot": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_]{0,31}$"
++ },
++ "instance_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^inv_[0-9A-HJKMNP-TV-Z]{26}$"
++ }
++ }
++ },
++ "inventory.equipped.v1": {
++ "title": "InventoryEquipped",
++ "description": "What a person has equipped (ADR-054 §2), keyed <kind>:<slot>. Surfaces read it in batches (inventory.equipped-batch@1) and cache it briefly.",
++ "type": "object",
++ "required": [
++ "subject",
++ "slots",
++ "updated_at"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "slots": {
++ "type": "object",
++ "propertyNames": {
++ "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+:[a-z][a-z0-9_]{0,31}$"
++ },
++ "additionalProperties": {
++ "type": "object",
++ "required": [
++ "instance_id",
++ "definition_id"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "instance_id": {
++ "type": "string",
++ "pattern": "^inv_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "definition_id": {
++ "type": "string",
++ "pattern": "^itd_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "token": {
++ "type": "string",
++ "maxLength": 80,
++ "description": "The definition's art token, so a renderer needs no second read."
++ }
++ }
++ },
++ "description": "<kind>:<slot> → the instance in use."
++ },
++ "updated_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ },
++ "inventory.grant-request.v1": {
++ "title": "InventoryGrantRequest",
++ "description": "An issuer grants one instance of a definition it issued to a person (inventory.item.grant). Idempotent per idempotency_key: a repeat answers the instance already granted. A capped definition that is sold out answers 409 inventory.supply_exhausted.",
++ "type": "object",
++ "required": [
++ "definition_id",
++ "subject",
++ "idempotency_key"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "definition_id": {
++ "type": "string",
++ "pattern": "^itd_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "idempotency_key": {
++ "type": "string",
++ "minLength": 8,
++ "maxLength": 128
++ },
++ "origin": {
++ "enum": [
++ "granted",
++ "earned"
++ ],
++ "default": "granted"
++ },
++ "reason": {
++ "type": "string",
++ "maxLength": 200,
++ "description": "Shown in the ledger: what the person did (a quest, an event, a milestone)."
++ },
++ "attributes": {
++ "type": "object"
++ }
++ }
++ },
++ "inventory.instance.v1": {
++ "title": "InventoryInstance",
++ "description": "One item a person owns (ADR-054 §2): a definition, its origin and state. bought and traded are reserved for the later money ADR (ADR-054 §5) and are refused until it is accepted.",
++ "type": "object",
++ "required": [
++ "id",
++ "definition_id",
++ "owner",
++ "origin",
++ "state",
++ "acquired_at"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^inv_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "definition_id": {
++ "type": "string",
++ "pattern": "^itd_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "owner": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "origin": {
++ "enum": [
++ "granted",
++ "earned",
++ "migrated",
++ "bought",
++ "traded"
++ ]
++ },
++ "state": {
++ "enum": [
++ "owned",
++ "consumed",
++ "revoked"
++ ]
++ },
++ "attributes": {
++ "type": "object",
++ "description": "Per-instance values (a serial number, a wear value), valid against the kind."
++ },
++ "serial": {
++ "type": "integer",
++ "minimum": 1,
++ "description": "The instance's number within a capped supply."
++ },
++ "acquired_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ },
++ "inventory.inventory.v1": {
++ "title": "InventoryList",
++ "description": "A person's inventory page: their instances, newest first, with the definitions they refer to. The public read shows only owned instances of published definitions; the person's own read (inventory.item.list) also shows consumed and revoked ones.",
++ "type": "object",
++ "required": [
++ "subject",
++ "instances",
++ "definitions",
++ "next_cursor"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "subject": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "instances": {
++ "type": "array",
++ "maxItems": 500,
++ "items": {
++ "$ref": "#/components/schemas/inventory.instance.v1"
++ }
++ },
++ "definitions": {
++ "type": "object",
++ "propertyNames": {
++ "pattern": "^itd_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "additionalProperties": {
++ "$ref": "#/components/schemas/inventory.definition.v1"
++ }
++ },
++ "next_cursor": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 200
++ }
++ }
++ }
++ },
++ "securitySchemes": {
++ "openvibeToken": {
++ "type": "http",
++ "scheme": "bearer",
++ "bearerFormat": "JWT",
++ "description": "An OpenVibe Network token for this service: a person's token, an app token (client credentials, audience of the service) or a first-party service token. Its `cap` claim must include the capability the operation names."
++ }
++ }
++ }
++}
ddiff --git a/generated/openapi/live.json b/generated/openapi/live.json
iindex 40ba4162..68c40be6 100644
---- a/generated/openapi/live.json
++++ b/generated/openapi/live.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Live API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media.json b/generated/openapi/media.json
iindex 7cd7c10e..0d9c65ad 100644
---- a/generated/openapi/media.json
++++ b/generated/openapi/media.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Media API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex e99320da..1b454ba6 100644
---- a/generated/openapi/network.json
++++ b/generated/openapi/network.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Network API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/news.json b/generated/openapi/news.json
iindex 6f903fcf..8915051b 100644
---- a/generated/openapi/news.json
++++ b/generated/openapi/news.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.News API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/openre.json b/generated/openapi/openre.json
iindex a54c29ae..1f6800d8 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRe.Stream API",
-- "version": "0.121.0",
-- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/reviews.json b/generated/openapi/reviews.json
iindex 6611b32b..dd441be3 100644
---- a/generated/openapi/reviews.json
++++ b/generated/openapi/reviews.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Reviews API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/run.json b/generated/openapi/run.json
iindex 5628377b..b7c15ed7 100644
---- a/generated/openapi/run.json
++++ b/generated/openapi/run.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Run API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/search.json b/generated/openapi/search.json
iindex c679dbbb..8d986135 100644
---- a/generated/openapi/search.json
++++ b/generated/openapi/search.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Search API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/services.json b/generated/openapi/services.json
iindex 27e4e96a..25188be9 100644
---- a/generated/openapi/services.json
++++ b/generated/openapi/services.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Services API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/sources.json b/generated/openapi/sources.json
iindex edeede36..e50cb449 100644
---- a/generated/openapi/sources.json
++++ b/generated/openapi/sources.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Sources API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tips.json b/generated/openapi/tips.json
iindex 862ae6fa..b5c20a6e 100644
---- a/generated/openapi/tips.json
++++ b/generated/openapi/tips.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tips API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/tools.json b/generated/openapi/tools.json
iindex 27a30eb7..ac21ba14 100644
---- a/generated/openapi/tools.json
++++ b/generated/openapi/tools.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Tools API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/trade.json b/generated/openapi/trade.json
iindex b025647c..fa43526b 100644
---- a/generated/openapi/trade.json
++++ b/generated/openapi/trade.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Trade API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vip.json b/generated/openapi/vip.json
iindex 0a8bae77..77faa8d4 100644
---- a/generated/openapi/vip.json
++++ b/generated/openapi/vip.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.VIP API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/watch.json b/generated/openapi/watch.json
iindex 726ea740..0861f099 100644
---- a/generated/openapi/watch.json
++++ b/generated/openapi/watch.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Watch API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/wiki.json b/generated/openapi/wiki.json
iindex 8360b6ed..82f6602e 100644
---- a/generated/openapi/wiki.json
++++ b/generated/openapi/wiki.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Wiki API",
-- "version": "0.121.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.121.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
++ "version": "0.122.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.122.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/manifests/capabilities/inventory.definition.manage.json b/manifests/capabilities/inventory.definition.manage.json
iindex 9977a002..1993c708 100644
---- a/manifests/capabilities/inventory.definition.manage.json
++++ b/manifests/capabilities/inventory.definition.manage.json
@@@ -2,9 +2,9 @@
"id": "inventory.definition.manage",
"version": "1.0",
"owner": "inventory",
-- "status": "planned",
++ "status": "active",
"visibility": "first-party",
-- "description": "PLANNED (ADR-054, plan T21): Create, edit, submit and retire definitions in the caller's namespace (POST /api/v1/definitions, PATCH /api/v1/definitions/:id with inventory.definition-request@1 → inventory.definition@1). A creator's definition goes to review; a service's or app's is published when it asks. It becomes active when OpenVibe.Inventory implements the route.",
++ "description": "Create, edit, submit and retire definitions in the caller's namespace (POST /api/v1/definitions, PATCH /api/v1/definitions/:id with inventory.definition-request@1 → inventory.definition@1). A creator's definition goes to review; a service's or app's is published when it asks.",
"inputSchema": "inventory.definition-request@1",
"outputSchema": "inventory.definition@1",
"permissions": [
@@@ -15,5 +15,8 @@
],
"quotaClass": "inventory-write",
"events": [],
-- "implementedBy": []
++ "implementedBy": [
++ "POST /api/v1/definitions",
++ "PATCH /api/v1/definitions/:id"
++ ]
}
ddiff --git a/manifests/capabilities/inventory.equip.manage.json b/manifests/capabilities/inventory.equip.manage.json
iindex 5fa7e8bd..03f45b28 100644
---- a/manifests/capabilities/inventory.equip.manage.json
++++ b/manifests/capabilities/inventory.equip.manage.json
@@@ -2,9 +2,9 @@
"id": "inventory.equip.manage",
"version": "1.0",
"owner": "inventory",
-- "status": "planned",
++ "status": "active",
"visibility": "public",
-- "description": "PLANNED (ADR-054, plan T21): Equip or clear a slot with an instance the person owns (PUT /api/v1/me/equipped with inventory.equip-request@1 → inventory.equipped@1). One item per slot. Refuses an instance not owned or not in state owned (409 inventory.not_owned). It becomes active when OpenVibe.Inventory implements the route.",
++ "description": "Equip or clear a slot with an instance the person owns (PUT /api/v1/me/equipped with inventory.equip-request@1 → inventory.equipped@1). One item per slot. Refuses an instance not owned or not in state owned (409 inventory.not_owned).",
"inputSchema": "inventory.equip-request@1",
"outputSchema": "inventory.equipped@1",
"permissions": [
@@@ -15,5 +15,7 @@
],
"quotaClass": "inventory-write",
"events": [],
-- "implementedBy": []
++ "implementedBy": [
++ "PUT /api/v1/me/equipped"
++ ]
}
ddiff --git a/manifests/capabilities/inventory.item.consume.json b/manifests/capabilities/inventory.item.consume.json
iindex f3b503ed..ef6ade1c 100644
---- a/manifests/capabilities/inventory.item.consume.json
++++ b/manifests/capabilities/inventory.item.consume.json
@@@ -2,9 +2,9 @@
"id": "inventory.item.consume",
"version": "1.0",
"owner": "inventory",
-- "status": "planned",
++ "status": "active",
"visibility": "first-party",
-- "description": "PLANNED (ADR-054, plan T21): Consume or revoke an instance of a definition the caller issued (POST /api/v1/instances/:id/consume | /revoke → inventory.instance@1). It becomes active when OpenVibe.Inventory implements the route.",
++ "description": "Consume or revoke an instance of a definition the caller issued (POST /api/v1/instances/:id/consume | /revoke → inventory.instance@1).",
"inputSchema": "common.no-body@1",
"outputSchema": "inventory.instance@1",
"permissions": [
@@@ -15,5 +15,8 @@
],
"quotaClass": "inventory-write",
"events": [],
-- "implementedBy": []
++ "implementedBy": [
++ "POST /api/v1/instances/:id/consume",
++ "POST /api/v1/instances/:id/revoke"
++ ]
}
ddiff --git a/manifests/capabilities/inventory.item.grant.json b/manifests/capabilities/inventory.item.grant.json
iindex 8e53f7c3..25b26509 100644
---- a/manifests/capabilities/inventory.item.grant.json
++++ b/manifests/capabilities/inventory.item.grant.json
@@@ -2,9 +2,9 @@
"id": "inventory.item.grant",
"version": "1.0",
"owner": "inventory",
-- "status": "planned",
++ "status": "active",
"visibility": "first-party",
-- "description": "PLANNED (ADR-054, plan T21): Grant an instance of a definition the caller issued (POST /api/v1/grants with inventory.grant-request@1 → inventory.instance@1; Idempotency by idempotency_key). Outside the issuer's namespace: 403 inventory.not_issuer. Sold out: 409 inventory.supply_exhausted. Never for money (ADR-054 §5). It becomes active when OpenVibe.Inventory implements the route.",
++ "description": "Grant an instance of a definition the caller issued (POST /api/v1/grants with inventory.grant-request@1 → inventory.instance@1; Idempotency by idempotency_key). Outside the issuer's namespace: 403 inventory.not_issuer. Sold out: 409 inventory.supply_exhausted. Never for money (ADR-054 §5).",
"inputSchema": "inventory.grant-request@1",
"outputSchema": "inventory.instance@1",
"permissions": [
@@@ -15,5 +15,7 @@
],
"quotaClass": "inventory-write",
"events": [],
-- "implementedBy": []
++ "implementedBy": [
++ "POST /api/v1/grants"
++ ]
}
ddiff --git a/manifests/capabilities/inventory.item.list.json b/manifests/capabilities/inventory.item.list.json
iindex 0a3f7576..77ed14b4 100644
---- a/manifests/capabilities/inventory.item.list.json
++++ b/manifests/capabilities/inventory.item.list.json
@@@ -2,9 +2,9 @@
"id": "inventory.item.list",
"version": "1.0",
"owner": "inventory",
-- "status": "planned",
++ "status": "active",
"visibility": "public",
-- "description": "PLANNED (ADR-054, plan T21): The person's own full inventory, consumed and revoked instances included (GET /api/v1/me/items → inventory.inventory@1). A service may read it acting for the person (on_behalf_of). It becomes active when OpenVibe.Inventory implements the route.",
++ "description": "The person's own full inventory, consumed and revoked instances included (GET /api/v1/me/items → inventory.inventory@1). A service may read it acting for the person (on_behalf_of).",
"inputSchema": "common.no-body@1",
"outputSchema": "inventory.inventory@1",
"permissions": [
@@@ -15,5 +15,7 @@
],
"quotaClass": "inventory-read",
"events": [],
-- "implementedBy": []
++ "implementedBy": [
++ "GET /api/v1/me/items"
++ ]
}
ddiff --git a/manifests/capabilities/inventory.item.read.json b/manifests/capabilities/inventory.item.read.json
iindex 87e47638..2768056a 100644
---- a/manifests/capabilities/inventory.item.read.json
++++ b/manifests/capabilities/inventory.item.read.json
@@@ -2,9 +2,9 @@
"id": "inventory.item.read",
"version": "1.0",
"owner": "inventory",
-- "status": "planned",
++ "status": "active",
"visibility": "public",
-- "description": "PLANNED (ADR-054, plan T21): Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds. It becomes active when OpenVibe.Inventory implements the route.",
++ "description": "Read a person's public inventory (GET /api/v1/people/:subject/items → inventory.inventory@1: owned instances of published definitions), their equipped set (GET /api/v1/people/:subject/equipped, GET /api/v1/equipped?subjects=… up to 100 → inventory.equipped-batch@1), definitions and kinds.",
"inputSchema": "common.no-body@1",
"outputSchema": "inventory.inventory@1",
"permissions": [
@@@ -13,5 +13,13 @@
"resourceConstraints": [],
"quotaClass": "inventory-read",
"events": [],
-- "implementedBy": []
++ "implementedBy": [
++ "GET /api/v1/kinds",
++ "GET /api/v1/kinds/:id",
++ "GET /api/v1/definitions",
++ "GET /api/v1/definitions/:id",
++ "GET /api/v1/people/:subject/items",
++ "GET /api/v1/people/:subject/equipped",
++ "GET /api/v1/equipped"
++ ]
}
ddiff --git a/manifests/services/inventory.json b/manifests/services/inventory.json
iindex 9fc914ae..ffc671ee 100644
---- a/manifests/services/inventory.json
++++ b/manifests/services/inventory.json
@@@ -1,20 +1,19 @@
{
-- "version": "0.0.0",
++ "version": "0.2.0",
"contractRanges": {
-- "openvibe-contracts": ">=0.121.0 <1.0.0"
++ "openvibe-contracts": ">=0.122.0 <1.0.0"
},
"id": "inventory",
"name": "OpenVibe.Inventory",
-- "status": "placeholder",
++ "status": "alpha",
"repository": "OpenVibers/OpenVibe.Inventory",
"domains": [
"inventory.openvibe.network"
],
"publicOrigin": "https://inventory.openvibe.network",
"exposure": {
-- "state": "placeholder",
-- "publicSite": null,
-- "note": "planned (ADR-054, plan T21 step 1); nothing is built or deployed yet. Live's cosmetics stay in Live until the migration in ADR-054 §8."
++ "state": "live",
++ "publicSite": "service"
},
"capabilities": [
"inventory.item.read",
@@@ -33,27 +32,76 @@
"inventory.item.unequipped",
"inventory.definition.published"
],
-- "eventsConsumed": [],
-- "namespacesOwned": [],
++ "eventsConsumed": [
++ "network.account.export_requested",
++ "network.account.deleted"
++ ],
++ "namespacesOwned": [
++ "inventory.*"
++ ],
"lifecycle": {
"liveness": {
-- "none": "not built yet; nothing listens on a loopback address"
++ "endpoint": "/api/health",
++ "means": "the process is up and answers HTTP, with the outbox relay's state; the database is what ready checks"
},
"shutdown": {
-- "none": "not built yet; nothing runs or drains"
++ "signal": "SIGTERM",
++ "deadlineSeconds": 10,
++ "drains": [
++ "HTTP server closed",
++ "Events subscription retries stopped",
++ "outbox relay stopped",
++ "Network key refresher stopped",
++ "store closed"
++ ]
},
"startupRecovery": {
-- "none": "not built yet; nothing starts"
++ "resumes": [
++ {
++ "kind": "sessions",
++ "what": "sign-in sessions are cookies verified against Network's keys, fetched again at boot"
++ },
++ {
++ "kind": "state",
++ "what": "kinds and Live's definitions are registered again at boot (idempotent); every grant, equip and ledger row was committed with its event in one transaction"
++ },
++ {
++ "kind": "outbox",
++ "what": "events written before the stop and not yet sent leave event_outbox when the relay starts"
++ },
++ {
++ "kind": "consumer",
++ "what": "OpenVibe.Events redelivers network.account.export_requested and network.account.deleted that were pending during the stop (at least once; account_data_events applies each export and deletion once)"
++ }
++ ]
},
"rollback": {
-- "none": "not built yet; nothing is released or rolled back"
++ "conditions": [
++ "automatic: ovhost deploy puts the previous sha back and restarts again when the ready URL does not answer 2xx within ready.timeoutSeconds after the restart (exit 3)",
++ "manual: ovhost rollback <service> --to <sha>"
++ ],
++ "window": "automatic only while ovhost waits for readiness after the restart; manual afterwards, as long as no blocker applies",
++ "blockers": {
++ "none": "migration 0001 only creates Inventory's own tables; Live keeps its own cosmetics tables until the switch (ADR-054 §8)"
++ }
},
"contracts": {
-- "range": ">=0.121.0 <1.0.0"
++ "range": ">=0.122.0 <1.0.0"
},
"leases": {
-- "none": "not built yet; nothing runs"
++ "none": "no claims: one process serves the site and the API"
}
},
-- "notes": "The network-wide inventory (ADR-054): item kinds (a contract plus a renderer per surface), definitions (itd_), instances (inv_), the equipped set and an append-only ledger, in its own PostgreSQL database (ov_inventory, loopback 5030). Issuers (services, apps, creators) grant within their namespace; no selling, buying, trading or conversion until a later money ADR (ADR-012, ADR-025). Live's cosmetics become the first kinds, migrated convert-verify-delete. Profiles are Network's and read the showcase here."
++ "notes": "Port 5030, unit openvibe-inventory.service, inventory.openvibe.network (the openvibe.network wildcard certificate). The network-wide inventory (ADR-054): item kinds (a contract plus a renderer per surface), definitions (itd_), instances (inv_), the equipped set and an append-only ledger in its own PostgreSQL database (ov_inventory). Issuers (services, apps) grant only within their namespace; people equip what they own; public reads need no token. Nothing is sold, bought, traded or converted until a later money ADR (ADR-012, ADR-025). Live's 70 cosmetics are seeded at boot as definitions issued by service:live (Live's item ids kept as aliases), and scripts/import-live.js moves Live's unlocks and equipped slots here row for row; Live then reads through this API (INVENTORY_AUTHORITY). Answers account export and deletion (ADR-033). inventory.definition.review stays planned until creator submissions open.",
++ "health": "/api/health",
++ "ready": "/api/ready",
++ "internalOrigin": "http://127.0.0.1:5030",
++ "site": {
++ "name": "Inventory",
++ "icon": "games",
++ "tagline": "Your items, on every OpenVibe site.",
++ "what": "Keep the items you earn across OpenVibe in one place, and choose what you wear in chat, on stream overlays and on your profile.",
++ "legalProfile": "ugc",
++ "position": 30
++ }
}
ddiff --git a/package-lock.json b/package-lock.json
iindex 97adf349..03664119 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-contracts",
-- "version": "0.121.0",
++ "version": "0.122.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.121.0",
++ "version": "0.122.0",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 51d0ab6f..fa16d5e6 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.121.0",
++ "version": "0.122.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"types": "generated/typescript/index.d.ts",