openvibers/openvibe.contracts Commits

Contracts 0.169.0: actor.resource.control (stop a task) and media.resource.control (delete an object) (#125)

OP OpenVibers committed 30 days ago · fe6a457b7a · 41 files, +543 −73

Plan T13 step 10: Actor and Media join Watch and Events as authorities behind the Services control route.

- **`actor.resource.control`** (active, first-party, sensitive). `stop` cancels a person's `actor.task`:
  - a queued task ends at once;
  - a running task is aborted and ends cancelled when its current step returns.
- **`media.resource.control`** (active, first-party, sensitive). `delete` soft-deletes a person's `media.object`, exactly as `DELETE /api/v1/objects/:id` does:
  - the object is restorable until its retention period ends;
  - held objects and legacy-managed objects are refused.
- Both act only for the resource's owner, inside the OVRN's project. Both take dry runs and are idempotent per (caller, project, key).
- The `actor` and `media` manifests list them.

Additive; 0.169.0. The suite passes (19,717 checks); `compat.js v0.168.0` finds no breaking change.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex ecb137df..2b0fcede 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,16 @@ 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.169.0 — 2026-10-14
++
++- **`actor.resource.control`** (active, first-party, sensitive): OpenVibe.Actor's control API (ADR-048, plan T13 step
++ 10). `POST /api/v1/resources/control` takes `stop` for a person's `actor.task` (cancel: a queued task ends at once, a
++ running one is aborted and ends cancelled). The `actor` manifest lists it.
++- **`media.resource.control`** (active, first-party, sensitive): OpenVibe.Media's control API. `delete` soft-deletes a
++ person's `media.object` exactly as `DELETE /api/v1/objects/:id` does (restorable until its retention period ends; held
++ and legacy-managed objects are refused). The `media` manifest lists it.
++- Both: only the resource's owner, inside the OVRN's project; dry runs; idempotent per (caller, project, key). Additive.
++
## 0.168.0 — 2026-10-14
- **`events.resource.control`** (active, first-party, sensitive): OpenVibe.Events' control API (ADR-048, plan T13 step
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex 636ad6c0..4c046522 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.168.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.169.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"
@@@ -900,6 +900,62 @@
}
}
},
++ "/api/v1/resources/control": {
++ "post": {
++ "operationId": "post_api_v1_resources_control",
++ "summary": "Control a task through OpenVibe.Actor's control API (ADR-048, plan T13 step 10): POST /api/v1/resources/control takes one common.resource-control-request@1 naming an actor.task by its OVRN, from a fir",
++ "description": "**actor.resource.control** (first-party): Control a task through OpenVibe.Actor's control API (ADR-048, plan T13 step 10): POST /api/v1/resources/control takes one common.resource-control-request@1 naming an actor.task by its OVRN, from a first-party service (OpenVibe.Services) acting for the person in on_behalf_of. Action: stop (cancel the task: a queued task ends at once, a running one is aborted and ends cancelled when its current step returns; its cost so far is kept and charged as usual); a task that already ended answers done with changed false. Any other action is refused unsupported (Actor deletes tasks only with the person's account data). Only the person who asked for the task may act on it, and only inside the project the OVRN names. dry_run decides and explains without applying. The first answer per (caller, project, idempotency_key) is kept and returned for a repeat; the same key with another request is refused. Answers common.resource-control-result@1.",
++ "tags": [
++ "actor.resource"
++ ],
++ "x-openvibe-capabilities": [
++ "actor.resource.control"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "standard",
++ "security": [
++ {
++ "openvibeToken": [
++ "actor.resource.control"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/common.resource-control-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/common.resource-control-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/api/v1/route": {
"post": {
"operationId": "post_api_v1_route",
@@@ -1894,6 +1950,147 @@
}
}
},
++ "common.resource-control-request.v1": {
++ "title": "ResourceControlRequest",
++ "description": "common.resource-control-request@1: one control operation OpenVibe.Services (or Actor's Console) sends to the authority that owns a resource (ADR-048, plan T13). Services never mutates another service's database; every create, update, start, stop, delete, resize, rotate, pair, grant or revoke is this request to the owning authority's control API, which decides and answers with a common.resource-control-result@1. A request names exactly one of resource (every action but create) or resource_kind (create, before the name exists). project_id is the tenancy boundary and equals the project segment of resource. idempotency_key makes a retry safe: the authority answers a repeated key with the first result. A sensitive action (money, publishing, deleting, physical control) is refused with confirmation_required until its owner approves; the retry carries that confirmation_id (roadmap WS-Z2). The cross-field rules are checked by contracts.resources.checkControlRequest.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "action",
++ "project_id",
++ "idempotency_key"
++ ],
++ "oneOf": [
++ {
++ "required": [
++ "resource"
++ ]
++ },
++ {
++ "required": [
++ "resource_kind"
++ ]
++ }
++ ],
++ "properties": {
++ "action": {
++ "enum": [
++ "create",
++ "update",
++ "delete",
++ "start",
++ "stop",
++ "suspend",
++ "resume",
++ "resize",
++ "rotate",
++ "pair",
++ "grant",
++ "revoke",
++ "archive"
++ ]
++ },
++ "resource": {
++ "$ref": "#/components/schemas/common.resource-name.v1",
++ "description": "The resource acted on; required for every action but create."
++ },
++ "resource_kind": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{0,31}\\.[a-z][a-z0-9-]{0,39}$",
++ "description": "service.type (a common.resource-summary@1 kind), for create, before the resource name exists."
++ },
++ "project_id": {
++ "type": "string",
++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "params": {
++ "type": "object",
++ "description": "Action-specific input, shaped by the authority's own contract (never redefined here)."
++ },
++ "idempotency_key": {
++ "type": "string",
++ "minLength": 8,
++ "maxLength": 200
++ },
++ "on_behalf_of": {
++ "$ref": "#/components/schemas/identity.subject-ref.v1",
++ "description": "The subject whose grant the authority checks; the caller's own token says who sent it."
++ },
++ "confirmation_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80,
++ "description": "The approved confirmation from an earlier confirmation_required answer."
++ },
++ "dry_run": {
++ "type": "boolean",
++ "default": false,
++ "description": "Decide and explain without applying."
++ },
++ "trace_id": {
++ "type": "string",
++ "pattern": "^[0-9a-f]{32}$"
++ }
++ }
++ },
++ "common.resource-control-result.v1": {
++ "title": "ResourceControlResult",
++ "description": "common.resource-control-result@1: the authority's answer to a common.resource-control-request@1 (ADR-048, plan T13). state is the outcome, not the resource's own state: done (applied), pending (accepted and asynchronous; the authority reports completion later on its events), refused (a policy or confirmation gate said no) or failed (an error). State rules: refused carries problem or confirmation_required; failed carries problem; done and pending carry neither; confirmation_required appears only on refused. result carries the authority's own response document and never another service's rows. The state rules are checked by contracts.resources.checkControlResult.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "action",
++ "state",
++ "at"
++ ],
++ "properties": {
++ "action": {
++ "type": "string"
++ },
++ "resource": {
++ "$ref": "#/components/schemas/common.resource-name.v1"
++ },
++ "state": {
++ "enum": [
++ "done",
++ "pending",
++ "refused",
++ "failed"
++ ]
++ },
++ "result": {
++ "type": "object"
++ },
++ "confirmation_required": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "confirmation_id",
++ "reason"
++ ],
++ "properties": {
++ "confirmation_id": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "reason": {
++ "type": "string"
++ }
++ },
++ "description": "The action needs its owner's approval; retry the same request with this confirmation_id once approved."
++ },
++ "problem": {
++ "$ref": "#/components/schemas/errors.problem.v1",
++ "description": "RFC 9457 body when refused or failed."
++ },
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ },
"common.resource-list-result.v1": {
"title": "ResourceListResult",
"description": "A page of the resource index (roadmap WS-Z7).",
@@@ -1940,6 +2137,16 @@
}
}
},
++ "common.resource-name.v1": {
++ "title": "ResourceName",
++ "description": "common.resource-name@1: the one stable, cross-service name of an OpenVibe resource (OVRN; ADR-034 section 2, ADR-048, plan T13): ovrn:<service>:<project_id>:<type>/<id>, for example ovrn:media:prj_01J0000000000000000000000A:object/med_01K0000000000000000000000B. The service segment is the authority that owns the resource; the project segment is its tenancy boundary; type is the second half of a common.resource-summary@1 kind and id is that summary's id, so the name composes from any resource summary. It is used in grant scopes, audit rows, event subjects, usage records, bill lines and console URLs. It never names a person, an app, a request, a session or an event. The pattern is the one common.usage-recorded@1 resource and common.resource-summary@1 ovrn already use.",
++ "type": "string",
++ "maxLength": 200,
++ "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",
++ "not": {
++ "pattern": "/(usr|gst|app|mod|svc|job|evt|req)_"
++ }
++ },
"common.resource-summary.v1": {
"title": "ResourceSummary",
"description": "One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.",
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex 43e5b000..87058d5c 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.168.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 7f2c060c..e79751cd 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.168.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 24258031..a871dbb1 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.168.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 720f0ec2..dea3cdcd 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.168.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 4faf15f9..4146599a 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.168.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.169.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/codes.json b/generated/openapi/codes.json
iindex 6cc54071..a4111391 100644
---- a/generated/openapi/codes.json
++++ b/generated/openapi/codes.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Codes API",
-- "version": "0.168.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 72e41144..03fc460d 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.168.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 272af9c2..99e762c4 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.168.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 10829a2c..8d5bd15e 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.168.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 d4f6cea3..905a1b0e 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.168.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 5855b5ef..708c7c63 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.168.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 75dad9f7..7f9cffc0 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.168.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 28e66641..97edfa37 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.168.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 e79e27e5..82f2e309 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -5,8 +5,8 @@
"service": "actor",
"name": "OpenVibe.Actor",
"origin": "https://openvibe.actor",
-- "operations": 21,
-- "capabilities": 7
++ "operations": 22,
++ "capabilities": 8
},
{
"service": "ai",
@@@ -117,8 +117,8 @@
"service": "media",
"name": "OpenVibe.Media",
"origin": "https://openvibe.media",
-- "operations": 9,
-- "capabilities": 6
++ "operations": 10,
++ "capabilities": 7
},
{
"service": "media-hub",
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex 223fe392..6301ebf6 100644
---- a/generated/openapi/inventory.json
++++ b/generated/openapi/inventory.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Inventory API",
-- "version": "0.168.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.169.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/live.json b/generated/openapi/live.json
iindex be1c1b90..5e09a726 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.168.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.169.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-hub.json b/generated/openapi/media-hub.json
iindex cb674976..c1fa1961 100644
---- a/generated/openapi/media-hub.json
++++ b/generated/openapi/media-hub.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.MediaHub API",
-- "version": "0.168.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 a1f1beff..dde6caaa 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.168.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.169.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"
@@@ -248,6 +248,62 @@
}
}
},
++ "/api/v1/resources/control": {
++ "post": {
++ "operationId": "post_api_v1_resources_control",
++ "summary": "Control a media object through OpenVibe.Media's control API (ADR-048, plan T13 step 10): POST /api/v1/resources/control takes one common.resource-control-request@1 naming a media.object by its OVRN, f",
++ "description": "**media.resource.control** (first-party): Control a media object through OpenVibe.Media's control API (ADR-048, plan T13 step 10): POST /api/v1/resources/control takes one common.resource-control-request@1 naming a media.object by its OVRN, from a first-party service (OpenVibe.Services) acting for the person in on_behalf_of. Action: delete (a soft delete, exactly as DELETE /api/v1/objects/:id: the object stops being served at once and can be restored through the API until its retention period ends; an object under a retention hold, or a legacy VOD, clip or file managed through its own routes, is refused). Any other action is refused unsupported. Only the object's owner may act on it, and only inside the project the OVRN names. dry_run decides and explains without applying. The first answer per (caller, project, idempotency_key) is kept and returned for a repeat; the same key with another request is refused. Answers common.resource-control-result@1.",
++ "tags": [
++ "media.resource"
++ ],
++ "x-openvibe-capabilities": [
++ "media.resource.control"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "standard",
++ "security": [
++ {
++ "openvibeToken": [
++ "media.resource.control"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/common.resource-control-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/common.resource-control-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/api/v2/{app}/objects": {
"get": {
"operationId": "get_api_v2_app_objects",
@@@ -547,6 +603,147 @@
},
"components": {
"schemas": {
++ "common.resource-control-request.v1": {
++ "title": "ResourceControlRequest",
++ "description": "common.resource-control-request@1: one control operation OpenVibe.Services (or Actor's Console) sends to the authority that owns a resource (ADR-048, plan T13). Services never mutates another service's database; every create, update, start, stop, delete, resize, rotate, pair, grant or revoke is this request to the owning authority's control API, which decides and answers with a common.resource-control-result@1. A request names exactly one of resource (every action but create) or resource_kind (create, before the name exists). project_id is the tenancy boundary and equals the project segment of resource. idempotency_key makes a retry safe: the authority answers a repeated key with the first result. A sensitive action (money, publishing, deleting, physical control) is refused with confirmation_required until its owner approves; the retry carries that confirmation_id (roadmap WS-Z2). The cross-field rules are checked by contracts.resources.checkControlRequest.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "action",
++ "project_id",
++ "idempotency_key"
++ ],
++ "oneOf": [
++ {
++ "required": [
++ "resource"
++ ]
++ },
++ {
++ "required": [
++ "resource_kind"
++ ]
++ }
++ ],
++ "properties": {
++ "action": {
++ "enum": [
++ "create",
++ "update",
++ "delete",
++ "start",
++ "stop",
++ "suspend",
++ "resume",
++ "resize",
++ "rotate",
++ "pair",
++ "grant",
++ "revoke",
++ "archive"
++ ]
++ },
++ "resource": {
++ "$ref": "#/components/schemas/common.resource-name.v1",
++ "description": "The resource acted on; required for every action but create."
++ },
++ "resource_kind": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9-]{0,31}\\.[a-z][a-z0-9-]{0,39}$",
++ "description": "service.type (a common.resource-summary@1 kind), for create, before the resource name exists."
++ },
++ "project_id": {
++ "type": "string",
++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "params": {
++ "type": "object",
++ "description": "Action-specific input, shaped by the authority's own contract (never redefined here)."
++ },
++ "idempotency_key": {
++ "type": "string",
++ "minLength": 8,
++ "maxLength": 200
++ },
++ "on_behalf_of": {
++ "$ref": "#/components/schemas/identity.subject-ref.v1",
++ "description": "The subject whose grant the authority checks; the caller's own token says who sent it."
++ },
++ "confirmation_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 80,
++ "description": "The approved confirmation from an earlier confirmation_required answer."
++ },
++ "dry_run": {
++ "type": "boolean",
++ "default": false,
++ "description": "Decide and explain without applying."
++ },
++ "trace_id": {
++ "type": "string",
++ "pattern": "^[0-9a-f]{32}$"
++ }
++ }
++ },
++ "common.resource-control-result.v1": {
++ "title": "ResourceControlResult",
++ "description": "common.resource-control-result@1: the authority's answer to a common.resource-control-request@1 (ADR-048, plan T13). state is the outcome, not the resource's own state: done (applied), pending (accepted and asynchronous; the authority reports completion later on its events), refused (a policy or confirmation gate said no) or failed (an error). State rules: refused carries problem or confirmation_required; failed carries problem; done and pending carry neither; confirmation_required appears only on refused. result carries the authority's own response document and never another service's rows. The state rules are checked by contracts.resources.checkControlResult.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "action",
++ "state",
++ "at"
++ ],
++ "properties": {
++ "action": {
++ "type": "string"
++ },
++ "resource": {
++ "$ref": "#/components/schemas/common.resource-name.v1"
++ },
++ "state": {
++ "enum": [
++ "done",
++ "pending",
++ "refused",
++ "failed"
++ ]
++ },
++ "result": {
++ "type": "object"
++ },
++ "confirmation_required": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "confirmation_id",
++ "reason"
++ ],
++ "properties": {
++ "confirmation_id": {
++ "type": "string",
++ "maxLength": 80
++ },
++ "reason": {
++ "type": "string"
++ }
++ },
++ "description": "The action needs its owner's approval; retry the same request with this confirmation_id once approved."
++ },
++ "problem": {
++ "$ref": "#/components/schemas/errors.problem.v1",
++ "description": "RFC 9457 body when refused or failed."
++ },
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ },
"common.resource-list-result.v1": {
"title": "ResourceListResult",
"description": "A page of the resource index (roadmap WS-Z7).",
@@@ -593,6 +790,16 @@
}
}
},
++ "common.resource-name.v1": {
++ "title": "ResourceName",
++ "description": "common.resource-name@1: the one stable, cross-service name of an OpenVibe resource (OVRN; ADR-034 section 2, ADR-048, plan T13): ovrn:<service>:<project_id>:<type>/<id>, for example ovrn:media:prj_01J0000000000000000000000A:object/med_01K0000000000000000000000B. The service segment is the authority that owns the resource; the project segment is its tenancy boundary; type is the second half of a common.resource-summary@1 kind and id is that summary's id, so the name composes from any resource summary. It is used in grant scopes, audit rows, event subjects, usage records, bill lines and console URLs. It never names a person, an app, a request, a session or an event. The pattern is the one common.usage-recorded@1 resource and common.resource-summary@1 ovrn already use.",
++ "type": "string",
++ "maxLength": 200,
++ "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",
++ "not": {
++ "pattern": "/(usr|gst|app|mod|svc|job|evt|req)_"
++ }
++ },
"common.resource-summary.v1": {
"title": "ResourceSummary",
"description": "One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.",
ddiff --git a/generated/openapi/network.json b/generated/openapi/network.json
iindex 95ad9be2..4d22df53 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.168.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 cffefdd9..832ad87d 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.168.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 a71aeb78..1f3bada2 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": "OpenRestream API",
-- "version": "0.168.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 279f1914..d71f984f 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.168.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 dfb0dcf9..32199241 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.168.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 5d26c168..72aca1f4 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.168.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 fda3856a..109dd615 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.168.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 14fcb5c5..e675d71f 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.168.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.169.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/space.json b/generated/openapi/space.json
iindex b80d3cb7..0bd56afc 100644
---- a/generated/openapi/space.json
++++ b/generated/openapi/space.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Space API",
-- "version": "0.168.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 f398447c..4eb175de 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.168.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 92791ee1..ab5e972c 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.168.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 cb1f2ab6..4a585b5a 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.168.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 ecf0b428..5a1d83ea 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.168.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 ea9e0482..621734e4 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.168.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.169.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 061189c4..a396fd19 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.168.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.169.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/work.json b/generated/openapi/work.json
iindex b61129e5..4aadea9a 100644
---- a/generated/openapi/work.json
++++ b/generated/openapi/work.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Work API",
-- "version": "0.168.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.168.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.169.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.169.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/actor.resource.control.json b/manifests/capabilities/actor.resource.control.json
nnew file mode 100644
iindex 00000000..dbd48bce
---- /dev/null
++++ b/manifests/capabilities/actor.resource.control.json
@@@ -0,0 +1,22 @@
++{
++ "id": "actor.resource.control",
++ "version": "1.0",
++ "owner": "actor",
++ "status": "active",
++ "visibility": "first-party",
++ "sensitive": true,
++ "description": "Control a task through OpenVibe.Actor's control API (ADR-048, plan T13 step 10): POST /api/v1/resources/control takes one common.resource-control-request@1 naming an actor.task by its OVRN, from a first-party service (OpenVibe.Services) acting for the person in on_behalf_of. Action: stop (cancel the task: a queued task ends at once, a running one is aborted and ends cancelled when its current step returns; its cost so far is kept and charged as usual); a task that already ended answers done with changed false. Any other action is refused unsupported (Actor deletes tasks only with the person's account data). Only the person who asked for the task may act on it, and only inside the project the OVRN names. dry_run decides and explains without applying. The first answer per (caller, project, idempotency_key) is kept and returned for a repeat; the same key with another request is refused. Answers common.resource-control-result@1.",
++ "permissions": [
++ "resources:control"
++ ],
++ "resourceConstraints": [
++ "project"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/resources/control"
++ ],
++ "inputSchema": "common.resource-control-request@1",
++ "outputSchema": "common.resource-control-result@1"
++}
ddiff --git a/manifests/capabilities/media.resource.control.json b/manifests/capabilities/media.resource.control.json
nnew file mode 100644
iindex 00000000..4fbc8197
---- /dev/null
++++ b/manifests/capabilities/media.resource.control.json
@@@ -0,0 +1,22 @@
++{
++ "id": "media.resource.control",
++ "version": "1.0",
++ "owner": "media",
++ "status": "active",
++ "visibility": "first-party",
++ "sensitive": true,
++ "description": "Control a media object through OpenVibe.Media's control API (ADR-048, plan T13 step 10): POST /api/v1/resources/control takes one common.resource-control-request@1 naming a media.object by its OVRN, from a first-party service (OpenVibe.Services) acting for the person in on_behalf_of. Action: delete (a soft delete, exactly as DELETE /api/v1/objects/:id: the object stops being served at once and can be restored through the API until its retention period ends; an object under a retention hold, or a legacy VOD, clip or file managed through its own routes, is refused). Any other action is refused unsupported. Only the object's owner may act on it, and only inside the project the OVRN names. dry_run decides and explains without applying. The first answer per (caller, project, idempotency_key) is kept and returned for a repeat; the same key with another request is refused. Answers common.resource-control-result@1.",
++ "permissions": [
++ "resources:control"
++ ],
++ "resourceConstraints": [
++ "project"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/resources/control"
++ ],
++ "inputSchema": "common.resource-control-request@1",
++ "outputSchema": "common.resource-control-result@1"
++}
ddiff --git a/manifests/services/actor.json b/manifests/services/actor.json
iindex d27f14df..3a764183 100644
---- a/manifests/services/actor.json
++++ b/manifests/services/actor.json
@@@ -21,6 +21,7 @@
"actor.task.list",
"actor.agent.read",
"actor.resource.read",
++ "actor.resource.control",
"actor.agent.manage",
"actor.agent.run"
],
ddiff --git a/manifests/services/media.json b/manifests/services/media.json
iindex f7ea2a4e..e810907e 100644
---- a/manifests/services/media.json
++++ b/manifests/services/media.json
@@@ -37,6 +37,7 @@
"media.object.read",
"media.object.upload",
"media.resource.read",
++ "media.resource.control",
"media.upload.create"
],
"eventsProduced": [
ddiff --git a/package.json b/package.json
iindex 182322af..afe1ba7c 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.168.0",
++ "version": "0.169.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",