openvibers/openvibe.contracts Commits

0.286.0: watch.rate.changed/approved/rejected event payloads (P6) (#295)

OP OpenVibers committed 9 days ago · e040e592e3 · 64 files, +907 −89

OpenVibe.Watch #205 emits watch.rate.changed when a provider's official price document states a new value, and watch.rate.approved / watch.rate.rejected when a person decides it. Contracts now describes the three payloads exactly as Watch sends them: the change (change_id, source_key, provider, model, token_class, from/to nano-USD per million as D1 decimal strings, currency, region, effective_date, source_url, fetched_at, approval_required) and the decision (state, decided_by usr_, decided_at, applied false).

Evidence only: Watch writes no rate card and an approval is dated evidence for OpenVibe.AI's catalog operator, who alone changes the supply rate card through AI's own path. Watch's manifest lists the three events in eventsProduced; AI's eventsConsumed is empty, so it is not registered as a consumer.

Checked: OV_ALLOW_SUITE=1 node test/run.js (24754 checks passed, generated/ up to date, compat vs v0.284.0 no breaking changes); gitleaks --pre-commit --staged.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex ecb25e43..5e687a62 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,6 +1,22 @@
# Changelog
++## 0.286.0 — 2026-11-04
++
++- **Provider-rate evidence events: `watch.rate.changed@1`, `watch.rate.approved@1`, `watch.rate.rejected@1`**
++ (OpenVibe.Watch #205, plan P6, flag `WATCH_PROVIDER_RATES` off by default).
++ - `watch.rate.changed` is raised when a provider's official price document states a new value for one model and
++ token class. It carries `change_id`, `source_key`, `provider`, `model`, `token_class` (`input`, `cached_read`,
++ `cache_write`, `output`), `from_nano_usd_per_m` (null for a first price), `to_nano_usd_per_m`, `currency`,
++ `region`, `effective_date`, `source_url`, `fetched_at` and `approval_required`.
++ - `watch.rate.approved` and `watch.rate.rejected` are the same change plus `state`, `decided_by` (a person's
++ `usr_` id; Watch refuses a service or an agent), `decided_at` and `applied` (always false).
++ - Money is integer nano-USD per million tokens as decimal strings (D1); all three schemas refuse numbers and floats.
++ - Evidence only: Watch writes no rate card. An approval is dated evidence for OpenVibe.AI's catalog operator, who
++ alone changes the supply rate card through AI's own path.
++ - Watch's service manifest now lists the three events in `eventsProduced`. OpenVibe.AI consumes no events yet
++ (`eventsConsumed` is empty), so it is not registered as a consumer.
++
## 0.285.0 — 2026-11-03
- **`ai.inference.create` is retired** (AI Exchange D8′).
ddiff --git a/README.md b/README.md
iindex ada4dc1a..d7bbc9cb 100644
---- a/README.md
++++ b/README.md
@@@ -2,7 +2,7 @@
> Machine-readable contracts for the whole OpenVibe network.
--**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.284.0: 969 schemas in `contracts/catalog.json`, 45 service manifests, 440 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
++**Status:** alpha (first released in Wave 1; the release is package.json's `version`, tagged). At v0.286.0: 974 schemas in `contracts/catalog.json`, 45 service manifests, 440 capability manifests, 13 namespace manifests and the staff capability map. Service repositories run `openvibe-contracts-check` and the pin-drift check in CI, and deployed services verify service and app tokens with `serviceAuth` in production. Consumers pin release tags (each repository's `STATUS.json` names its pin). `node scripts/docs-currency.js <root>` checks every checkout's README and `STATUS.json` against its code: the pins and versions they name, a library's consumer list, the deployed flag against the manifest, README links, and the paths and migrations they name. `node scripts/estate.js` generates `docs/ESTATE.md` and `manifests/repositories/` from the estate checkouts, and `--check` fails on drift (plan T1 step 3).
**Plan:** OpenVibe Development Roadmap, Wave 1 (implementation plan rev 3, §3.1 and §18.11).
**License:** AGPL-3.0 (same as every OpenVibe service).
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex f39607ac..9fc09517 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -4591,6 +4591,33 @@
"compatibility": "backward",
"status": "planned"
},
++ {
++ "id": "watch.rate.changed",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "events/payloads/watch.rate.changed.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "watch.rate.approved",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "events/payloads/watch.rate.approved.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "watch.rate.rejected",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "events/payloads/watch.rate.rejected.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
{
"id": "games.player.joined",
"version": "1.0.0",
ddiff --git a/contracts/events/payloads/watch.rate.approved.v1.json b/contracts/events/payloads/watch.rate.approved.v1.json
nnew file mode 100644
iindex 00000000..dd5014bf
---- /dev/null
++++ b/contracts/events/payloads/watch.rate.approved.v1.json
@@@ -0,0 +1,28 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.rate.approved.v1.json",
++ "title": "WatchRateApprovedPayload",
++ "description": "watch.rate.approved v1 (OpenVibe.Watch server/provider-rates.js decide(); plan P6, flag WATCH_PROVIDER_RATES off by default): a person approved a pending provider-rate change. The payload is the change (watch.rate.changed@1) plus the decision. It is EVIDENCE, not a billable rate: Watch writes no rate card, applied is always false, and OpenVibe.AI's catalog operator alone changes the supply rate card through AI's own path. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch; actor is the service, and decided_by names the person.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["change_id", "source_key", "provider", "model", "token_class", "from_nano_usd_per_m", "to_nano_usd_per_m", "currency", "region", "effective_date", "source_url", "fetched_at", "approval_required", "state", "decided_by", "decided_at", "applied"],
++ "properties": {
++ "change_id": { "type": "string", "pattern": "^prc_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "source_key": { "type": "string", "description": "The source Watch fetched: the provider's key in its registry (deepinfra, featherless)." },
++ "provider": { "type": "string", "description": "The provider whose document stated the rate (deepinfra, featherless)." },
++ "model": { "type": "string", "description": "The model id exactly as the provider's document stated it." },
++ "token_class": { "type": "string", "enum": ["input", "cached_read", "cache_write", "output"], "description": "The D1 token classes." },
++ "from_nano_usd_per_m": { "type": ["string", "null"], "pattern": "^[0-9]{1,19}$", "description": "The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price." },
++ "to_nano_usd_per_m": { "type": "string", "pattern": "^[0-9]{1,19}$", "description": "The value the document stated, as an integer nano-USD per million tokens string." },
++ "currency": { "type": "string", "description": "The document's currency; USD for both sources today." },
++ "region": { "type": "string", "description": "The document's scope; global for both sources today." },
++ "effective_date": { "type": "string", "format": "date", "description": "The first day this value was observed (YYYY-MM-DD)." },
++ "source_url": { "type": "string", "format": "uri", "description": "The official document fetched." },
++ "fetched_at": { "type": "string", "format": "date-time" },
++ "approval_required": { "const": false, "description": "false: the decision is made." },
++ "state": { "const": "approved" },
++ "decided_by": { "type": "string", "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$", "description": "The person who approved it. A service or an agent may not; Watch refuses those with watch.rate_person_only." },
++ "decided_at": { "type": "string", "format": "date-time" },
++ "applied": { "const": false, "description": "Always false: an approval is evidence and never writes a billable rate." }
++ }
++}
ddiff --git a/contracts/events/payloads/watch.rate.changed.v1.json b/contracts/events/payloads/watch.rate.changed.v1.json
nnew file mode 100644
iindex 00000000..a2eb356e
---- /dev/null
++++ b/contracts/events/payloads/watch.rate.changed.v1.json
@@@ -0,0 +1,24 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.rate.changed.v1.json",
++ "title": "WatchRateChangedPayload",
++ "description": "watch.rate.changed v1 (OpenVibe.Watch server/provider-rates.js changeEvent(); plan P6, flag WATCH_PROVIDER_RATES off by default): a provider's published price document stated a different value for one model and token class than Watch last observed. It is EVIDENCE, not a rate card: Watch writes no billable price, and a person (never a service or an agent) must approve or reject the change; the decision is dated evidence for OpenVibe.AI's catalog operator. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["change_id", "source_key", "provider", "model", "token_class", "from_nano_usd_per_m", "to_nano_usd_per_m", "currency", "region", "effective_date", "source_url", "fetched_at", "approval_required"],
++ "properties": {
++ "change_id": { "type": "string", "pattern": "^prc_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "source_key": { "type": "string", "description": "The source Watch fetched: the provider's key in its registry (deepinfra, featherless)." },
++ "provider": { "type": "string", "description": "The provider whose document stated the rate (deepinfra, featherless)." },
++ "model": { "type": "string", "description": "The model id exactly as the provider's document stated it." },
++ "token_class": { "type": "string", "enum": ["input", "cached_read", "cache_write", "output"], "description": "The D1 token classes." },
++ "from_nano_usd_per_m": { "type": ["string", "null"], "pattern": "^[0-9]{1,19}$", "description": "The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price." },
++ "to_nano_usd_per_m": { "type": "string", "pattern": "^[0-9]{1,19}$", "description": "The value the document states now, as an integer nano-USD per million tokens string." },
++ "currency": { "type": "string", "description": "The document's currency; USD for both sources today." },
++ "region": { "type": "string", "description": "The document's scope; global for both sources today." },
++ "effective_date": { "type": "string", "format": "date", "description": "The first day this value was observed (YYYY-MM-DD); an unchanged value keeps its first date." },
++ "source_url": { "type": "string", "format": "uri", "description": "The official document fetched; never a private or authenticated URL." },
++ "fetched_at": { "type": "string", "format": "date-time" },
++ "approval_required": { "type": "boolean", "description": "true for a change: it waits for a person's decision." }
++ }
++}
ddiff --git a/contracts/events/payloads/watch.rate.rejected.v1.json b/contracts/events/payloads/watch.rate.rejected.v1.json
nnew file mode 100644
iindex 00000000..44d7541c
---- /dev/null
++++ b/contracts/events/payloads/watch.rate.rejected.v1.json
@@@ -0,0 +1,28 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.rate.rejected.v1.json",
++ "title": "WatchRateRejectedPayload",
++ "description": "watch.rate.rejected v1 (OpenVibe.Watch server/provider-rates.js decide(); plan P6, flag WATCH_PROVIDER_RATES off by default): a person rejected a pending provider-rate change. The payload is the change (watch.rate.changed@1) plus the decision. Rejecting a change writes no rate, and applied is always false. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch; actor is the service, and decided_by names the person.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["change_id", "source_key", "provider", "model", "token_class", "from_nano_usd_per_m", "to_nano_usd_per_m", "currency", "region", "effective_date", "source_url", "fetched_at", "approval_required", "state", "decided_by", "decided_at", "applied"],
++ "properties": {
++ "change_id": { "type": "string", "pattern": "^prc_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "source_key": { "type": "string", "description": "The source Watch fetched: the provider's key in its registry (deepinfra, featherless)." },
++ "provider": { "type": "string", "description": "The provider whose document stated the rate (deepinfra, featherless)." },
++ "model": { "type": "string", "description": "The model id exactly as the provider's document stated it." },
++ "token_class": { "type": "string", "enum": ["input", "cached_read", "cache_write", "output"], "description": "The D1 token classes." },
++ "from_nano_usd_per_m": { "type": ["string", "null"], "pattern": "^[0-9]{1,19}$", "description": "The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price." },
++ "to_nano_usd_per_m": { "type": "string", "pattern": "^[0-9]{1,19}$", "description": "The value the document stated, as an integer nano-USD per million tokens string." },
++ "currency": { "type": "string", "description": "The document's currency; USD for both sources today." },
++ "region": { "type": "string", "description": "The document's scope; global for both sources today." },
++ "effective_date": { "type": "string", "format": "date", "description": "The first day this value was observed (YYYY-MM-DD)." },
++ "source_url": { "type": "string", "format": "uri", "description": "The official document fetched." },
++ "fetched_at": { "type": "string", "format": "date-time" },
++ "approval_required": { "const": false, "description": "false: the decision is made." },
++ "state": { "const": "rejected" },
++ "decided_by": { "type": "string", "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$", "description": "The person who rejected it. A service or an agent may not; Watch refuses those with watch.rate_person_only." },
++ "decided_at": { "type": "string", "format": "date-time" },
++ "applied": { "const": false, "description": "Always false: a decision never writes a billable rate." }
++ }
++}
ddiff --git a/fixtures/watch.rate.approved/invalid/applied-true.json b/fixtures/watch.rate.approved/invalid/applied-true.json
nnew file mode 100644
iindex 00000000..78e4ea07
---- /dev/null
++++ b/fixtures/watch.rate.approved/invalid/applied-true.json
@@@ -0,0 +1,19 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "source_key": "deepinfra",
++ "provider": "deepinfra",
++ "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
++ "token_class": "input",
++ "from_nano_usd_per_m": "70000000",
++ "to_nano_usd_per_m": "90000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.deepinfra.com/models/list",
++ "fetched_at": "2026-11-03T09:15:00.000Z",
++ "approval_required": false,
++ "state": "approved",
++ "decided_by": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
++ "decided_at": "2026-11-03T12:00:00.000Z",
++ "applied": true
++}
ddiff --git a/fixtures/watch.rate.approved/invalid/service-decided.json b/fixtures/watch.rate.approved/invalid/service-decided.json
nnew file mode 100644
iindex 00000000..471215cc
---- /dev/null
++++ b/fixtures/watch.rate.approved/invalid/service-decided.json
@@@ -0,0 +1,19 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "source_key": "deepinfra",
++ "provider": "deepinfra",
++ "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
++ "token_class": "input",
++ "from_nano_usd_per_m": "70000000",
++ "to_nano_usd_per_m": "90000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.deepinfra.com/models/list",
++ "fetched_at": "2026-11-03T09:15:00.000Z",
++ "approval_required": false,
++ "state": "approved",
++ "decided_by": "svc_aix-admin",
++ "decided_at": "2026-11-03T12:00:00.000Z",
++ "applied": false
++}
ddiff --git a/fixtures/watch.rate.approved/valid/deepinfra-input.json b/fixtures/watch.rate.approved/valid/deepinfra-input.json
nnew file mode 100644
iindex 00000000..febd873a
---- /dev/null
++++ b/fixtures/watch.rate.approved/valid/deepinfra-input.json
@@@ -0,0 +1,19 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "source_key": "deepinfra",
++ "provider": "deepinfra",
++ "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
++ "token_class": "input",
++ "from_nano_usd_per_m": "70000000",
++ "to_nano_usd_per_m": "90000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.deepinfra.com/models/list",
++ "fetched_at": "2026-11-03T09:15:00.000Z",
++ "approval_required": false,
++ "state": "approved",
++ "decided_by": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
++ "decided_at": "2026-11-03T12:00:00.000Z",
++ "applied": false
++}
ddiff --git a/fixtures/watch.rate.changed/invalid/bad-token-class.json b/fixtures/watch.rate.changed/invalid/bad-token-class.json
nnew file mode 100644
iindex 00000000..5e9dcb59
---- /dev/null
++++ b/fixtures/watch.rate.changed/invalid/bad-token-class.json
@@@ -0,0 +1,15 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "source_key": "deepinfra",
++ "provider": "deepinfra",
++ "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
++ "token_class": "token-class",
++ "from_nano_usd_per_m": "70000000",
++ "to_nano_usd_per_m": "90000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.deepinfra.com/models/list",
++ "fetched_at": "2026-11-03T09:15:00.000Z",
++ "approval_required": true
++}
ddiff --git a/fixtures/watch.rate.changed/invalid/money-float.json b/fixtures/watch.rate.changed/invalid/money-float.json
nnew file mode 100644
iindex 00000000..0e3204a3
---- /dev/null
++++ b/fixtures/watch.rate.changed/invalid/money-float.json
@@@ -0,0 +1,15 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "source_key": "deepinfra",
++ "provider": "deepinfra",
++ "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
++ "token_class": "input",
++ "from_nano_usd_per_m": "70000000",
++ "to_nano_usd_per_m": "0.09",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.deepinfra.com/models/list",
++ "fetched_at": "2026-11-03T09:15:00.000Z",
++ "approval_required": true
++}
ddiff --git a/fixtures/watch.rate.changed/invalid/money-number.json b/fixtures/watch.rate.changed/invalid/money-number.json
nnew file mode 100644
iindex 00000000..c13a96f3
---- /dev/null
++++ b/fixtures/watch.rate.changed/invalid/money-number.json
@@@ -0,0 +1,15 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "source_key": "deepinfra",
++ "provider": "deepinfra",
++ "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
++ "token_class": "input",
++ "from_nano_usd_per_m": "70000000",
++ "to_nano_usd_per_m": 90000000,
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.deepinfra.com/models/list",
++ "fetched_at": "2026-11-03T09:15:00.000Z",
++ "approval_required": true
++}
ddiff --git a/fixtures/watch.rate.changed/valid/deepinfra-input.json b/fixtures/watch.rate.changed/valid/deepinfra-input.json
nnew file mode 100644
iindex 00000000..f2170c9c
---- /dev/null
++++ b/fixtures/watch.rate.changed/valid/deepinfra-input.json
@@@ -0,0 +1,15 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "source_key": "deepinfra",
++ "provider": "deepinfra",
++ "model": "Qwen/Qwen3-Coder-30B-A3B-Instruct",
++ "token_class": "input",
++ "from_nano_usd_per_m": "70000000",
++ "to_nano_usd_per_m": "90000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.deepinfra.com/models/list",
++ "fetched_at": "2026-11-03T09:15:00.000Z",
++ "approval_required": true
++}
ddiff --git a/fixtures/watch.rate.changed/valid/first-price.json b/fixtures/watch.rate.changed/valid/first-price.json
nnew file mode 100644
iindex 00000000..68e8c812
---- /dev/null
++++ b/fixtures/watch.rate.changed/valid/first-price.json
@@@ -0,0 +1,15 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPR",
++ "source_key": "featherless",
++ "provider": "featherless",
++ "model": "Qwen/Qwen3-8B",
++ "token_class": "cached_read",
++ "from_nano_usd_per_m": null,
++ "to_nano_usd_per_m": "50000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.featherless.ai/v1/models",
++ "fetched_at": "2026-11-03T10:00:00.000Z",
++ "approval_required": true
++}
ddiff --git a/fixtures/watch.rate.rejected/invalid/missing-decided-by.json b/fixtures/watch.rate.rejected/invalid/missing-decided-by.json
nnew file mode 100644
iindex 00000000..1d410fd0
---- /dev/null
++++ b/fixtures/watch.rate.rejected/invalid/missing-decided-by.json
@@@ -0,0 +1,18 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPS",
++ "source_key": "featherless",
++ "provider": "featherless",
++ "model": "Qwen/Qwen3-8B",
++ "token_class": "output",
++ "from_nano_usd_per_m": "75000000",
++ "to_nano_usd_per_m": "80000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.featherless.ai/v1/models",
++ "fetched_at": "2026-11-03T10:00:00.000Z",
++ "approval_required": false,
++ "state": "rejected",
++ "decided_at": "2026-11-03T12:30:00.000Z",
++ "applied": false
++}
ddiff --git a/fixtures/watch.rate.rejected/invalid/wrong-state.json b/fixtures/watch.rate.rejected/invalid/wrong-state.json
nnew file mode 100644
iindex 00000000..8938bbf8
---- /dev/null
++++ b/fixtures/watch.rate.rejected/invalid/wrong-state.json
@@@ -0,0 +1,19 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPS",
++ "source_key": "featherless",
++ "provider": "featherless",
++ "model": "Qwen/Qwen3-8B",
++ "token_class": "output",
++ "from_nano_usd_per_m": "75000000",
++ "to_nano_usd_per_m": "80000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.featherless.ai/v1/models",
++ "fetched_at": "2026-11-03T10:00:00.000Z",
++ "approval_required": false,
++ "state": "approved",
++ "decided_by": "usr_01JAB2C3D4E5F6G7H8J9K0MNPT",
++ "decided_at": "2026-11-03T12:30:00.000Z",
++ "applied": false
++}
ddiff --git a/fixtures/watch.rate.rejected/valid/featherless-output.json b/fixtures/watch.rate.rejected/valid/featherless-output.json
nnew file mode 100644
iindex 00000000..c0ea7d9c
---- /dev/null
++++ b/fixtures/watch.rate.rejected/valid/featherless-output.json
@@@ -0,0 +1,19 @@
++{
++ "change_id": "prc_01JAB2C3D4E5F6G7H8J9K0MNPS",
++ "source_key": "featherless",
++ "provider": "featherless",
++ "model": "Qwen/Qwen3-8B",
++ "token_class": "output",
++ "from_nano_usd_per_m": "75000000",
++ "to_nano_usd_per_m": "80000000",
++ "currency": "USD",
++ "region": "global",
++ "effective_date": "2026-11-03",
++ "source_url": "https://api.featherless.ai/v1/models",
++ "fetched_at": "2026-11-03T10:00:00.000Z",
++ "approval_required": false,
++ "state": "rejected",
++ "decided_by": "usr_01JAB2C3D4E5F6G7H8J9K0MNPT",
++ "decided_at": "2026-11-03T12:30:00.000Z",
++ "applied": false
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex fee08c84..81f4fe56 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -52286,6 +52286,331 @@
}
}
},
++ "watch.rate.changed": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.rate.changed.v1.json",
++ "title": "WatchRateChangedPayload",
++ "description": "watch.rate.changed v1 (OpenVibe.Watch server/provider-rates.js changeEvent(); plan P6, flag WATCH_PROVIDER_RATES off by default): a provider's published price document stated a different value for one model and token class than Watch last observed. It is EVIDENCE, not a rate card: Watch writes no billable price, and a person (never a service or an agent) must approve or reject the change; the decision is dated evidence for OpenVibe.AI's catalog operator. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "change_id",
++ "source_key",
++ "provider",
++ "model",
++ "token_class",
++ "from_nano_usd_per_m",
++ "to_nano_usd_per_m",
++ "currency",
++ "region",
++ "effective_date",
++ "source_url",
++ "fetched_at",
++ "approval_required"
++ ],
++ "properties": {
++ "change_id": {
++ "type": "string",
++ "pattern": "^prc_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "source_key": {
++ "type": "string",
++ "description": "The source Watch fetched: the provider's key in its registry (deepinfra, featherless)."
++ },
++ "provider": {
++ "type": "string",
++ "description": "The provider whose document stated the rate (deepinfra, featherless)."
++ },
++ "model": {
++ "type": "string",
++ "description": "The model id exactly as the provider's document stated it."
++ },
++ "token_class": {
++ "type": "string",
++ "enum": [
++ "input",
++ "cached_read",
++ "cache_write",
++ "output"
++ ],
++ "description": "The D1 token classes."
++ },
++ "from_nano_usd_per_m": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^[0-9]{1,19}$",
++ "description": "The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price."
++ },
++ "to_nano_usd_per_m": {
++ "type": "string",
++ "pattern": "^[0-9]{1,19}$",
++ "description": "The value the document states now, as an integer nano-USD per million tokens string."
++ },
++ "currency": {
++ "type": "string",
++ "description": "The document's currency; USD for both sources today."
++ },
++ "region": {
++ "type": "string",
++ "description": "The document's scope; global for both sources today."
++ },
++ "effective_date": {
++ "type": "string",
++ "format": "date",
++ "description": "The first day this value was observed (YYYY-MM-DD); an unchanged value keeps its first date."
++ },
++ "source_url": {
++ "type": "string",
++ "format": "uri",
++ "description": "The official document fetched; never a private or authenticated URL."
++ },
++ "fetched_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "approval_required": {
++ "type": "boolean",
++ "description": "true for a change: it waits for a person's decision."
++ }
++ }
++ }
++ },
++ "watch.rate.approved": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.rate.approved.v1.json",
++ "title": "WatchRateApprovedPayload",
++ "description": "watch.rate.approved v1 (OpenVibe.Watch server/provider-rates.js decide(); plan P6, flag WATCH_PROVIDER_RATES off by default): a person approved a pending provider-rate change. The payload is the change (watch.rate.changed@1) plus the decision. It is EVIDENCE, not a billable rate: Watch writes no rate card, applied is always false, and OpenVibe.AI's catalog operator alone changes the supply rate card through AI's own path. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch; actor is the service, and decided_by names the person.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "change_id",
++ "source_key",
++ "provider",
++ "model",
++ "token_class",
++ "from_nano_usd_per_m",
++ "to_nano_usd_per_m",
++ "currency",
++ "region",
++ "effective_date",
++ "source_url",
++ "fetched_at",
++ "approval_required",
++ "state",
++ "decided_by",
++ "decided_at",
++ "applied"
++ ],
++ "properties": {
++ "change_id": {
++ "type": "string",
++ "pattern": "^prc_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "source_key": {
++ "type": "string",
++ "description": "The source Watch fetched: the provider's key in its registry (deepinfra, featherless)."
++ },
++ "provider": {
++ "type": "string",
++ "description": "The provider whose document stated the rate (deepinfra, featherless)."
++ },
++ "model": {
++ "type": "string",
++ "description": "The model id exactly as the provider's document stated it."
++ },
++ "token_class": {
++ "type": "string",
++ "enum": [
++ "input",
++ "cached_read",
++ "cache_write",
++ "output"
++ ],
++ "description": "The D1 token classes."
++ },
++ "from_nano_usd_per_m": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^[0-9]{1,19}$",
++ "description": "The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price."
++ },
++ "to_nano_usd_per_m": {
++ "type": "string",
++ "pattern": "^[0-9]{1,19}$",
++ "description": "The value the document stated, as an integer nano-USD per million tokens string."
++ },
++ "currency": {
++ "type": "string",
++ "description": "The document's currency; USD for both sources today."
++ },
++ "region": {
++ "type": "string",
++ "description": "The document's scope; global for both sources today."
++ },
++ "effective_date": {
++ "type": "string",
++ "format": "date",
++ "description": "The first day this value was observed (YYYY-MM-DD)."
++ },
++ "source_url": {
++ "type": "string",
++ "format": "uri",
++ "description": "The official document fetched."
++ },
++ "fetched_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "approval_required": {
++ "const": false,
++ "description": "false: the decision is made."
++ },
++ "state": {
++ "const": "approved"
++ },
++ "decided_by": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The person who approved it. A service or an agent may not; Watch refuses those with watch.rate_person_only."
++ },
++ "decided_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "applied": {
++ "const": false,
++ "description": "Always false: an approval is evidence and never writes a billable rate."
++ }
++ }
++ }
++ },
++ "watch.rate.rejected": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.rate.rejected.v1.json",
++ "title": "WatchRateRejectedPayload",
++ "description": "watch.rate.rejected v1 (OpenVibe.Watch server/provider-rates.js decide(); plan P6, flag WATCH_PROVIDER_RATES off by default): a person rejected a pending provider-rate change. The payload is the change (watch.rate.changed@1) plus the decision. Rejecting a change writes no rate, and applied is always false. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch; actor is the service, and decided_by names the person.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "change_id",
++ "source_key",
++ "provider",
++ "model",
++ "token_class",
++ "from_nano_usd_per_m",
++ "to_nano_usd_per_m",
++ "currency",
++ "region",
++ "effective_date",
++ "source_url",
++ "fetched_at",
++ "approval_required",
++ "state",
++ "decided_by",
++ "decided_at",
++ "applied"
++ ],
++ "properties": {
++ "change_id": {
++ "type": "string",
++ "pattern": "^prc_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "source_key": {
++ "type": "string",
++ "description": "The source Watch fetched: the provider's key in its registry (deepinfra, featherless)."
++ },
++ "provider": {
++ "type": "string",
++ "description": "The provider whose document stated the rate (deepinfra, featherless)."
++ },
++ "model": {
++ "type": "string",
++ "description": "The model id exactly as the provider's document stated it."
++ },
++ "token_class": {
++ "type": "string",
++ "enum": [
++ "input",
++ "cached_read",
++ "cache_write",
++ "output"
++ ],
++ "description": "The D1 token classes."
++ },
++ "from_nano_usd_per_m": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^[0-9]{1,19}$",
++ "description": "The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price."
++ },
++ "to_nano_usd_per_m": {
++ "type": "string",
++ "pattern": "^[0-9]{1,19}$",
++ "description": "The value the document stated, as an integer nano-USD per million tokens string."
++ },
++ "currency": {
++ "type": "string",
++ "description": "The document's currency; USD for both sources today."
++ },
++ "region": {
++ "type": "string",
++ "description": "The document's scope; global for both sources today."
++ },
++ "effective_date": {
++ "type": "string",
++ "format": "date",
++ "description": "The first day this value was observed (YYYY-MM-DD)."
++ },
++ "source_url": {
++ "type": "string",
++ "format": "uri",
++ "description": "The official document fetched."
++ },
++ "fetched_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "approval_required": {
++ "const": false,
++ "description": "false: the decision is made."
++ },
++ "state": {
++ "const": "rejected"
++ },
++ "decided_by": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The person who rejected it. A service or an agent may not; Watch refuses those with watch.rate_person_only."
++ },
++ "decided_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "applied": {
++ "const": false,
++ "description": "Always false: a decision never writes a billable rate."
++ }
++ }
++ }
++ },
"games.player.joined": {
"version": "1.0.0",
"owner": "games",
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex 081cfd89..ef3be171 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.285.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 5164768f..edd28395 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.285.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/bench.json b/generated/openapi/bench.json
iindex 4675251c..f390e9ed 100644
---- a/generated/openapi/bench.json
++++ b/generated/openapi/bench.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bench API",
-- "version": "0.285.0",
-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 93d52890..f44a6778 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.285.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 4f8b875d..da160b12 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.285.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 6c2333b5..21e86786 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.285.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 b55029bc..db615e9e 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.285.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 24778bdc..3ef7a2a8 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.285.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 84b137e6..4abd8d64 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.285.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 660aa7ff..aaa3f12b 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.285.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 64356c82..31aaafe6 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.285.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/domains.json b/generated/openapi/domains.json
iindex e5ac1cf5..19157751 100644
---- a/generated/openapi/domains.json
++++ b/generated/openapi/domains.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Domains API",
-- "version": "0.285.0",
-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 81838924..549593f6 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.285.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 8b91fce7..3e0ebdc7 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.285.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 9a818036..3b2cfa55 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.285.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 e7291a0b..98d00a9d 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.285.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/inventory.json b/generated/openapi/inventory.json
iindex 1abf09b8..0bc3fa42 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.285.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 54dc444d..99b37478 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.285.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 d0e19c08..213e515b 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.285.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 0de10681..25979519 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.285.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 ed35a41c..163f59c8 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.285.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 4104aba9..e609b6cd 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.285.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 228735c7..c7bb8625 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.285.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/play.json b/generated/openapi/play.json
iindex 81d187af..78064d36 100644
---- a/generated/openapi/play.json
++++ b/generated/openapi/play.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Play API",
-- "version": "0.285.0",
-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/quest.json b/generated/openapi/quest.json
iindex e9f9a452..16bc68bb 100644
---- a/generated/openapi/quest.json
++++ b/generated/openapi/quest.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Quest API",
-- "version": "0.285.0",
-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/report.json b/generated/openapi/report.json
iindex eb4d1356..90642cba 100644
---- a/generated/openapi/report.json
++++ b/generated/openapi/report.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Report API",
-- "version": "0.285.0",
-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 da05d92b..ecae30f5 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.285.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 d3597913..9ff598ca 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.285.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 e15d8e75..5bd93f00 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.285.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 1d14784b..ebb9fe82 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.285.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 0d942c7d..4d0795f5 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.285.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 114f4d41..11ee367c 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.285.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 150a7d32..75f36ee8 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.285.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/today.json b/generated/openapi/today.json
iindex 44f57e1d..dd035752 100644
---- a/generated/openapi/today.json
++++ b/generated/openapi/today.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Today API",
-- "version": "0.285.0",
-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 0da9f48d..76e7a61a 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.285.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 3847f0a2..ef4c8263 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.285.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 dfaf56a7..5eb4fd71 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.285.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/vision.json b/generated/openapi/vision.json
iindex 2f713f87..14b49bc2 100644
---- a/generated/openapi/vision.json
++++ b/generated/openapi/vision.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Vision API",
-- "version": "0.285.0",
-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 475e3aa3..8c46f14f 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.285.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 227e1030..0b2270c2 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.285.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.286.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 7e19d312..fabb0462 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.285.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/zone.json b/generated/openapi/zone.json
iindex 84562b21..b60f2faf 100644
---- a/generated/openapi/zone.json
++++ b/generated/openapi/zone.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Zone API",
-- "version": "0.285.0",
-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.285.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.286.0",
++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.286.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/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex 41e1cb6d..d2fcea3b 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -196160,6 +196160,185 @@ export interface WatchCheckFailedPayload {
consecutive_failures: number;
}
++/** [email protected] (owner: watch) */
++/**
++ * watch.rate.changed v1 (OpenVibe.Watch server/provider-rates.js changeEvent(); plan P6, flag WATCH_PROVIDER_RATES off by default): a provider's published price document stated a different value for one model and token class than Watch last observed. It is EVIDENCE, not a rate card: Watch writes no billable price, and a person (never a service or an agent) must approve or reject the change; the decision is dated evidence for OpenVibe.AI's catalog operator. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch.
++ */
++export interface WatchRateChangedPayload {
++ change_id: string;
++ /**
++ * The source Watch fetched: the provider's key in its registry (deepinfra, featherless).
++ */
++ source_key: string;
++ /**
++ * The provider whose document stated the rate (deepinfra, featherless).
++ */
++ provider: string;
++ /**
++ * The model id exactly as the provider's document stated it.
++ */
++ model: string;
++ /**
++ * The D1 token classes.
++ */
++ token_class: "input" | "cached_read" | "cache_write" | "output";
++ /**
++ * The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price.
++ */
++ from_nano_usd_per_m: string | null;
++ /**
++ * The value the document states now, as an integer nano-USD per million tokens string.
++ */
++ to_nano_usd_per_m: string;
++ /**
++ * The document's currency; USD for both sources today.
++ */
++ currency: string;
++ /**
++ * The document's scope; global for both sources today.
++ */
++ region: string;
++ /**
++ * The first day this value was observed (YYYY-MM-DD); an unchanged value keeps its first date.
++ */
++ effective_date: string;
++ /**
++ * The official document fetched; never a private or authenticated URL.
++ */
++ source_url: string;
++ fetched_at: string;
++ /**
++ * true for a change: it waits for a person's decision.
++ */
++ approval_required: boolean;
++}
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.rate.approved v1 (OpenVibe.Watch server/provider-rates.js decide(); plan P6, flag WATCH_PROVIDER_RATES off by default): a person approved a pending provider-rate change. The payload is the change (watch.rate.changed@1) plus the decision. It is EVIDENCE, not a billable rate: Watch writes no rate card, applied is always false, and OpenVibe.AI's catalog operator alone changes the supply rate card through AI's own path. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch; actor is the service, and decided_by names the person.
++ */
++export interface WatchRateApprovedPayload {
++ change_id: string;
++ /**
++ * The source Watch fetched: the provider's key in its registry (deepinfra, featherless).
++ */
++ source_key: string;
++ /**
++ * The provider whose document stated the rate (deepinfra, featherless).
++ */
++ provider: string;
++ /**
++ * The model id exactly as the provider's document stated it.
++ */
++ model: string;
++ /**
++ * The D1 token classes.
++ */
++ token_class: "input" | "cached_read" | "cache_write" | "output";
++ /**
++ * The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price.
++ */
++ from_nano_usd_per_m: string | null;
++ /**
++ * The value the document stated, as an integer nano-USD per million tokens string.
++ */
++ to_nano_usd_per_m: string;
++ /**
++ * The document's currency; USD for both sources today.
++ */
++ currency: string;
++ /**
++ * The document's scope; global for both sources today.
++ */
++ region: string;
++ /**
++ * The first day this value was observed (YYYY-MM-DD).
++ */
++ effective_date: string;
++ /**
++ * The official document fetched.
++ */
++ source_url: string;
++ fetched_at: string;
++ /**
++ * false: the decision is made.
++ */
++ approval_required: false;
++ state: "approved";
++ /**
++ * The person who approved it. A service or an agent may not; Watch refuses those with watch.rate_person_only.
++ */
++ decided_by: string;
++ decided_at: string;
++ /**
++ * Always false: an approval is evidence and never writes a billable rate.
++ */
++ applied: false;
++}
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.rate.rejected v1 (OpenVibe.Watch server/provider-rates.js decide(); plan P6, flag WATCH_PROVIDER_RATES off by default): a person rejected a pending provider-rate change. The payload is the change (watch.rate.changed@1) plus the decision. Rejecting a change writes no rate, and applied is always false. Money is integer nano-USD per million tokens as a decimal string (D1: never a float). Envelope: subject { type: provider-rate, id: <source_key> }, visibility internal, priority important, source and actor service:watch; actor is the service, and decided_by names the person.
++ */
++export interface WatchRateRejectedPayload {
++ change_id: string;
++ /**
++ * The source Watch fetched: the provider's key in its registry (deepinfra, featherless).
++ */
++ source_key: string;
++ /**
++ * The provider whose document stated the rate (deepinfra, featherless).
++ */
++ provider: string;
++ /**
++ * The model id exactly as the provider's document stated it.
++ */
++ model: string;
++ /**
++ * The D1 token classes.
++ */
++ token_class: "input" | "cached_read" | "cache_write" | "output";
++ /**
++ * The value Watch last observed, as an integer nano-USD per million tokens string; null for a first price.
++ */
++ from_nano_usd_per_m: string | null;
++ /**
++ * The value the document stated, as an integer nano-USD per million tokens string.
++ */
++ to_nano_usd_per_m: string;
++ /**
++ * The document's currency; USD for both sources today.
++ */
++ currency: string;
++ /**
++ * The document's scope; global for both sources today.
++ */
++ region: string;
++ /**
++ * The first day this value was observed (YYYY-MM-DD).
++ */
++ effective_date: string;
++ /**
++ * The official document fetched.
++ */
++ source_url: string;
++ fetched_at: string;
++ /**
++ * false: the decision is made.
++ */
++ approval_required: false;
++ state: "rejected";
++ /**
++ * The person who rejected it. A service or an agent may not; Watch refuses those with watch.rate_person_only.
++ */
++ decided_by: string;
++ decided_at: string;
++ /**
++ * Always false: a decision never writes a billable rate.
++ */
++ applied: false;
++}
++
/** [email protected] (owner: games) */
/**
* games.player.joined v1 (OpenVibe.Games apps/server/src/platform/gameEvents.ts playerJoinedEvent, via GameEventRecorder.recordJoin from game/gameServer.ts handleHello). A character entered the world: written to Games' event_outbox in a transaction of its own once the session exists and the welcome was sent (a new character's row is first written by its next save). restored is true when the character already existed in the database, false for a new one. Only emitted while Events publishing is configured. No position, appearance, inventory, rank or connection data. Envelope: subject { type: player, id: <player.id> }, visibility subject when the player has a Network subject and internal otherwise, priority low, actor user:<usr_...> or guest:<gst_...> from player.subject, else service:games. No consumer yet.
ddiff --git a/manifests/services/watch.json b/manifests/services/watch.json
iindex 5417dfc0..0fe24834 100644
---- a/manifests/services/watch.json
++++ b/manifests/services/watch.json
@@@ -30,7 +30,10 @@
"watch.watch.removed",
"watch.observation.recorded",
"watch.watch.triggered",
-- "watch.check.failed"
++ "watch.check.failed",
++ "watch.rate.changed",
++ "watch.rate.approved",
++ "watch.rate.rejected"
],
"eventsConsumed": [
"network.account.export_requested",
ddiff --git a/package-lock.json b/package-lock.json
iindex 74df9218..a11d3a01 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-contracts",
-- "version": "0.285.0",
++ "version": "0.286.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.285.0",
++ "version": "0.286.0",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex fe6027c3..7e9e2e90 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.285.0",
++ "version": "0.286.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",