openvibers/openvibe.contracts Commits
Add watch id prefixes, harness capability keys and resource summary ovrn (#21)
Changes
@@@ -8,6 +8,23 @@ the notes were in the tag and commit messages (`git tag -n1`).- `network.project.read` is active, implemented by OpenVibe.Network `GET /internal/projects/:project_id`.++**Watch ids** (plan T18, ready now):++- `lib/ids.js`: `PREFIX.watch = 'wch'`, `PREFIX.observation = 'wco'` and `PREFIX.check = 'ckr'`, so `ids.newId('watch')`++ gives the `wch_<ULID>` id the `common.resource-summary` fixture `watch` already carries. None is a subject type or a++ principal.++++**Harness capability vocabulary** (plan T17, ready now):++- `platform.harness-offer@1` `capabilities` gains the optional booleans `edit`, `review`, `tools`, `vision`, `browser`++ and `computer_use`, and an optional `runtimes` array (unique; `function`, `code`, `browser`, `linux`, `desktop`,++ `gpu`, the `platform.runtime-class@1` classes). `capabilities` keeps `additionalProperties: false`, and the entry stays++ 1.0.0, as it did when 0.86.0 added optional fields. New fixtures `capability-vocabulary` (valid, every new key) and++ `unknown-capability` (invalid, a `gpu` key: a runtime class belongs in `runtimes`). Additive.++++**Resource names in the resource index** (plan T13, ready now):++- `common.resource-summary@1` is 1.1.0: an optional `ovrn` (ADR-034 section 2) with the pattern of++ `common.usage-recorded@1` `resource`, naming the summary's own service, project and id. New fixtures `with-ovrn`++ (valid) and `ovrn-without-project` (invalid). Additive.++## 0.87.0 — 2026-10-03**Host git sources** (plan T12 Stage B): a Host site may name a public Git source — provider, repository URL and branch;@@@ -5514,7 +5514,7 @@},{"id": "common.resource-summary",-- "version": "1.0.0",++ "version": "1.1.0","owner": "contracts","schema": "common/resource-summary.v1.json","visibility": "public",@@@ -27,6 +27,12 @@"type": "string","pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"},++ "ovrn": {++ "type": "string",++ "maxLength": 200,++ "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."++ },"owner": {"$ref": "../identity/subject-ref.v1.json"},@@@ -40,6 +40,46 @@},"resume": {"type": "boolean"++ },++ "edit": {++ "type": "boolean",++ "description": "edits files in its working tree"++ },++ "review": {++ "type": "boolean",++ "description": "reviews a change and reports findings"++ },++ "tools": {++ "type": "boolean",++ "description": "calls tools such as a shell, search, or file reads on its own"++ },++ "vision": {++ "type": "boolean",++ "description": "reads images such as screenshots"++ },++ "browser": {++ "type": "boolean",++ "description": "drives a web browser"++ },++ "computer_use": {++ "type": "boolean",++ "description": "operates a desktop through its screen, keyboard, and mouse"++ },++ "runtimes": {++ "type": "array",++ "uniqueItems": true,++ "items": {++ "type": "string",++ "enum": [++ "function",++ "code",++ "browser",++ "linux",++ "desktop",++ "gpu"++ ]++ },++ "description": "platform.runtime-class@1 classes the harness runs in"}},"required": [nnew file mode 100644@@@ -0,0 +1,20 @@++{++ "id": "wch_01J0000000000000000000000A",++ "kind": "watch.watch",++ "service": "watch",++ "project_id": "prj_01J0000000000000000000000A",++ "ovrn": "ovrn:watch:watch/wch_01J0000000000000000000000A",++ "owner": {++ "type": "user",++ "id": "usr_01J0000000000000000000000A"++ },++ "name": "Price of a camera",++ "state": "active",++ "created_at": "2026-09-28T23:00:00Z",++ "usage": {++ "watch-check": 120++ },++ "links": {++ "self": "https://openvibe.watch/api/v1/watches/wch_01J0000000000000000000000A"++ }++}nnew file mode 100644@@@ -0,0 +1,20 @@++{++ "id": "wch_01J0000000000000000000000A",++ "kind": "watch.watch",++ "service": "watch",++ "project_id": "prj_01J0000000000000000000000A",++ "ovrn": "ovrn:watch:prj_01J0000000000000000000000A:watch/wch_01J0000000000000000000000A",++ "owner": {++ "type": "user",++ "id": "usr_01J0000000000000000000000A"++ },++ "name": "Price of a camera",++ "state": "active",++ "created_at": "2026-09-28T23:00:00Z",++ "usage": {++ "watch-check": 120++ },++ "links": {++ "self": "https://openvibe.watch/api/v1/watches/wch_01J0000000000000000000000A"++ }++}nnew file mode 100644@@@ -0,0 +1,24 @@++{++ "id": "harness-1",++ "name": "Example Agent",++ "provider": "example-ai",++ "capabilities": {++ "host_access": true,++ "mcp": true,++ "long_autonomy": true,++ "resume": true,++ "gpu": true++ },++ "address": {++ "kind": "cli",++ "target": "example-agent"++ },++ "price": {++ "amount_usd": 0.1,++ "unit": "hour"++ },++ "limits": {++ "max_duration_seconds": 7200,++ "max_concurrent_runs": 4++ }++}nnew file mode 100644@@@ -0,0 +1,34 @@++{++ "id": "harness-2",++ "name": "Example Desktop Agent",++ "provider": "example-ai",++ "capabilities": {++ "host_access": false,++ "mcp": true,++ "long_autonomy": true,++ "resume": true,++ "edit": true,++ "review": true,++ "tools": true,++ "vision": true,++ "browser": true,++ "computer_use": true,++ "runtimes": [++ "code",++ "browser",++ "desktop"++ ]++ },++ "address": {++ "kind": "api",++ "target": "https://agent.example.com/v1"++ },++ "price": {++ "amount_usd": 0.5,++ "unit": "hour"++ },++ "limits": {++ "max_duration_seconds": 3600,++ "max_concurrent_runs": 2++ }++}@@@ -60658,6 +60658,46 @@},"resume": {"type": "boolean"++ },++ "edit": {++ "type": "boolean",++ "description": "edits files in its working tree"++ },++ "review": {++ "type": "boolean",++ "description": "reviews a change and reports findings"++ },++ "tools": {++ "type": "boolean",++ "description": "calls tools such as a shell, search, or file reads on its own"++ },++ "vision": {++ "type": "boolean",++ "description": "reads images such as screenshots"++ },++ "browser": {++ "type": "boolean",++ "description": "drives a web browser"++ },++ "computer_use": {++ "type": "boolean",++ "description": "operates a desktop through its screen, keyboard, and mouse"++ },++ "runtimes": {++ "type": "array",++ "uniqueItems": true,++ "items": {++ "type": "string",++ "enum": [++ "function",++ "code",++ "browser",++ "linux",++ "desktop",++ "gpu"++ ]++ },++ "description": "platform.runtime-class@1 classes the harness runs in"}},"required": [@@@ -61520,7 +61560,7 @@}},"common.resource-summary": {-- "version": "1.0.0",++ "version": "1.1.0","owner": "contracts","status": "active","schema": {@@@ -61552,6 +61592,12 @@"type": "string","pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"},++ "ovrn": {++ "type": "string",++ "maxLength": 200,++ "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",++ "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."++ },"owner": {"$ref": "../identity/subject-ref.v1.json"},@@@ -51622,6 +51622,34 @@ export interface HarnessOffer {mcp: boolean;long_autonomy: boolean;resume: boolean;++ /**++ * edits files in its working tree++ */++ edit?: boolean;++ /**++ * reviews a change and reports findings++ */++ review?: boolean;++ /**++ * calls tools such as a shell, search, or file reads on its own++ */++ tools?: boolean;++ /**++ * reads images such as screenshots++ */++ vision?: boolean;++ /**++ * drives a web browser++ */++ browser?: boolean;++ /**++ * operates a desktop through its screen, keyboard, and mouse++ */++ computer_use?: boolean;++ /**++ * platform.runtime-class@1 classes the harness runs in++ */++ runtimes?: ("function" | "code" | "browser" | "linux" | "desktop" | "gpu")[];};address: {kind: "api" | "cli" | "mcp";@@@ -51895,7 +51923,7 @@ export interface DeliveryPolicy {max_payload_bytes?: number;}--/** [email protected] (owner: contracts) */++/** [email protected] (owner: contracts) *//*** One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.*/@@@ -51907,6 +51935,10 @@ export interface ResourceSummary {kind: string;service: string;project_id?: string;++ /**++ * Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0.++ */++ ovrn?: string;owner?: SubjectRef;name?: string;state: string;@@@ -6,7 +6,7 @@const crypto = require('crypto');const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';--const PREFIX = { user: 'usr', guest: 'gst', app: 'app', mod: 'mod', agent: 'agt', node: 'nod', event: 'evt', media: 'med', project: 'prj', confirmation: 'cnf' };++const PREFIX = { user: 'usr', guest: 'gst', app: 'app', mod: 'mod', agent: 'agt', node: 'nod', event: 'evt', media: 'med', project: 'prj', confirmation: 'cnf', watch: 'wch', observation: 'wco', check: 'ckr' };const SLUG_TYPES = new Set(['service', 'system']);const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;const SLUG_RE = /^[a-z][a-z0-9-]{1,39}$/;@@@ -529,6 +529,7 @@ ok(nodeId.startsWith('nod_') && ids.principalSub({ type: 'node', id: nodeId }) =assert.throws(() => ids.principalSub({ type: 'node', id: 'nod_42' }), /principals/);ok(!ids.SUBJECT_TYPES.includes('node') && ids.parseSubject(`node:${nodeId}`) === null, 'a node is a principal, never a subject');assert.throws(() => ids.principalSub({ type: 'user', id: ids.newId('user') }), /principals/);++for (const [kind, prefix] of [['watch', 'wch'], ['observation', 'wco'], ['check', 'ckr']]) ok(ids.newId(kind).startsWith(`${prefix}_`), `newId(${kind}) is ${prefix}_<ULID>`);ok(contracts.validate('media.media-ref', { media_id: ids.legacyMediaId('live', 'vod', 42) }).valid, 'legacyMediaId is a valid MediaRef');ok(contracts.validate('events.event-envelope', { event_id: ids.newId('event'), event_type: 'network.user.created', version: 1, source: 'network', actor: { type: 'system', id: 'network' }, timestamp: new Date().toISOString(), subject: { type: 'user', id: ids.newId('user') }, payload: {} }).valid, 'newId(event) builds a valid envelope');
@@ -8,6 +8,23 @@ the notes were in the tag and commit messages (`git tag -n1`).
@@ -8,6 +8,23 @@ the notes were in the tag and commit messages (`git tag -n1`).
- `network.project.read` is active, implemented by OpenVibe.Network `GET /internal/projects/:project_id`.
- `network.project.read` is active, implemented by OpenVibe.Network `GET /internal/projects/:project_id`.
+**Watch ids** (plan T18, ready now):
+- `lib/ids.js`: `PREFIX.watch = 'wch'`, `PREFIX.observation = 'wco'` and `PREFIX.check = 'ckr'`, so `ids.newId('watch')`
+ gives the `wch_<ULID>` id the `common.resource-summary` fixture `watch` already carries. None is a subject type or a
+ principal.
+
+**Harness capability vocabulary** (plan T17, ready now):
+- `platform.harness-offer@1` `capabilities` gains the optional booleans `edit`, `review`, `tools`, `vision`, `browser`
+ and `computer_use`, and an optional `runtimes` array (unique; `function`, `code`, `browser`, `linux`, `desktop`,
+ `gpu`, the `platform.runtime-class@1` classes). `capabilities` keeps `additionalProperties: false`, and the entry stays
+ 1.0.0, as it did when 0.86.0 added optional fields. New fixtures `capability-vocabulary` (valid, every new key) and
+ `unknown-capability` (invalid, a `gpu` key: a runtime class belongs in `runtimes`). Additive.
+
+**Resource names in the resource index** (plan T13, ready now):
+- `common.resource-summary@1` is 1.1.0: an optional `ovrn` (ADR-034 section 2) with the pattern of
+ `common.usage-recorded@1` `resource`, naming the summary's own service, project and id. New fixtures `with-ovrn`
+ (valid) and `ovrn-without-project` (invalid). Additive.
+
## 0.87.0 — 2026-10-03
## 0.87.0 — 2026-10-03
**Host git sources** (plan T12 Stage B): a Host site may name a public Git source — provider, repository URL and branch;
**Host git sources** (plan T12 Stage B): a Host site may name a public Git source — provider, repository URL and branch;
@@ -5514,7 +5514,7 @@
@@ -5514,7 +5514,7 @@
},
},
{
{
"id": "common.resource-summary",
"id": "common.resource-summary",
- "version": "1.0.0",
+ "version": "1.1.0",
"owner": "contracts",
"owner": "contracts",
"schema": "common/resource-summary.v1.json",
"schema": "common/resource-summary.v1.json",
"visibility": "public",
"visibility": "public",
@@ -27,6 +27,12 @@
@@ -27,6 +27,12 @@
"type": "string",
"type": "string",
"pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
"pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
},
},
+ "ovrn": {
+ "type": "string",
+ "maxLength": 200,
+ "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."
+ },
"owner": {
"owner": {
"$ref": "../identity/subject-ref.v1.json"
"$ref": "../identity/subject-ref.v1.json"
},
},
@@ -40,6 +40,46 @@
@@ -40,6 +40,46 @@
},
},
"resume": {
"resume": {
"type": "boolean"
"type": "boolean"
+ },
+ "edit": {
+ "type": "boolean",
+ "description": "edits files in its working tree"
+ },
+ "review": {
+ "type": "boolean",
+ "description": "reviews a change and reports findings"
+ },
+ "tools": {
+ "type": "boolean",
+ "description": "calls tools such as a shell, search, or file reads on its own"
+ },
+ "vision": {
+ "type": "boolean",
+ "description": "reads images such as screenshots"
+ },
+ "browser": {
+ "type": "boolean",
+ "description": "drives a web browser"
+ },
+ "computer_use": {
+ "type": "boolean",
+ "description": "operates a desktop through its screen, keyboard, and mouse"
+ },
+ "runtimes": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "enum": [
+ "function",
+ "code",
+ "browser",
+ "linux",
+ "desktop",
+ "gpu"
+ ]
+ },
+ "description": "platform.runtime-class@1 classes the harness runs in"
}
}
},
},
"required": [
"required": [
new file mode 100644
new file mode 100644
@@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
+{
+ "id": "wch_01J0000000000000000000000A",
+ "kind": "watch.watch",
+ "service": "watch",
+ "project_id": "prj_01J0000000000000000000000A",
+ "ovrn": "ovrn:watch:watch/wch_01J0000000000000000000000A",
+ "owner": {
+ "type": "user",
+ "id": "usr_01J0000000000000000000000A"
+ },
+ "name": "Price of a camera",
+ "state": "active",
+ "created_at": "2026-09-28T23:00:00Z",
+ "usage": {
+ "watch-check": 120
+ },
+ "links": {
+ "self": "https://openvibe.watch/api/v1/watches/wch_01J0000000000000000000000A"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
+{
+ "id": "wch_01J0000000000000000000000A",
+ "kind": "watch.watch",
+ "service": "watch",
+ "project_id": "prj_01J0000000000000000000000A",
+ "ovrn": "ovrn:watch:prj_01J0000000000000000000000A:watch/wch_01J0000000000000000000000A",
+ "owner": {
+ "type": "user",
+ "id": "usr_01J0000000000000000000000A"
+ },
+ "name": "Price of a camera",
+ "state": "active",
+ "created_at": "2026-09-28T23:00:00Z",
+ "usage": {
+ "watch-check": 120
+ },
+ "links": {
+ "self": "https://openvibe.watch/api/v1/watches/wch_01J0000000000000000000000A"
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
+{
+ "id": "harness-1",
+ "name": "Example Agent",
+ "provider": "example-ai",
+ "capabilities": {
+ "host_access": true,
+ "mcp": true,
+ "long_autonomy": true,
+ "resume": true,
+ "gpu": true
+ },
+ "address": {
+ "kind": "cli",
+ "target": "example-agent"
+ },
+ "price": {
+ "amount_usd": 0.1,
+ "unit": "hour"
+ },
+ "limits": {
+ "max_duration_seconds": 7200,
+ "max_concurrent_runs": 4
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
+{
+ "id": "harness-2",
+ "name": "Example Desktop Agent",
+ "provider": "example-ai",
+ "capabilities": {
+ "host_access": false,
+ "mcp": true,
+ "long_autonomy": true,
+ "resume": true,
+ "edit": true,
+ "review": true,
+ "tools": true,
+ "vision": true,
+ "browser": true,
+ "computer_use": true,
+ "runtimes": [
+ "code",
+ "browser",
+ "desktop"
+ ]
+ },
+ "address": {
+ "kind": "api",
+ "target": "https://agent.example.com/v1"
+ },
+ "price": {
+ "amount_usd": 0.5,
+ "unit": "hour"
+ },
+ "limits": {
+ "max_duration_seconds": 3600,
+ "max_concurrent_runs": 2
+ }
+}
@@ -60658,6 +60658,46 @@
@@ -60658,6 +60658,46 @@
},
},
"resume": {
"resume": {
"type": "boolean"
"type": "boolean"
+ },
+ "edit": {
+ "type": "boolean",
+ "description": "edits files in its working tree"
+ },
+ "review": {
+ "type": "boolean",
+ "description": "reviews a change and reports findings"
+ },
+ "tools": {
+ "type": "boolean",
+ "description": "calls tools such as a shell, search, or file reads on its own"
+ },
+ "vision": {
+ "type": "boolean",
+ "description": "reads images such as screenshots"
+ },
+ "browser": {
+ "type": "boolean",
+ "description": "drives a web browser"
+ },
+ "computer_use": {
+ "type": "boolean",
+ "description": "operates a desktop through its screen, keyboard, and mouse"
+ },
+ "runtimes": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string",
+ "enum": [
+ "function",
+ "code",
+ "browser",
+ "linux",
+ "desktop",
+ "gpu"
+ ]
+ },
+ "description": "platform.runtime-class@1 classes the harness runs in"
}
}
},
},
"required": [
"required": [
@@ -61520,7 +61560,7 @@
@@ -61520,7 +61560,7 @@
}
}
},
},
"common.resource-summary": {
"common.resource-summary": {
- "version": "1.0.0",
+ "version": "1.1.0",
"owner": "contracts",
"owner": "contracts",
"status": "active",
"status": "active",
"schema": {
"schema": {
@@ -61552,6 +61592,12 @@
@@ -61552,6 +61592,12 @@
"type": "string",
"type": "string",
"pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
"pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
},
},
+ "ovrn": {
+ "type": "string",
+ "maxLength": 200,
+ "pattern": "^ovrn:[a-z][a-z0-9-]{0,31}:prj_[0-9A-HJKMNP-TV-Z]{26}:[a-z][a-z0-9-]{0,39}/[a-z]{3}_[0-9A-HJKMNP-TV-Z]{26}$",
+ "description": "Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0."
+ },
"owner": {
"owner": {
"$ref": "../identity/subject-ref.v1.json"
"$ref": "../identity/subject-ref.v1.json"
},
},
@@ -51622,6 +51622,34 @@ export interface HarnessOffer {
@@ -51622,6 +51622,34 @@ export interface HarnessOffer {
mcp: boolean;
mcp: boolean;
long_autonomy: boolean;
long_autonomy: boolean;
resume: boolean;
resume: boolean;
+ /**
+ * edits files in its working tree
+ */
+ edit?: boolean;
+ /**
+ * reviews a change and reports findings
+ */
+ review?: boolean;
+ /**
+ * calls tools such as a shell, search, or file reads on its own
+ */
+ tools?: boolean;
+ /**
+ * reads images such as screenshots
+ */
+ vision?: boolean;
+ /**
+ * drives a web browser
+ */
+ browser?: boolean;
+ /**
+ * operates a desktop through its screen, keyboard, and mouse
+ */
+ computer_use?: boolean;
+ /**
+ * platform.runtime-class@1 classes the harness runs in
+ */
+ runtimes?: ("function" | "code" | "browser" | "linux" | "desktop" | "gpu")[];
};
};
address: {
address: {
kind: "api" | "cli" | "mcp";
kind: "api" | "cli" | "mcp";
@@ -51895,7 +51923,7 @@ export interface DeliveryPolicy {
@@ -51895,7 +51923,7 @@ export interface DeliveryPolicy {
max_payload_bytes?: number;
max_payload_bytes?: number;
}
}
-/** [email protected] (owner: contracts) */
+/** [email protected] (owner: contracts) */
/**
/**
* One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.
* One resource of any service, as the resource index lists it (roadmap WS-Z7): every service answers GET /api/v1/resources with these, so OpenVibe.Services shows any resource without owning its data.
*/
*/
@@ -51907,6 +51935,10 @@ export interface ResourceSummary {
@@ -51907,6 +51935,10 @@ export interface ResourceSummary {
kind: string;
kind: string;
service: string;
service: string;
project_id?: string;
project_id?: string;
+ /**
+ * Optional resource name (ADR-034 section 2), the name grants, audit, events, usage records and bills use: ovrn:<service>:<project_id>:<type>/<id>, e.g. ovrn:watch:<project_id>:watch/<wch_id>, with the pattern of common.usage-recorded@1 resource. Its service, project and id are this summary's service, project_id and id. Added in 1.1.0.
+ */
+ ovrn?: string;
owner?: SubjectRef;
owner?: SubjectRef;
name?: string;
name?: string;
state: string;
state: string;
@@ -6,7 +6,7 @@
@@ -6,7 +6,7 @@
const crypto = require('crypto');
const crypto = require('crypto');
const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
-const PREFIX = { user: 'usr', guest: 'gst', app: 'app', mod: 'mod', agent: 'agt', node: 'nod', event: 'evt', media: 'med', project: 'prj', confirmation: 'cnf' };
+const PREFIX = { user: 'usr', guest: 'gst', app: 'app', mod: 'mod', agent: 'agt', node: 'nod', event: 'evt', media: 'med', project: 'prj', confirmation: 'cnf', watch: 'wch', observation: 'wco', check: 'ckr' };
const SLUG_TYPES = new Set(['service', 'system']);
const SLUG_TYPES = new Set(['service', 'system']);
const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
const SLUG_RE = /^[a-z][a-z0-9-]{1,39}$/;
const SLUG_RE = /^[a-z][a-z0-9-]{1,39}$/;
@@ -529,6 +529,7 @@ ok(nodeId.startsWith('nod_') && ids.principalSub({ type: 'node', id: nodeId }) =
@@ -529,6 +529,7 @@ ok(nodeId.startsWith('nod_') && ids.principalSub({ type: 'node', id: nodeId }) =
assert.throws(() => ids.principalSub({ type: 'node', id: 'nod_42' }), /principals/);
assert.throws(() => ids.principalSub({ type: 'node', id: 'nod_42' }), /principals/);
ok(!ids.SUBJECT_TYPES.includes('node') && ids.parseSubject(`node:${nodeId}`) === null, 'a node is a principal, never a subject');
ok(!ids.SUBJECT_TYPES.includes('node') && ids.parseSubject(`node:${nodeId}`) === null, 'a node is a principal, never a subject');
assert.throws(() => ids.principalSub({ type: 'user', id: ids.newId('user') }), /principals/);
assert.throws(() => ids.principalSub({ type: 'user', id: ids.newId('user') }), /principals/);
+for (const [kind, prefix] of [['watch', 'wch'], ['observation', 'wco'], ['check', 'ckr']]) ok(ids.newId(kind).startsWith(`${prefix}_`), `newId(${kind}) is ${prefix}_<ULID>`);
ok(contracts.validate('media.media-ref', { media_id: ids.legacyMediaId('live', 'vod', 42) }).valid, 'legacyMediaId is a valid MediaRef');
ok(contracts.validate('media.media-ref', { media_id: ids.legacyMediaId('live', 'vod', 42) }).valid, 'legacyMediaId is a valid MediaRef');
ok(contracts.validate('events.event-envelope', { event_id: ids.newId('event'), event_type: 'network.user.created', version: 1, source: 'network', actor: { type: 'system', id: 'network' }, timestamp: new Date().toISOString(), subject: { type: 'user', id: ids.newId('user') }, payload: {} }).valid, 'newId(event) builds a valid envelope');
ok(contracts.validate('events.event-envelope', { event_id: ids.newId('event'), event_type: 'network.user.created', version: 1, source: 'network', actor: { type: 'system', id: 'network' }, timestamp: new Date().toISOString(), subject: { type: 'user', id: ids.newId('user') }, payload: {} }).valid, 'newId(event) builds a valid envelope');