openvibers/openvibe.contracts Commits

Define read-only Actor task view tickets (#357)

OP OpenVibers committed 6 days ago · 3ca791e5f2 · 11 files, +183 −3

Changes

ddiff --git a/contracts/actor/task-view-ticket.v1.json b/contracts/actor/task-view-ticket.v1.json
nnew file mode 100644
iindex 00000000..8a22c5f4
---- /dev/null
++++ b/contracts/actor/task-view-ticket.v1.json
@@@ -0,0 +1,23 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/actor/task-view-ticket.v1.json",
++ "title": "ActorTaskViewTicket",
++ "description": "actor.task-view-ticket@1: a reusable read-only view of one task for its owner, valid for 15 minutes. The URL contains a bearer credential; never log it or forward it in a referrer.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "url",
++ "expires_at"
++ ],
++ "properties": {
++ "url": {
++ "type": "string",
++ "format": "uri",
++ "pattern": "^https?://[^/?#]+/embed/task/[^/?#]+\\?t=tvt_[A-Za-z0-9_-]{43}$"
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++}
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex edad0e9f..7513adcc 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -10198,6 +10198,16 @@
"visibility": "first-party",
"compatibility": "backward",
"status": "active"
++ },
++ {
++ "id": "actor.task-view-ticket",
++ "version": "1.0.0",
++ "owner": "actor",
++ "schema": "actor/task-view-ticket.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active",
++ "adr": "ADR-044"
}
]
}
ddiff --git a/fixtures/actor.task-view-ticket/invalid/missing-expiry.json b/fixtures/actor.task-view-ticket/invalid/missing-expiry.json
nnew file mode 100644
iindex 00000000..985501a1
---- /dev/null
++++ b/fixtures/actor.task-view-ticket/invalid/missing-expiry.json
@@@ -0,0 +1,3 @@
++{
++ "url": "https://openvibe.actor/"
++}
ddiff --git a/fixtures/actor.task-view-ticket/invalid/wrong-ticket.json b/fixtures/actor.task-view-ticket/invalid/wrong-ticket.json
nnew file mode 100644
iindex 00000000..109a38f4
---- /dev/null
++++ b/fixtures/actor.task-view-ticket/invalid/wrong-ticket.json
@@@ -0,0 +1,4 @@
++{
++ "url": "https://openvibe.actor/embed/task/tsk_example?t=wpt_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
++ "expires_at": "2026-11-08T12:15:00Z"
++}
ddiff --git a/fixtures/actor.task-view-ticket/valid/view.json b/fixtures/actor.task-view-ticket/valid/view.json
nnew file mode 100644
iindex 00000000..a9a532b9
---- /dev/null
++++ b/fixtures/actor.task-view-ticket/valid/view.json
@@@ -0,0 +1,4 @@
++{
++ "url": "https://openvibe.actor/embed/task/tsk_example?t=tvt_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
++ "expires_at": "2026-11-08T12:15:00Z"
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex b11bd636..44782b3c 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -113039,6 +113039,34 @@
}
}
}
++ },
++ "actor.task-view-ticket": {
++ "version": "1.0.0",
++ "owner": "actor",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/actor/task-view-ticket.v1.json",
++ "title": "ActorTaskViewTicket",
++ "description": "actor.task-view-ticket@1: a reusable read-only view of one task for its owner, valid for 15 minutes. The URL contains a bearer credential; never log it or forward it in a referrer.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "url",
++ "expires_at"
++ ],
++ "properties": {
++ "url": {
++ "type": "string",
++ "format": "uri",
++ "pattern": "^https?://[^/?#]+/embed/task/[^/?#]+\\?t=tvt_[A-Za-z0-9_-]{43}$"
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ }
}
}
}
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex aceb4b42..80ced999 100644
---- a/generated/openapi/actor.json
++++ b/generated/openapi/actor.json
@@@ -2856,6 +2856,62 @@
}
}
},
++ "/api/v1/tasks/{id}/view-ticket": {
++ "post": {
++ "operationId": "post_api_v1_tasks_id_view_ticket",
++ "summary": "Mint a 15-minute reusable read-only task embed ticket.",
++ "description": "**actor.task.view_ticket** (public): Mint a 15-minute reusable read-only task embed ticket. Only the person's own Bearer token and their own task are accepted; session cookies, service and delegated tokens cannot mint. Another person's task returns 404. Tickets work only on /embed/task/:id and its events/still reads, never on a write route. Wrong-task or expired tickets return 403. Stored only as SHA-256 hashes, bound to task and requester.",
++ "tags": [
++ "actor.task"
++ ],
++ "x-openvibe-capabilities": [
++ "actor.task.view_ticket"
++ ],
++ "x-openvibe-visibility": [
++ "public"
++ ],
++ "x-openvibe-quota-class": "actor-read",
++ "security": [
++ {
++ "openvibeToken": [
++ "actor.task.view_ticket"
++ ]
++ }
++ ],
++ "parameters": [
++ {
++ "name": "id",
++ "in": "path",
++ "required": true,
++ "schema": {
++ "type": "string"
++ }
++ }
++ ],
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/actor.task-view-ticket.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
++ },
"/internal/config": {
"get": {
"operationId": "get_internal_config",
@@@ -4652,6 +4708,27 @@
}
}
},
++ "actor.task-view-ticket.v1": {
++ "title": "ActorTaskViewTicket",
++ "description": "actor.task-view-ticket@1: a reusable read-only view of one task for its owner, valid for 15 minutes. The URL contains a bearer credential; never log it or forward it in a referrer.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "url",
++ "expires_at"
++ ],
++ "properties": {
++ "url": {
++ "type": "string",
++ "format": "uri",
++ "pattern": "^https?://[^/?#]+/embed/task/[^/?#]+\\?t=tvt_[A-Za-z0-9_-]{43}$"
++ },
++ "expires_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ },
"agent.timeline-entry.v1": {
"title": "AgentTimelineEntry",
"description": "One entry of the agent's timeline (design 2026-11-07 §2): one step of the agent's work, in one mode, for one person. The Dock shows it: the mode's icon and word, the title, where it ran and why, the outcome, the time and the cost. Only a title, an outcome and a link: never a prompt, a diff or a page. A person sees their own entries; another person's entry is a 404. The audience is 'private' (Only me) unless the person shared the entry through the one Share sheet.",
ddiff --git a/generated/openapi/index.json b/generated/openapi/index.json
iindex 9f592bc2..fcaf0253 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -5,8 +5,8 @@
"service": "actor",
"name": "OpenVibe.Actor",
"origin": "https://openvibe.actor",
-- "operations": 54,
-- "capabilities": 16
++ "operations": 55,
++ "capabilities": 17
},
{
"service": "ai",
ddiff --git a/generated/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex 35da553b..795508e6 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -316603,3 +316603,12 @@ export interface MailInboxAnswering {
*/
changed_at: string | null;
}
++
++/** [email protected] (owner: actor) */
++/**
++ * actor.task-view-ticket@1: a reusable read-only view of one task for its owner, valid for 15 minutes. The URL contains a bearer credential; never log it or forward it in a referrer.
++ */
++export interface ActorTaskViewTicket {
++ url: string;
++ expires_at: string;
++}
ddiff --git a/manifests/capabilities/actor.task.view_ticket.json b/manifests/capabilities/actor.task.view_ticket.json
nnew file mode 100644
iindex 00000000..c9b792dc
---- /dev/null
++++ b/manifests/capabilities/actor.task.view_ticket.json
@@@ -0,0 +1,21 @@
++{
++ "id": "actor.task.view_ticket",
++ "version": "1.0",
++ "owner": "actor",
++ "status": "active",
++ "visibility": "public",
++ "description": "Mint a 15-minute reusable read-only task embed ticket. Only the person's own Bearer token and their own task are accepted; session cookies, service and delegated tokens cannot mint. Another person's task returns 404. Tickets work only on /embed/task/:id and its events/still reads, never on a write route. Wrong-task or expired tickets return 403. Stored only as SHA-256 hashes, bound to task and requester.",
++ "inputSchema": "common.no-body@1",
++ "outputSchema": "actor.task-view-ticket@1",
++ "permissions": [
++ "actor:tasks:read"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "actor-read",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/tasks/:id/view-ticket"
++ ]
++}
ddiff --git a/manifests/services/actor.json b/manifests/services/actor.json
iindex a43b1257..15becfde 100644
---- a/manifests/services/actor.json
++++ b/manifests/services/actor.json
@@@ -31,7 +31,8 @@
"actor.config.manage",
"actor.timeline.read",
"actor.assignment.read",
-- "actor.assignment.cancel"
++ "actor.assignment.cancel",
++ "actor.task.view_ticket"
],
"eventsProduced": [
"agent.step.started",