openvibers/openvibe.contracts Commits

Add user-owned trust class and publish the estate table (#13)

OP OpenVibers committed 3 Oct 2026 · eba7c2fe19 · 38 files, +201 −70

local checks ✓ 3/3 · CI ✓ 3/3 · review SHIP by DeepSeek harness (QUALITY=high)

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

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex fa006864..d2fa97b7 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,7 +4,19 @@ 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`).
--## Unreleased
++## 0.87.0 — 2026-10-03
++
++**User-owned trust class and the estate table** (plan T1 step 3; ADR-034 §5 control plane/data plane; the Fabric ADR,
++ADR-046, is still to write).
++- `platform.resource-offer@1` 1.1.0 and `platform.workload-requirements@1` 1.1.0 add the trust class `user-owned`
++ (a user's own node or machine), ordered `first-party`, `user-owned`, `partner`, `community`, `external`. Additive:
++ a producer or consumer that knows only the previous four values is unchanged. New valid fixtures `user-owned-node`
++ (an offer with `trust: "user-owned"`) and `user-owned-only` (requirements whose `trust` is `["user-owned"]`); the
++ existing first-party `owned-node` fixture stays.
++- `platform.usage-sample@1`: `route_epoch` and `trace_id` gain descriptions; their types and shape are unchanged.
++- `docs/ESTATE.md`: the plan §1.1 estate table as a data-only document (repository, product, authority, runtime,
++ database, domain, SDK/Contracts pin, deployment, public/private, current track). Step 2 replaces it with the table
++ generated in CI.
**Named object zones for OpenVibe.Zone** (ADR-031 amendment 2026-10-02; plan D37). The amendment maps named Zone buckets
onto Media's S3 surface. A zone is a Media namespace, and Media keeps the one object catalog and the only deletion
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex ddbc8954..9b07d205 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -5240,7 +5240,7 @@
},
{
"id": "platform.resource-offer",
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "network",
"schema": "platform/resource-offer.v1.json",
"visibility": "first-party",
@@@ -5250,7 +5250,7 @@
},
{
"id": "platform.workload-requirements",
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "network",
"schema": "platform/workload-requirements.v1.json",
"visibility": "first-party",
ddiff --git a/contracts/platform/resource-offer.v1.json b/contracts/platform/resource-offer.v1.json
iindex 2e4739a1..cd827dad 100644
---- a/contracts/platform/resource-offer.v1.json
++++ b/contracts/platform/resource-offer.v1.json
@@@ -53,6 +53,7 @@
"type": "string",
"enum": [
"first-party",
++ "user-owned",
"partner",
"community",
"external"
ddiff --git a/contracts/platform/usage-sample.v1.json b/contracts/platform/usage-sample.v1.json
iindex b0a0a158..d3d8fe0f 100644
---- a/contracts/platform/usage-sample.v1.json
++++ b/contracts/platform/usage-sample.v1.json
@@@ -80,10 +80,12 @@
},
"route_epoch": {
"type": "integer",
-- "minimum": 0
++ "minimum": 0,
++ "description": "Epoch of the signed placement plan that chose where this reading ran (platform.placement-plan@1 `epoch`). A later plan supersedes it; absent when Fabric did not place the work."
},
"trace_id": {
-- "type": "string"
++ "type": "string",
++ "description": "Opaque trace id tying this reading to the request and route that produced it, the same `trace_id` platform.telemetry-sample@1 carries; absent when the producer had no trace."
},
"source": {
"type": "string"
ddiff --git a/contracts/platform/workload-requirements.v1.json b/contracts/platform/workload-requirements.v1.json
iindex 7d8ce9b5..c611ec26 100644
---- a/contracts/platform/workload-requirements.v1.json
++++ b/contracts/platform/workload-requirements.v1.json
@@@ -78,6 +78,7 @@
"type": "string",
"enum": [
"first-party",
++ "user-owned",
"partner",
"community",
"external"
ddiff --git a/docs/ESTATE.md b/docs/ESTATE.md
nnew file mode 100644
iindex 00000000..77f079c1
---- /dev/null
++++ b/docs/ESTATE.md
@@@ -0,0 +1,33 @@
++# The estate
++
++Data only, from the plan's §1.1 "The estate" table (`OpenVibe_Updated_Plan_Based_On_Codebase.md`, 2026-09-30). Every
++cell is read straight from that table; `—` means §1.1 does not state it, not that it is empty in the estate. The
++authority for runtime, database, pins and deployment is each repository's `STATUS.json`, `package.json` and
++`migrations/`, so this table is a summary and T1 step 2 replaces it with one generated in CI from those sources.
++
++| Repository | Product | Authority it owns | Runtime | Database | Domain | SDK/Contracts pin | Deployment | Public/private | Current track |
++|---|---|---|---|---|---|---|---|---|---|
++| — | Network | identity, registry, grants, node/device principal | — | SQLite | openvibe.network + auth/api/admin/my/themes | — | Production | — | T2 |
++| — | Live | product surface only (no chat/money/transport after T3/T4/T5) | — | SQLite | openvibe.live | — | Production | — | T4 |
++| — | Chat | all chat tables | — | PostgreSQL | openvibe.chat | — | Production; T3 cutovers landed | — | T3 |
++| — | Media | all bytes, delivery | — | PostgreSQL | openvibe.media | — | Production; Fabric F1a/F1b live | — | T4 |
++| — | Events | event semantics | — | PostgreSQL | events.openvibe.network | — | Production backbone; ADR-042 fabric | — | T7 |
++| — | AI | models, provider routing | — | — | ai.openvibe.services | — | Production, internal only | — | T6 |
++| — | Billing | the ledger | — | — | billing.openvibe.network | — | Shadow; Live is money authority | — | T5 |
++| — | Tips, VIP | — | — | — | — | — | Built; not launched | — | T5 |
++| — | OpenRe.Stream | ingest | — | — | ingest.openre.stream | — | Built; 0 of 102 slots | — | T4 |
++| — | Host | sites, tenant config | — | — | openvibe.host, `ovhost` | — | Stage A production | — | T12 |
++| — | Community | community hub | — | PostgreSQL | openvibe.community | — | Production (forum empty) | — | T10 |
++| — | Tools | tools | — | SQLite | openvibe.tools + 7 satellites | — | Production, guard in report mode | — | T8 |
++| — | Games | game world | — | PostgreSQL | openvibe.games, play. | — | Production; M1 identity live | — | T8 |
++| — | Blog, Wiki | — | — | — | — | — | Deployed, thin | — | T9 |
++| — | Search | — | — | — | — | — | Deployed; 0 real documents | — | T9 |
++| — | Sources, News, Reviews, Deals, Coupons, Trade | — | — | — | — | — | Built; empty, sources disabled | — | T9 |
++| — | Codes | — | — | — | openvibe.codes | — | Deployed, thin (the old product) | — | T16 |
++| OpenVibe.Bot | Bot | robots, robot control (device principal moves to Network) | — | — | openvibe.bot | — | Service built (T15 step 1: robots, devices, pairing, device/operator WS, four profiles; ADR-043); robots still live in Live; not cut over | — | T15 |
++| OpenVibe.Node | Node | — | — | — | — | — | Core built on `origin/main` (`node-core` merged: node core, pairing, control link, WHIP publisher, Adeept + Cozmo plugins, installer, CI); not deployed | — | T14 |
++| — | Actor, Services, Run, Watch, Website, Zone | — | — | — | — | — | Not created | — | T13/T14/T17/T18/T19 |
++| — | openvibe-agents | — | — | — | — | — | Internal harness (§2.4); prototype for T16's routing | — | T16 |
++| — | Sites (33 domains) | — | — | — | 33 domains | — | Placeholder generator | — | deleted in T11 |
++| — | Realtime | — | — | — | — | — | Empty repo (closed by ADR-005) | — | deleted in T0 |
++| — | SDK, Contracts, Shared, Publishing, Extensions, Examples | libraries | — | — | — | Contracts 0.83.0, SDK 0.25.2 | — | — | T1 |
ddiff --git a/fixtures/platform.resource-offer/valid/user-owned-node.json b/fixtures/platform.resource-offer/valid/user-owned-node.json
nnew file mode 100644
iindex 00000000..56904110
---- /dev/null
++++ b/fixtures/platform.resource-offer/valid/user-owned-node.json
@@@ -0,0 +1,36 @@
++{
++ "offer_id": "off_user_node_1",
++ "kind": "node",
++ "node_id": "usr-node-1",
++ "provider": "self",
++ "region": "home",
++ "trust": "user-owned",
++ "capabilities": [
++ "node:http",
++ "worker:ai-gpu"
++ ],
++ "capacity": {
++ "cpu": {
++ "utilization": 0.1,
++ "available_cores": 8
++ },
++ "memory": {
++ "available_mb": 32000
++ },
++ "gpu": {
++ "type": "rtx-4090",
++ "vram_free_mb": 20000,
++ "utilization": 0
++ }
++ },
++ "latency_ms": {
++ "publish_p95": 20
++ },
++ "health": {
++ "status": "up"
++ },
++ "pricing": {
++ "model": "free-allowance"
++ },
++ "updated_at": "2026-10-03T00:00:00Z"
++}
ddiff --git a/fixtures/platform.workload-requirements/valid/user-owned-only.json b/fixtures/platform.workload-requirements/valid/user-owned-only.json
nnew file mode 100644
iindex 00000000..f6472156
---- /dev/null
++++ b/fixtures/platform.workload-requirements/valid/user-owned-only.json
@@@ -0,0 +1,9 @@
++{
++ "kind": "ai.run",
++ "mobility": "job",
++ "latency_class": "background",
++ "objective": "private",
++ "trust": [
++ "user-owned"
++ ]
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex a50d9e51..c35b77d4 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -57736,7 +57736,7 @@
}
},
"platform.resource-offer": {
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "network",
"status": "active",
"schema": {
@@@ -57794,6 +57794,7 @@
"type": "string",
"enum": [
"first-party",
++ "user-owned",
"partner",
"community",
"external"
@@@ -58144,7 +58145,7 @@
}
},
"platform.workload-requirements": {
-- "version": "1.0.0",
++ "version": "1.1.0",
"owner": "network",
"status": "active",
"schema": {
@@@ -58227,6 +58228,7 @@
"type": "string",
"enum": [
"first-party",
++ "user-owned",
"partner",
"community",
"external"
@@@ -58976,10 +58978,12 @@
},
"route_epoch": {
"type": "integer",
-- "minimum": 0
++ "minimum": 0,
++ "description": "Epoch of the signed placement plan that chose where this reading ran (platform.placement-plan@1 `epoch`). A later plan supersedes it; absent when Fabric did not place the work."
},
"trace_id": {
-- "type": "string"
++ "type": "string",
++ "description": "Opaque trace id tying this reading to the request and route that produced it, the same `trace_id` platform.telemetry-sample@1 carries; absent when the producer had no trace."
},
"source": {
"type": "string"
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex 39ce9ec8..9ef013e0 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.86.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 b4cd862c..45661534 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.86.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.87.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"
@@@ -3696,10 +3696,12 @@
},
"route_epoch": {
"type": "integer",
-- "minimum": 0
++ "minimum": 0,
++ "description": "Epoch of the signed placement plan that chose where this reading ran (platform.placement-plan@1 `epoch`). A later plan supersedes it; absent when Fabric did not place the work."
},
"trace_id": {
-- "type": "string"
++ "type": "string",
++ "description": "Opaque trace id tying this reading to the request and route that produced it, the same `trace_id` platform.telemetry-sample@1 carries; absent when the producer had no trace."
},
"source": {
"type": "string"
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex a5eda3b7..8d27bf2d 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.86.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 a416d913..42dc8609 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.86.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 78691e14..8877b798 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.86.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 96ec84b5..2b4bf3ff 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.86.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 b849b9a9..21c02ee1 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.86.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 20953d6e..271b9f65 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.86.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 772ecf70..3c6ecc4a 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.86.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 8f417c77..2873c008 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.86.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 a58c5fad..219235a8 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.86.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 537e91a2..4b7fb7c5 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.86.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 d61da51a..6814edf7 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.86.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 a2e4d431..216b9e0d 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.86.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 88553175..cb58c087 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.86.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 3b04a148..39524671 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.86.0",
-- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 8adc4ef4..29e83655 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.86.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 9df6e106..b7ab487d 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.86.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 94ea101a..20f3cada 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.86.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 0d0f6deb..f16199af 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.86.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 3bb8b29f..0793638d 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.86.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 0086a072..cd2f09e2 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.86.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 e543527c..5cb91988 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.86.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 a1982d5f..6bdd16e2 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.86.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 3912c196..a17587c2 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.86.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.86.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.87.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.87.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 6d191d10..2a4510f0 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -50724,7 +50724,7 @@ export interface NetworkCoinsReadResult {
};
}
--/** [email protected] (owner: network) */
++/** [email protected] (owner: network) */
/**
* What one node or external provider can run right now (roadmap WS-Z9, decision 43): capabilities, multidimensional capacity, measured latencies, health and pricing. First-party only: it carries capacity the public node registry (network.node@1) deliberately leaves out.
*/
@@@ -50747,7 +50747,7 @@ export type ResourceOffer = {
adapter?: string;
region: string;
cell?: string;
-- trust: "first-party" | "partner" | "community" | "external";
++ trust: "first-party" | "user-owned" | "partner" | "community" | "external";
/**
* e.g. node:http, worker:browser, worker:ffmpeg, worker:ai-gpu, events:gateway, events:durable, object:r2. Kind harness: task:edit, task:review, task:browse, task:run, task:test and task:plan for the task kinds it takes (its detail's task_capabilities), and harness:mcp, harness:resume, harness:host-access and harness:long-autonomy for its detail's capabilities that are true
*/
@@@ -50822,7 +50822,7 @@ export type ResourceOffer = {
detail?: {};
};
--/** [email protected] (owner: network) */
++/** [email protected] (owner: network) */
/**
* What a workload needs, so the platform can place it (roadmap WS-Z9). Hard constraints are filtered before any objective is scored; a cheaper candidate that misses one is never chosen.
*/
@@@ -50856,8 +50856,8 @@ export interface WorkloadRequirements {
* @minItems 1
*/
trust?: [
-- "first-party" | "partner" | "community" | "external",
-- ...("first-party" | "partner" | "community" | "external")[]
++ "first-party" | "user-owned" | "partner" | "community" | "external",
++ ...("first-party" | "user-owned" | "partner" | "community" | "external")[]
];
/**
* a region, or 'nearest'
@@@ -51126,7 +51126,13 @@ export interface UsageSample {
* Vibes charged for this reading, as an integer count of vibes-bits (Billing's ledger minor unit, currency `vibes-bits`; balance credit and ledger amounts use the same unit). Never whole Vibes, USD or a fraction: round once, when rating. Covers only `quantity` minus `free_allowance_used`; 0 means rated and nothing charged. Absent means not rated (yet). Records a charge already made in Billing's ledger; it is never a request to charge.
*/
vibes_charged?: number;
++ /**
++ * Epoch of the signed placement plan that chose where this reading ran (platform.placement-plan@1 `epoch`). A later plan supersedes it; absent when Fabric did not place the work.
++ */
route_epoch?: number;
++ /**
++ * Opaque trace id tying this reading to the request and route that produced it, the same `trace_id` platform.telemetry-sample@1 carries; absent when the producer had no trace.
++ */
trace_id?: string;
source: string;
}
ddiff --git a/package-lock.json b/package-lock.json
iindex a312138b..9d553b84 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-contracts",
-- "version": "0.86.0",
++ "version": "0.87.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.86.0",
++ "version": "0.87.0",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 68845405..6a53173e 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.86.0",
++ "version": "0.87.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",
ddiff --git a/test/platform-fabric.test.js b/test/platform-fabric.test.js
iindex b22660a9..46efeec5 100644
---- a/test/platform-fabric.test.js
++++ b/test/platform-fabric.test.js
@@@ -37,7 +37,9 @@ const planFields = [
];
const full = usage.examples.find(e => planFields.every(f => f in e));
assert.ok(full, 'a usage-sample example carries all 15 plan fields');
++checks++;
assert.strictEqual(contracts.validate('platform.usage-sample', full).valid, true);
++checks++;
for (const [field, value] of [['vibes_charged', 1.5], ['vibes_charged', -1], ['free_allowance_used', -1]]) {
assert.strictEqual(contracts.validate('platform.usage-sample', { ...full, [field]: value }).valid, false, `${field} ${value} is refused`);
checks++;
@@@ -50,8 +52,31 @@ for (const field of ['route_epoch', 'trace_id']) {
}
const legacy = Object.fromEntries(Object.entries(full).filter(([k]) => !['free_allowance_used', 'vibes_charged', 'route_epoch', 'trace_id'].includes(k)));
assert.strictEqual(contracts.validate('platform.usage-sample', legacy).valid, true, 'a reading without the new fields validates');
++checks++;
const minimal = Object.fromEntries(usage.required.map(k => [k, full[k]]));
assert.strictEqual(contracts.validate('platform.usage-sample', minimal).valid, true, 'a reading with only the required fields validates');
--checks += 3;
++checks++;
++
++// The five Fabric trust classes (plan §2.1.13): user-owned sits between first-party and partner in both
++// schemas, an offer or requirement carrying it is accepted, and an unknown class is refused.
++const trustClasses = ['first-party', 'user-owned', 'partner', 'community', 'external'];
++assert.deepStrictEqual(contracts.schema('platform.resource-offer').properties.trust.enum, trustClasses, 'resource-offer trust classes');
++checks++;
++assert.deepStrictEqual(contracts.schema('platform.workload-requirements').properties.trust.items.enum, trustClasses, 'workload-requirements trust classes');
++checks++;
++const userOffer = {
++ offer_id: 'off_user_node_1', kind: 'node', region: 'home', trust: 'user-owned',
++ capabilities: ['node:http'], health: { status: 'up' }, pricing: { model: 'free-allowance' },
++ updated_at: '2026-10-03T00:00:00Z',
++};
++assert.strictEqual(contracts.validate('platform.resource-offer', userOffer).valid, true, 'a user-owned offer validates');
++checks++;
++assert.strictEqual(contracts.validate('platform.resource-offer', { ...userOffer, trust: 'other' }).valid, false, 'an unknown offer trust is refused');
++checks++;
++const userRequirement = { kind: 'ai.run', mobility: 'job', latency_class: 'background', objective: 'private', trust: ['user-owned'] };
++assert.strictEqual(contracts.validate('platform.workload-requirements', userRequirement).valid, true, 'a user-owned-only requirement validates');
++checks++;
++assert.strictEqual(contracts.validate('platform.workload-requirements', { ...userRequirement, trust: ['other'] }).valid, false, 'an unknown requirement trust is refused');
++checks++;
console.log(`platform fabric: ${checks} example and required-field checks passed`);