openvibers/openvibe.contracts Commits

Say usage rollups are counts and readings are Billing's only money input (#30)

OP OpenVibers committed 4 Oct 2026 · 9cf64d3a5e · 39 files, +122 −78

local checks ✓ 3/3 · CI ✓ 3/3 · review SHIP by Claude opus (QUALITY=high) · 1 fix round

https://github.com/OpenVibers/OpenVibe.Contracts/pull/30

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 75318cd4..628f1e29 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,14 @@ 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.93.1 — 2026-10-04
++
++**Usage rollups are counts, readings are money** (plan T5 step 8, C1; ADR-031 Counting). Description-only: no schema shape
++change. `common.usage-recorded@1` says rollups are counts for dashboards and quotas and Billing never consumes a
++`*.usage.recorded` topic; `platform.usage-sample@1` says `idempotency_key` is the only dedupe key and encodes work identity
++only, and `service` is the producing service's manifest id; `billing.usage.record` is the only money input to Billing. New
++test `test/usage-topics.test.js`: only network, codes and zone may list a `*.usage.recorded` topic as consumed.
++
## 0.93.0 — 2026-10-04
**OpenVibe.Bot's profiles, device protocol, operator commands, pairing and events** (plan T15 R7; ADR-043). The Bot
ddiff --git a/contracts/common/usage-recorded.v1.json b/contracts/common/usage-recorded.v1.json
iindex a577d950..11442b21 100644
---- a/contracts/common/usage-recorded.v1.json
++++ b/contracts/common/usage-recorded.v1.json
@@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/common/usage-recorded.v1.json",
"title": "UsageRecorded",
-- "description": "common.usage-recorded@1 (roadmap WS-N task 4, ADR-014): one rollup of a developer project's use of one capability in one environment over one closed window (an hour or a day), as the service that owns the capability counted it. The payload of every <service>.usage.recorded event; OpenVibe.Network adds them up per project and day for the project's dashboard on OpenVibe.Codes. The producer counts in the transaction that does its own accounting (a job's end, a stored event, a delivery attempt) and writes the rollup to its outbox after the window has closed: never one event per request. Totals, not deltas: a later event with the same key (source, project_id, env, capability, resource, dimension, unit, window_start) replaces the earlier one, and a lower revision never replaces a higher one. Envelope: subject { type: project, id: <project_id> }, visibility internal, priority low, actor the producing service. Never carries a subject id, an address, a session, a request's input or content, or a file name.",
++ "description": "common.usage-recorded@1 (roadmap WS-N task 4, ADR-014): one rollup of a developer project's use of one capability in one environment over one closed window (an hour or a day), as the service that owns the capability counted it. The payload of every <service>.usage.recorded event; OpenVibe.Network adds them up per project and day for the project's dashboard on OpenVibe.Codes. The producer counts in the transaction that does its own accounting (a job's end, a stored event, a delivery attempt) and writes the rollup to its outbox after the window has closed: never one event per request. Totals, not deltas: a later event with the same key (source, project_id, env, capability, resource, dimension, unit, window_start) replaces the earlier one, and a lower revision never replaces a higher one. Envelope: subject { type: project, id: <project_id> }, visibility internal, priority low, actor the producing service. Never carries a subject id, an address, a session, a request's input or content, or a file name. Rollups are counts for dashboards and quotas, never money: Billing never consumes any *.usage.recorded topic, and a service that bills posts platform.usage-sample readings (billing.usage.record).",
"type": "object",
"required": ["project_id", "env", "capability", "unit", "window", "window_start", "window_end", "quantity", "errors"],
"additionalProperties": false,
@@@ -28,7 +28,7 @@
"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)_" },
-- "description": "Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so Billing can rate billable usage by resource: ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job."
++ "description": "Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so a dashboard or quota can group a count by resource (rollups are counts, never money; Billing never consumes them and rates only platform.usage-sample readings): ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job."
},
"unit": {
"type": "string",
ddiff --git a/contracts/platform/usage-sample.v1.json b/contracts/platform/usage-sample.v1.json
iindex d3d8fe0f..eaf1c2cc 100644
---- a/contracts/platform/usage-sample.v1.json
++++ b/contracts/platform/usage-sample.v1.json
@@@ -22,10 +22,11 @@
},
"idempotency_key": {
"type": "string",
-- "description": "Stable across retries"
++ "description": "Stable across retries. The only dedupe key, and it encodes work identity only (examples: tools:job:<id>, ai:<run>:tokens, run:<job>:<n>), never route_epoch, node, region or trace_id."
},
"service": {
-- "type": "string"
++ "type": "string",
++ "description": "The Contracts manifest id of the producing service (tools, ai, run)."
},
"project": {
"type": "string",
ddiff --git a/contracts/zone/object-zone-usage.v1.json b/contracts/zone/object-zone-usage.v1.json
iindex 275a8625..ea8c6401 100644
---- a/contracts/zone/object-zone-usage.v1.json
++++ b/contracts/zone/object-zone-usage.v1.json
@@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/zone/object-zone-usage.v1.json",
"title": "ObjectZoneUsage",
-- "description": "zone.object-zone-usage@1 (PLANNED; ADR-031 amendment 2026-10-02): the answer of GET /api/v1/zones/{zone_id}/usage on OpenVibe.Zone (capability zone.usage.read). Zone never counts. current is the live-object snapshot that Media's internal zone endpoint returns. series sums Media's hourly media.usage.recorded rollups (common.usage-recorded@1) whose dimension is this zone id in lowercase, over the closed hours of the current UTC month. Billing rates the same rollups. Zone's control operations are not metered. ovrn is the OVRN of zone_id, never of another zone (contracts.zones.checkObjectZoneUsage). More fields may be added.",
++ "description": "zone.object-zone-usage@1 (PLANNED; ADR-031 amendment 2026-10-02): the answer of GET /api/v1/zones/{zone_id}/usage on OpenVibe.Zone (capability zone.usage.read). Zone never counts. current is the live-object snapshot that Media's internal zone endpoint returns. series sums Media's hourly media.usage.recorded rollups (common.usage-recorded@1) whose dimension is this zone id in lowercase, over the closed hours of the current UTC month. Rollups are counts; Billing rates only platform.usage-sample readings (billing.usage.record). Zone's control operations are not metered. ovrn is the OVRN of zone_id, never of another zone (contracts.zones.checkObjectZoneUsage). More fields may be added.",
"type": "object",
"additionalProperties": false,
"required": [
ddiff --git a/docs/adr/ADR-031-s3-compatible-surface.md b/docs/adr/ADR-031-s3-compatible-surface.md
iindex 2ec9b75f..7a0669e2 100644
---- a/docs/adr/ADR-031-s3-compatible-surface.md
++++ b/docs/adr/ADR-031-s3-compatible-surface.md
@@@ -171,7 +171,7 @@ Zone provisions each change in Media **synchronously**:
- Only live objects count. An object counts as soon as it completes and stops counting at its tombstone, even before its copies are erased.
- **Zone count:** the project's `zones` quota is enforced by Zone.
- **Counting:** **Media is the only counter.** Per zone and per closed hour it emits `media.usage.recorded` (`common.usage-recorded@1`, planned for Media). Every rollup names the zone twice:
-- - `resource` is the zone's resource name, `ovrn:zone:<project_id>:object-zone/<zone_id>`, as ADR-034 section 9 requires of billable usage. Billing rates by it and the console links it.
++ - `resource` is the zone's resource name, `ovrn:zone:<project_id>:object-zone/<zone_id>`, as ADR-034 section 2 names resources. The console links it. Rollups are counts; Billing rates readings only; Media posts readings for what it bills.
- `dimension` is the zone id in lowercase (`zon_01k…`), for consumers that only group by dimension.
- Rollups for the default zone carry the default zone's resource name too. A rollup without `resource` is never Media's.
- The series are:
ddiff --git a/docs/adr/ADR-034-platform-north-star.md b/docs/adr/ADR-034-platform-north-star.md
iindex 9ad2ecf8..4ac4d63e 100644
---- a/docs/adr/ADR-034-platform-north-star.md
++++ b/docs/adr/ADR-034-platform-north-star.md
@@@ -97,12 +97,15 @@ Mods, bots, functions and integrations are all **extensions**. One `extension-ma
### 9. Metering is a primitive, and affordable is a design target
--- Every billable action emits `common.usage-recorded` with the resource name, project and quantity. Billing rates it against a public price list.
++- Every billable action posts a `platform.usage-sample@1` reading (`billing.usage.record`) with the resource name, project and quantity. Billing rates the readings against a public price list.
++- `common.usage-recorded` rollups are counts for dashboards and quotas. Billing never consumes them.
- Budgets and alerts are per project, as AI quotas already work.
- Prices are cost plus a stated margin: storage from B2, egress from R2, compute seconds.
- Free tiers fit on cheap hardware.
- Internal traffic between a project's own resources is never charged.
++Amended 2026-10-04: Billing rates `platform.usage-sample@1` readings only. Earlier this section said Billing rated `common.usage-recorded` rollups.
++
### 10. Efficiency is measured, not assumed
- Cost per request, per GB and per run is a metric beside latency.
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex 303d669b..7714d278 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -3002,7 +3002,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/common/usage-recorded.v1.json",
"title": "UsageRecorded",
-- "description": "common.usage-recorded@1 (roadmap WS-N task 4, ADR-014): one rollup of a developer project's use of one capability in one environment over one closed window (an hour or a day), as the service that owns the capability counted it. The payload of every <service>.usage.recorded event; OpenVibe.Network adds them up per project and day for the project's dashboard on OpenVibe.Codes. The producer counts in the transaction that does its own accounting (a job's end, a stored event, a delivery attempt) and writes the rollup to its outbox after the window has closed: never one event per request. Totals, not deltas: a later event with the same key (source, project_id, env, capability, resource, dimension, unit, window_start) replaces the earlier one, and a lower revision never replaces a higher one. Envelope: subject { type: project, id: <project_id> }, visibility internal, priority low, actor the producing service. Never carries a subject id, an address, a session, a request's input or content, or a file name.",
++ "description": "common.usage-recorded@1 (roadmap WS-N task 4, ADR-014): one rollup of a developer project's use of one capability in one environment over one closed window (an hour or a day), as the service that owns the capability counted it. The payload of every <service>.usage.recorded event; OpenVibe.Network adds them up per project and day for the project's dashboard on OpenVibe.Codes. The producer counts in the transaction that does its own accounting (a job's end, a stored event, a delivery attempt) and writes the rollup to its outbox after the window has closed: never one event per request. Totals, not deltas: a later event with the same key (source, project_id, env, capability, resource, dimension, unit, window_start) replaces the earlier one, and a lower revision never replaces a higher one. Envelope: subject { type: project, id: <project_id> }, visibility internal, priority low, actor the producing service. Never carries a subject id, an address, a session, a request's input or content, or a file name. Rollups are counts for dashboards and quotas, never money: Billing never consumes any *.usage.recorded topic, and a service that bills posts platform.usage-sample readings (billing.usage.record).",
"type": "object",
"required": [
"project_id",
@@@ -3052,7 +3052,7 @@
"not": {
"pattern": "/(usr|gst|app|mod|svc|job|evt|req)_"
},
-- "description": "Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so Billing can rate billable usage by resource: ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job."
++ "description": "Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so a dashboard or quota can group a count by resource (rollups are counts, never money; Billing never consumes them and rates only platform.usage-sample readings): ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job."
},
"unit": {
"type": "string",
@@@ -61740,10 +61740,11 @@
},
"idempotency_key": {
"type": "string",
-- "description": "Stable across retries"
++ "description": "Stable across retries. The only dedupe key, and it encodes work identity only (examples: tools:job:<id>, ai:<run>:tokens, run:<job>:<n>), never route_epoch, node, region or trace_id."
},
"service": {
-- "type": "string"
++ "type": "string",
++ "description": "The Contracts manifest id of the producing service (tools, ai, run)."
},
"project": {
"type": "string",
@@@ -64801,7 +64802,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://openvibe.network/contracts/zone/object-zone-usage.v1.json",
"title": "ObjectZoneUsage",
-- "description": "zone.object-zone-usage@1 (PLANNED; ADR-031 amendment 2026-10-02): the answer of GET /api/v1/zones/{zone_id}/usage on OpenVibe.Zone (capability zone.usage.read). Zone never counts. current is the live-object snapshot that Media's internal zone endpoint returns. series sums Media's hourly media.usage.recorded rollups (common.usage-recorded@1) whose dimension is this zone id in lowercase, over the closed hours of the current UTC month. Billing rates the same rollups. Zone's control operations are not metered. ovrn is the OVRN of zone_id, never of another zone (contracts.zones.checkObjectZoneUsage). More fields may be added.",
++ "description": "zone.object-zone-usage@1 (PLANNED; ADR-031 amendment 2026-10-02): the answer of GET /api/v1/zones/{zone_id}/usage on OpenVibe.Zone (capability zone.usage.read). Zone never counts. current is the live-object snapshot that Media's internal zone endpoint returns. series sums Media's hourly media.usage.recorded rollups (common.usage-recorded@1) whose dimension is this zone id in lowercase, over the closed hours of the current UTC month. Rollups are counts; Billing rates only platform.usage-sample readings (billing.usage.record). Zone's control operations are not metered. ovrn is the OVRN of zone_id, never of another zone (contracts.zones.checkObjectZoneUsage). More fields may be added.",
"type": "object",
"additionalProperties": false,
"required": [
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex f757d677..6e8a6408 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.93.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 eeb54197..1519b101 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.93.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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"
@@@ -1673,8 +1673,8 @@
},
"post": {
"operationId": "post_api_v1_usage",
-- "summary": "Record a platform.usage-sample@1 reading without moving money.",
-- "description": "**billing.usage.record** (internal): Record a platform.usage-sample@1 reading without moving money. The reading's idempotency_key deduplicates retries. Listing all readings requires billing.ledger.admin.",
++ "summary": "The only money input to Billing: record a platform.usage-sample@1 reading without moving money.",
++ "description": "**billing.usage.record** (internal): The only money input to Billing: record a platform.usage-sample@1 reading without moving money. The reading's idempotency_key deduplicates retries. Listing all readings requires billing.ledger.admin.",
"tags": [
"billing.usage"
],
@@@ -3638,10 +3638,11 @@
},
"idempotency_key": {
"type": "string",
-- "description": "Stable across retries"
++ "description": "Stable across retries. The only dedupe key, and it encodes work identity only (examples: tools:job:<id>, ai:<run>:tokens, run:<job>:<n>), never route_epoch, node, region or trace_id."
},
"service": {
-- "type": "string"
++ "type": "string",
++ "description": "The Contracts manifest id of the producing service (tools, ai, run)."
},
"project": {
"type": "string",
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex dd7f7dbb..81977c49 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.93.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 3a2cec4c..7114698e 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.93.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 0dea2735..768117ea 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.93.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 c93185e4..4d00a509 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.93.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 df303120..d7724d1c 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.93.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 fd247878..c1a3fe41 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.93.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 c8b5f0bf..e3700c52 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.93.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 4c265ae1..f7f6ffcf 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.93.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 07abe2dc..59d0c9e9 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.93.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 7ad19140..637d7919 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.93.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 068c1d3b..97e175f5 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.93.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 94885855..66a67206 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.93.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 3c093154..4470c291 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.93.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 9f6c84c9..3038b7e7 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.93.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 efc0aeb0..1aae782d 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRe.Stream API",
-- "version": "0.93.0",
-- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 aab3b314..744492c8 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.93.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 309cc4c3..e9830a4c 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.93.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 fc86220b..e95cb4d3 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.93.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 e9f52ca6..e894097b 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.93.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 ce603726..51892e2b 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.93.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 c115e6f9..56974d45 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.93.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 83ed38eb..b31770a7 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.93.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 8b7ec493..9583fb84 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.93.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 4b317e20..67d80354 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.93.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.93.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.93.1",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.93.1): 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 7c42594c..eb0947ac 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -4703,7 +4703,7 @@ export interface ModerationAction {
/** [email protected] (owner: network) */
/**
-- * common.usage-recorded@1 (roadmap WS-N task 4, ADR-014): one rollup of a developer project's use of one capability in one environment over one closed window (an hour or a day), as the service that owns the capability counted it. The payload of every <service>.usage.recorded event; OpenVibe.Network adds them up per project and day for the project's dashboard on OpenVibe.Codes. The producer counts in the transaction that does its own accounting (a job's end, a stored event, a delivery attempt) and writes the rollup to its outbox after the window has closed: never one event per request. Totals, not deltas: a later event with the same key (source, project_id, env, capability, resource, dimension, unit, window_start) replaces the earlier one, and a lower revision never replaces a higher one. Envelope: subject { type: project, id: <project_id> }, visibility internal, priority low, actor the producing service. Never carries a subject id, an address, a session, a request's input or content, or a file name.
++ * common.usage-recorded@1 (roadmap WS-N task 4, ADR-014): one rollup of a developer project's use of one capability in one environment over one closed window (an hour or a day), as the service that owns the capability counted it. The payload of every <service>.usage.recorded event; OpenVibe.Network adds them up per project and day for the project's dashboard on OpenVibe.Codes. The producer counts in the transaction that does its own accounting (a job's end, a stored event, a delivery attempt) and writes the rollup to its outbox after the window has closed: never one event per request. Totals, not deltas: a later event with the same key (source, project_id, env, capability, resource, dimension, unit, window_start) replaces the earlier one, and a lower revision never replaces a higher one. Envelope: subject { type: project, id: <project_id> }, visibility internal, priority low, actor the producing service. Never carries a subject id, an address, a session, a request's input or content, or a file name. Rollups are counts for dashboards and quotas, never money: Billing never consumes any *.usage.recorded topic, and a service that bills posts platform.usage-sample readings (billing.usage.record).
*/
export interface UsageRecorded {
/**
@@@ -4723,7 +4723,7 @@ export interface UsageRecorded {
*/
dimension?: string;
/**
-- * Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so Billing can rate billable usage by resource: ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job.
++ * Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so a dashboard or quota can group a count by resource (rollups are counts, never money; Billing never consumes them and rates only platform.usage-sample readings): ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job.
*/
resource?: string;
/**
@@@ -29757,7 +29757,7 @@ export interface ToolsUsageRecordedPayload {
*/
dimension?: string;
/**
-- * Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so Billing can rate billable usage by resource: ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job.
++ * Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so a dashboard or quota can group a count by resource (rollups are counts, never money; Billing never consumes them and rates only platform.usage-sample readings): ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job.
*/
resource?: string;
/**
@@@ -30725,7 +30725,7 @@ export interface EventsUsageRecordedPayload {
*/
dimension?: string;
/**
-- * Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so Billing can rate billable usage by resource: ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job.
++ * Optional resource name (ADR-034 section 2) of the project resource the usage counts against, so a dashboard or quota can group a count by resource (rollups are counts, never money; Billing never consumes them and rates only platform.usage-sample readings): ovrn:zone:<project_id>:object-zone/<zon_id> on Media's per-zone rollups (ADR-031 amendment 2026-10-02). Its project is project_id: a resource of another project is refused (contracts.usage.checkUsageRecorded). Added in 1.1.0. Never the resource name of a person, an app, a request or a job.
*/
resource?: string;
/**
@@@ -51666,9 +51666,12 @@ export interface CapacitySnapshot {
export interface UsageSample {
id: string;
/**
-- * Stable across retries
++ * Stable across retries. The only dedupe key, and it encodes work identity only (examples: tools:job:<id>, ai:<run>:tokens, run:<job>:<n>), never route_epoch, node, region or trace_id.
*/
idempotency_key: string;
++ /**
++ * The Contracts manifest id of the producing service (tools, ai, run).
++ */
service: string;
project?: string;
subject?: string;
@@@ -52566,7 +52569,7 @@ export interface ObjectZoneDeleteQuery {
/** [email protected] (owner: zone) */
/**
-- * zone.object-zone-usage@1 (PLANNED; ADR-031 amendment 2026-10-02): the answer of GET /api/v1/zones/{zone_id}/usage on OpenVibe.Zone (capability zone.usage.read). Zone never counts. current is the live-object snapshot that Media's internal zone endpoint returns. series sums Media's hourly media.usage.recorded rollups (common.usage-recorded@1) whose dimension is this zone id in lowercase, over the closed hours of the current UTC month. Billing rates the same rollups. Zone's control operations are not metered. ovrn is the OVRN of zone_id, never of another zone (contracts.zones.checkObjectZoneUsage). More fields may be added.
++ * zone.object-zone-usage@1 (PLANNED; ADR-031 amendment 2026-10-02): the answer of GET /api/v1/zones/{zone_id}/usage on OpenVibe.Zone (capability zone.usage.read). Zone never counts. current is the live-object snapshot that Media's internal zone endpoint returns. series sums Media's hourly media.usage.recorded rollups (common.usage-recorded@1) whose dimension is this zone id in lowercase, over the closed hours of the current UTC month. Rollups are counts; Billing rates only platform.usage-sample readings (billing.usage.record). Zone's control operations are not metered. ovrn is the OVRN of zone_id, never of another zone (contracts.zones.checkObjectZoneUsage). More fields may be added.
*/
export interface ObjectZoneUsage {
zone_id: string;
ddiff --git a/manifests/capabilities/billing.usage.record.json b/manifests/capabilities/billing.usage.record.json
iindex ac8dcc6d..2b4cff2c 100644
---- a/manifests/capabilities/billing.usage.record.json
++++ b/manifests/capabilities/billing.usage.record.json
@@@ -4,7 +4,7 @@
"owner": "billing",
"status": "active",
"visibility": "internal",
-- "description": "Record a platform.usage-sample@1 reading without moving money. The reading's idempotency_key deduplicates retries. Listing all readings requires billing.ledger.admin.",
++ "description": "The only money input to Billing: record a platform.usage-sample@1 reading without moving money. The reading's idempotency_key deduplicates retries. Listing all readings requires billing.ledger.admin.",
"permissions": [
"billing:usage"
],
ddiff --git a/package-lock.json b/package-lock.json
iindex 9149e510..963fcaf3 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-contracts",
-- "version": "0.93.0",
++ "version": "0.93.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.93.0",
++ "version": "0.93.1",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 1719ff8e..1b9f28fa 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.93.0",
++ "version": "0.93.1",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"types": "generated/typescript/index.d.ts",
ddiff --git a/test/run.js b/test/run.js
iindex 1b6bce43..d40d38e8 100644
---- a/test/run.js
++++ b/test/run.js
@@@ -905,6 +905,8 @@ sub(path.join(__dirname, 'bot-manifest.test.js'));
sub(path.join(__dirname, 'product-catalog.test.js'));
// Named object zones: identity, retired names, list limits and per-zone usage (ADR-031 amendment 2026-10-02).
sub(path.join(__dirname, 'zones.test.js'));
++// *.usage.recorded rollups are counts: only network, codes and zone may consume one, never billing (T5 step 8).
++sub(path.join(__dirname, 'usage-topics.test.js'));
// ── Generated output and compatibility gate ──────────────────────────────
sub(path.join(__dirname, 'platform-fabric.test.js'));
ddiff --git a/test/usage-topics.test.js b/test/usage-topics.test.js
nnew file mode 100644
iindex 00000000..65f7290f
---- /dev/null
++++ b/test/usage-topics.test.js
@@@ -0,0 +1,25 @@
++'use strict';
++// T5 step 8: *.usage.recorded rollups are counts for dashboards and quotas, never money. Only network, codes and
++// zone may consume one; Billing never does (it rates platform.usage-sample readings, billing.usage.record).
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++
++const dir = path.join(__dirname, '..', 'manifests', 'services');
++const MAY_CONSUME = new Set(['network', 'codes', 'zone']);
++const isUsageTopic = (t) => /\.usage\.recorded$/.test(t);
++
++const consumers = [];
++for (const f of fs.readdirSync(dir).filter((n) => n.endsWith('.json')).sort()) {
++ const m = JSON.parse(fs.readFileSync(path.join(dir, f), 'utf8'));
++ const id = m.id || path.basename(f, '.json');
++ const topics = (m.eventsConsumed || []).filter(isUsageTopic);
++ if (topics.length) consumers.push({ id, topics });
++}
++
++for (const c of consumers) {
++ assert.ok(MAY_CONSUME.has(c.id), `${c.id} consumes ${c.topics.join(', ')}: only network, codes and zone may consume a *.usage.recorded topic`);
++}
++assert.ok(!consumers.some((c) => c.id === 'billing'), 'billing never consumes a *.usage.recorded topic');
++assert.ok(consumers.some((c) => c.id === 'network'), 'network consumes the usage rollups it adds up per project');
++console.log(`usage-topics ok: ${consumers.map((c) => c.id).join(', ')} consume a *.usage.recorded topic`);