openvibers/openvibe.contracts Commits

Agent Streams S3: report.session@1, its write request and the report.session.write capability (0.300.0) (#310)

OP OpenVibers committed 7 days ago · 7bbbd6af06 · 60 files, +2366 −88

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 71b3743c..94261f82 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -1,5 +1,12 @@
# Changelog
++## 0.300.0 — 2026-11-06
++
++- Add `report.session@1`: the report of one agent session, whatever ran it — a Codes task, an Actor task, a desk session or a session on a person's own machine (the Agent Streams plan, S3). It carries the id (`rps_<ULID>`), the owner (`usr_…`), the source (`codes`, `actor`, `desk` or `node`), the task (title ≤ 200 characters, the task's ref and its link back), the start and end, the worked seconds, the outcome (`done`, `stopped` or `failed`, with `stopped_because` in plain words when it did not finish), the summary (≤ 600 characters), the timeline (the steps, the same shape as `live.agent-stream-step@1`), the outputs (`pr`, `file`, `page`, `deploy`, `clip` or `vod`), the proof (the tests, the screenshots' media ids and the review's verdict), the cost and the models, up to five highlights, the agent stream it streamed on and the visibility (`private`, `unlisted` or `public`). The raw transcript, secrets and code are never in a report: the source service keeps the transcript for the owner, the house redactor runs over every text field before anything is stored, and a pull request is a link (its content shows only when the repository is public).
++- Add `report.session-write-request@1` and `report.session-write-result@1`: the body of `POST /internal/session-reports` on OpenVibe.Report and what it answers. The route is idempotent per (source, task ref): the same session's task always answers the same report. The report's id is Report's own; the body never carries one. The write request's `stream_only` says a stream-only report (Live's, when no tool finished the session).
++- Add the capability `report.session.write` (first-party) and name it in Report's service manifest. The caller is a first-party service — Codes, Actor or Live — with a service token that holds it for the audience `openvibe.report`.
++- Valid and invalid fixtures cover the report, the write request and the write result, so a missing owner, an id that is not `rps_…`, an outcome outside the list or a URL that is not a Report page fails the run.
++
## 0.299.0 — 2026-11-06
- Add `live.agent-stream-step@1`: one step of the work an agent is doing on an agent stream (the Agent Streams plan, S2). It carries `at` (when the step began), `title` (at most 120 characters), `status` (`started`, `passed`, `failed` or `skipped`), the optional `detail` (at most 500 characters), the optional `tests` (`passed` and `failed`) and the optional `cost_usd`. The step is plain text: the house text filters have already run over it before Live stores it.
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex 1164672b..0d71702a 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -9474,6 +9474,33 @@
"visibility": "first-party",
"compatibility": "backward",
"status": "active"
++ },
++ {
++ "id": "report.session",
++ "version": "1.0.0",
++ "owner": "report",
++ "schema": "report/session.v1.json",
++ "visibility": "public",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "report.session-write-request",
++ "version": "1.0.0",
++ "owner": "report",
++ "schema": "report/session-write-request.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "report.session-write-result",
++ "version": "1.0.0",
++ "owner": "report",
++ "schema": "report/session-write-result.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
}
]
}
ddiff --git a/contracts/report/session-write-request.v1.json b/contracts/report/session-write-request.v1.json
nnew file mode 100644
iindex 00000000..dfcb813d
---- /dev/null
++++ b/contracts/report/session-write-request.v1.json
@@@ -0,0 +1,334 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/report/session-write-request.v1.json",
++ "title": "ReportSessionWriteRequest",
++ "description": "report.session-write-request@1 (the Agent Streams plan, S3): the body of POST /internal/session-reports on OpenVibe.Report (capability report.session.write). The caller is a first-party service - Codes, Actor or Live - holding that capability for the audience openvibe.report; the body names the person the session was theirs. The route is idempotent per (SOURCE, TASK.REF): a repeat of the same session's task answers the report already stored, with created false. The report's id is Report's own (rps_<ULID>); the body never carries one. Every text field passes the house redactor before anything is stored, so no secret and no raw transcript is ever stored.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "owner",
++ "source",
++ "task",
++ "started_at",
++ "ended_at",
++ "worked_seconds",
++ "outcome",
++ "summary"
++ ],
++ "properties": {
++ "owner": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The person the session was theirs."
++ },
++ "source": {
++ "enum": [
++ "codes",
++ "actor",
++ "desk",
++ "node"
++ ]
++ },
++ "task": {
++ "$ref": "#/$defs/task"
++ },
++ "started_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "ended_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "worked_seconds": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "outcome": {
++ "enum": [
++ "done",
++ "stopped",
++ "failed"
++ ]
++ },
++ "stopped_because": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 300
++ },
++ "summary": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 600
++ },
++ "timeline": {
++ "type": "array",
++ "items": {
++ "$ref": "#/$defs/step"
++ }
++ },
++ "outputs": {
++ "type": "array",
++ "items": {
++ "$ref": "#/$defs/output"
++ }
++ },
++ "proof": {
++ "$ref": "#/$defs/proof"
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "models": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ }
++ },
++ "highlights": {
++ "type": "array",
++ "maxItems": 5,
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ }
++ },
++ "stream": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "ags_id"
++ ],
++ "properties": {
++ "ags_id": {
++ "type": "string",
++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "vod_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ }
++ }
++ },
++ "visibility": {
++ "enum": [
++ "private",
++ "unlisted",
++ "public"
++ ],
++ "description": "Who may see it. Absent means private."
++ },
++ "stream_only": {
++ "type": "boolean",
++ "description": "Live's stream-only report: the session is the stream itself and no tool will finish it. Absent or false means a normal session report."
++ }
++ },
++ "$defs": {
++ "task": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "title",
++ "ref"
++ ],
++ "properties": {
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ }
++ }
++ },
++ "step": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "at",
++ "title",
++ "status"
++ ],
++ "properties": {
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "status": {
++ "enum": [
++ "started",
++ "passed",
++ "failed",
++ "skipped"
++ ]
++ },
++ "detail": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 500
++ },
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ }
++ }
++ },
++ "output": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title"
++ ],
++ "properties": {
++ "kind": {
++ "enum": [
++ "pr",
++ "file",
++ "page",
++ "deploy",
++ "clip",
++ "vod"
++ ]
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "state": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 60
++ }
++ }
++ },
++ "proof": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "tests",
++ "screenshots",
++ "review"
++ ],
++ "properties": {
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "screenshots": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ }
++ },
++ "review": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "verdict"
++ ],
++ "properties": {
++ "verdict": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 40
++ },
++ "notes": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2000
++ }
++ }
++ }
++ }
++ }
++ }
++}
ddiff --git a/contracts/report/session-write-result.v1.json b/contracts/report/session-write-result.v1.json
nnew file mode 100644
iindex 00000000..ef65e7cc
---- /dev/null
++++ b/contracts/report/session-write-result.v1.json
@@@ -0,0 +1,28 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/report/session-write-result.v1.json",
++ "title": "ReportSessionWriteResult",
++ "description": "report.session-write-result@1: what POST /internal/session-reports on OpenVibe.Report answers. ID is the report's id, URL its page (openvibe.report/s/<id>) and CREATED says whether this call stored the report or found the one it had already stored (the route is idempotent per source and task ref).",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "url",
++ "created"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^rps_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "url": {
++ "type": "string",
++ "format": "uri",
++ "pattern": "^https://openvibe\\.report/s/"
++ },
++ "created": {
++ "type": "boolean",
++ "description": "True when this call stored the report, false when it was already there."
++ }
++ }
++}
ddiff --git a/contracts/report/session.v1.json b/contracts/report/session.v1.json
nnew file mode 100644
iindex 00000000..fee59f3f
---- /dev/null
++++ b/contracts/report/session.v1.json
@@@ -0,0 +1,363 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/report/session.v1.json",
++ "title": "ReportSession",
++ "description": "report.session@1 (the Agent Streams plan, S3): the report of one agent session, whatever ran it - a Codes task, an Actor task, a desk session or a session on a person's own machine. OWNER is the person it belongs to, SOURCE where the work ran and TASK the task it is about, with a link back to it. TIMELINE holds the steps as they happened (the same shape as live.agent-stream-step@1). OUTPUTS are what came out (a pull request, files, pages, a deploy, a clip, the VOD). PROOF is Codes' finished-task proof: the tests, the screenshots and the review. COST_USD and MODELS say what it cost and which models ran. HIGHLIGHTS are up to five one-line moments. STREAM is the agent stream it streamed on, when it did. VISIBILITY is who may see it: private (the default), unlisted (anyone with the link) or public. NEVER IN A REPORT: the raw transcript (the source service keeps it for the owner, privately), secrets (the house redactor runs over every text field before anything is stored) and code or diffs (a link to the pull request is fine; its content shows only when the repository is public).",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "owner",
++ "source",
++ "task",
++ "started_at",
++ "ended_at",
++ "worked_seconds",
++ "outcome",
++ "summary",
++ "timeline",
++ "outputs",
++ "proof",
++ "cost_usd",
++ "models",
++ "highlights",
++ "stream",
++ "visibility"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^rps_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The report's id (ULID, Crockford base32)."
++ },
++ "owner": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The person the session was theirs."
++ },
++ "source": {
++ "enum": [
++ "codes",
++ "actor",
++ "desk",
++ "node"
++ ],
++ "description": "Where the session ran."
++ },
++ "task": {
++ "$ref": "#/$defs/task"
++ },
++ "started_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "ended_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "worked_seconds": {
++ "type": "integer",
++ "minimum": 0,
++ "description": "How long the agent worked (the page's 'worked 42 min')."
++ },
++ "outcome": {
++ "enum": [
++ "done",
++ "stopped",
++ "failed"
++ ],
++ "description": "How the session ended. A session that did not finish says why in stopped_because."
++ },
++ "stopped_because": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 300,
++ "description": "Why it stopped, in plain words. Present when the outcome is not done."
++ },
++ "summary": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 600,
++ "description": "What was asked and what happened, in plain words."
++ },
++ "timeline": {
++ "type": "array",
++ "items": {
++ "$ref": "#/$defs/step"
++ },
++ "description": "The steps, in the order they happened."
++ },
++ "outputs": {
++ "type": "array",
++ "items": {
++ "$ref": "#/$defs/output"
++ }
++ },
++ "proof": {
++ "$ref": "#/$defs/proof"
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0,
++ "description": "What the session cost, in dollars."
++ },
++ "models": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "description": "Which models ran."
++ },
++ "highlights": {
++ "type": "array",
++ "maxItems": 5,
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "description": "Up to five one-line moments."
++ },
++ "stream": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "ags_id"
++ ],
++ "properties": {
++ "ags_id": {
++ "type": "string",
++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "vod_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ }
++ },
++ "description": "The agent stream the session streamed on, when it did."
++ },
++ "visibility": {
++ "enum": [
++ "private",
++ "unlisted",
++ "public"
++ ]
++ }
++ },
++ "$defs": {
++ "task": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "title",
++ "ref"
++ ],
++ "properties": {
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200,
++ "description": "What the task was, in the person's own words."
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200,
++ "description": "The task's id in its source."
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "description": "The task's page, when it has one."
++ }
++ }
++ },
++ "step": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "at",
++ "title",
++ "status"
++ ],
++ "properties": {
++ "at": {
++ "type": "string",
++ "format": "date-time",
++ "description": "When the step began."
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "status": {
++ "enum": [
++ "started",
++ "passed",
++ "failed",
++ "skipped"
++ ],
++ "description": "The same statuses as live.agent-stream-step@1."
++ },
++ "detail": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 500
++ },
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ }
++ }
++ },
++ "output": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title"
++ ],
++ "properties": {
++ "kind": {
++ "enum": [
++ "pr",
++ "file",
++ "page",
++ "deploy",
++ "clip",
++ "vod"
++ ],
++ "description": "What came out."
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "state": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 60,
++ "description": "A pull request's state ('open', 'merged'), when the source knows it."
++ }
++ }
++ },
++ "proof": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "tests",
++ "screenshots",
++ "review"
++ ],
++ "properties": {
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ },
++ "description": "The finished-task tests (Codes' proof)."
++ },
++ "screenshots": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "description": "The screenshots' media ids."
++ },
++ "review": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "verdict"
++ ],
++ "properties": {
++ "verdict": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 40
++ },
++ "notes": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2000
++ }
++ },
++ "description": "The second opinion, in one line, with its notes folded."
++ }
++ }
++ }
++ }
++}
ddiff --git a/fixtures/report.session-write-request/invalid/no-owner.json b/fixtures/report.session-write-request/invalid/no-owner.json
nnew file mode 100644
iindex 00000000..2ce4f3a9
---- /dev/null
++++ b/fixtures/report.session-write-request/invalid/no-owner.json
@@@ -0,0 +1,9 @@
++{
++ "source": "codes",
++ "task": { "title": "Ship the checkout page", "ref": "tsk_1" },
++ "started_at": "2026-11-06T18:00:00.000Z",
++ "ended_at": "2026-11-06T18:42:00.000Z",
++ "worked_seconds": 2520,
++ "outcome": "done",
++ "summary": "Asked for a checkout page."
++}
ddiff --git a/fixtures/report.session-write-request/valid/request.json b/fixtures/report.session-write-request/valid/request.json
nnew file mode 100644
iindex 00000000..2e84f0fe
---- /dev/null
++++ b/fixtures/report.session-write-request/valid/request.json
@@@ -0,0 +1,29 @@
++{
++ "owner": "usr_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "source": "codes",
++ "task": {
++ "title": "Ship the checkout page",
++ "ref": "tsk_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "url": "https://openvibe.codes/t/tsk_01JAN2C3D4E5F6G7H8J9K0MNPS"
++ },
++ "started_at": "2026-11-06T18:00:00.000Z",
++ "ended_at": "2026-11-06T18:42:00.000Z",
++ "worked_seconds": 2520,
++ "outcome": "done",
++ "summary": "Asked for a checkout page; the agent built it, ran the tests and opened a pull request.",
++ "timeline": [
++ { "at": "2026-11-06T18:20:00.000Z", "title": "Run the checkout tests", "status": "passed", "tests": { "passed": 12, "failed": 0 } }
++ ],
++ "outputs": [
++ { "kind": "pr", "url": "https://forgejo.example/openvibe/site/pulls/7", "title": "Checkout page", "state": "open" }
++ ],
++ "proof": {
++ "tests": { "passed": 12, "failed": 0 },
++ "screenshots": ["med_01JAN2C3D4E5F6G7H8J9K0MNPS"],
++ "review": { "verdict": "Looks good", "notes": null }
++ },
++ "cost_usd": 0.31,
++ "models": ["claude-sonnet-4"],
++ "highlights": ["Found the coupon bug on the first read"],
++ "visibility": "private"
++}
ddiff --git a/fixtures/report.session-write-result/invalid/url-not-report.json b/fixtures/report.session-write-result/invalid/url-not-report.json
nnew file mode 100644
iindex 00000000..c73ceaba
---- /dev/null
++++ b/fixtures/report.session-write-result/invalid/url-not-report.json
@@@ -0,0 +1,5 @@
++{
++ "id": "rps_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "url": "https://openvibe.example/s/rps_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "created": true
++}
ddiff --git a/fixtures/report.session-write-result/valid/result.json b/fixtures/report.session-write-result/valid/result.json
nnew file mode 100644
iindex 00000000..63bcab62
---- /dev/null
++++ b/fixtures/report.session-write-result/valid/result.json
@@@ -0,0 +1,5 @@
++{
++ "id": "rps_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "url": "https://openvibe.report/s/rps_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "created": true
++}
ddiff --git a/fixtures/report.session/invalid/id-not-rps.json b/fixtures/report.session/invalid/id-not-rps.json
nnew file mode 100644
iindex 00000000..2c00d913
---- /dev/null
++++ b/fixtures/report.session/invalid/id-not-rps.json
@@@ -0,0 +1,19 @@
++{
++ "id": "session_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "owner": "usr_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "source": "codes",
++ "task": { "title": "Ship the checkout page", "ref": "tsk_1" },
++ "started_at": "2026-11-06T18:00:00.000Z",
++ "ended_at": "2026-11-06T18:42:00.000Z",
++ "worked_seconds": 2520,
++ "outcome": "done",
++ "summary": "Asked for a checkout page.",
++ "timeline": [],
++ "outputs": [],
++ "proof": { "tests": { "passed": 1, "failed": 0 }, "screenshots": [], "review": null },
++ "cost_usd": 0.31,
++ "models": [],
++ "highlights": [],
++ "stream": null,
++ "visibility": "unlisted"
++}
ddiff --git a/fixtures/report.session/invalid/outcome-unknown.json b/fixtures/report.session/invalid/outcome-unknown.json
nnew file mode 100644
iindex 00000000..e06af7c7
---- /dev/null
++++ b/fixtures/report.session/invalid/outcome-unknown.json
@@@ -0,0 +1,19 @@
++{
++ "id": "rps_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "owner": "usr_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "source": "codes",
++ "task": { "title": "Ship the checkout page", "ref": "tsk_1" },
++ "started_at": "2026-11-06T18:00:00.000Z",
++ "ended_at": "2026-11-06T18:42:00.000Z",
++ "worked_seconds": 2520,
++ "outcome": "finished",
++ "summary": "Asked for a checkout page.",
++ "timeline": [],
++ "outputs": [],
++ "proof": { "tests": { "passed": 1, "failed": 0 }, "screenshots": [], "review": null },
++ "cost_usd": 0.31,
++ "models": [],
++ "highlights": [],
++ "stream": null,
++ "visibility": "unlisted"
++}
ddiff --git a/fixtures/report.session/valid/session.json b/fixtures/report.session/valid/session.json
nnew file mode 100644
iindex 00000000..7363ba73
---- /dev/null
++++ b/fixtures/report.session/valid/session.json
@@@ -0,0 +1,37 @@
++{
++ "id": "rps_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "owner": "usr_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "source": "codes",
++ "task": {
++ "title": "Ship the checkout page",
++ "ref": "tsk_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "url": "https://openvibe.codes/t/tsk_01JAN2C3D4E5F6G7H8J9K0MNPS"
++ },
++ "started_at": "2026-11-06T18:00:00.000Z",
++ "ended_at": "2026-11-06T18:42:00.000Z",
++ "worked_seconds": 2520,
++ "outcome": "done",
++ "summary": "Asked for a checkout page; the agent built it, ran the tests and opened a pull request.",
++ "timeline": [
++ { "at": "2026-11-06T18:01:00.000Z", "title": "Read the checkout code", "status": "passed" },
++ { "at": "2026-11-06T18:20:00.000Z", "title": "Run the checkout tests", "status": "passed", "tests": { "passed": 12, "failed": 0 } }
++ ],
++ "outputs": [
++ { "kind": "pr", "url": "https://forgejo.example/openvibe/site/pulls/7", "title": "Checkout page", "state": "open" }
++ ],
++ "proof": {
++ "tests": { "passed": 12, "failed": 0 },
++ "screenshots": ["med_01JAN2C3D4E5F6G7H8J9K0MNPS"],
++ "review": { "verdict": "Looks good", "notes": "The mobile layout needs a wider gutter." }
++ },
++ "cost_usd": 0.31,
++ "models": ["claude-sonnet-4"],
++ "highlights": [
++ "Found the coupon bug on the first read"
++ ],
++ "stream": {
++ "ags_id": "ags_01JAN2C3D4E5F6G7H8J9K0MNPS",
++ "vod_id": "vod_01JAN2C3D4E5F6G7H8J9K0MNPS"
++ },
++ "visibility": "unlisted"
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex ab3965f6..733893e8 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -103909,6 +103909,746 @@
}
}
}
++ },
++ "report.session": {
++ "version": "1.0.0",
++ "owner": "report",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/report/session.v1.json",
++ "title": "ReportSession",
++ "description": "report.session@1 (the Agent Streams plan, S3): the report of one agent session, whatever ran it - a Codes task, an Actor task, a desk session or a session on a person's own machine. OWNER is the person it belongs to, SOURCE where the work ran and TASK the task it is about, with a link back to it. TIMELINE holds the steps as they happened (the same shape as live.agent-stream-step@1). OUTPUTS are what came out (a pull request, files, pages, a deploy, a clip, the VOD). PROOF is Codes' finished-task proof: the tests, the screenshots and the review. COST_USD and MODELS say what it cost and which models ran. HIGHLIGHTS are up to five one-line moments. STREAM is the agent stream it streamed on, when it did. VISIBILITY is who may see it: private (the default), unlisted (anyone with the link) or public. NEVER IN A REPORT: the raw transcript (the source service keeps it for the owner, privately), secrets (the house redactor runs over every text field before anything is stored) and code or diffs (a link to the pull request is fine; its content shows only when the repository is public).",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "owner",
++ "source",
++ "task",
++ "started_at",
++ "ended_at",
++ "worked_seconds",
++ "outcome",
++ "summary",
++ "timeline",
++ "outputs",
++ "proof",
++ "cost_usd",
++ "models",
++ "highlights",
++ "stream",
++ "visibility"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^rps_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The report's id (ULID, Crockford base32)."
++ },
++ "owner": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The person the session was theirs."
++ },
++ "source": {
++ "enum": [
++ "codes",
++ "actor",
++ "desk",
++ "node"
++ ],
++ "description": "Where the session ran."
++ },
++ "task": {
++ "$ref": "#/$defs/task"
++ },
++ "started_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "ended_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "worked_seconds": {
++ "type": "integer",
++ "minimum": 0,
++ "description": "How long the agent worked (the page's 'worked 42 min')."
++ },
++ "outcome": {
++ "enum": [
++ "done",
++ "stopped",
++ "failed"
++ ],
++ "description": "How the session ended. A session that did not finish says why in stopped_because."
++ },
++ "stopped_because": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 300,
++ "description": "Why it stopped, in plain words. Present when the outcome is not done."
++ },
++ "summary": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 600,
++ "description": "What was asked and what happened, in plain words."
++ },
++ "timeline": {
++ "type": "array",
++ "items": {
++ "$ref": "#/$defs/step"
++ },
++ "description": "The steps, in the order they happened."
++ },
++ "outputs": {
++ "type": "array",
++ "items": {
++ "$ref": "#/$defs/output"
++ }
++ },
++ "proof": {
++ "$ref": "#/$defs/proof"
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0,
++ "description": "What the session cost, in dollars."
++ },
++ "models": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "description": "Which models ran."
++ },
++ "highlights": {
++ "type": "array",
++ "maxItems": 5,
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "description": "Up to five one-line moments."
++ },
++ "stream": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "ags_id"
++ ],
++ "properties": {
++ "ags_id": {
++ "type": "string",
++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "vod_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ }
++ },
++ "description": "The agent stream the session streamed on, when it did."
++ },
++ "visibility": {
++ "enum": [
++ "private",
++ "unlisted",
++ "public"
++ ]
++ }
++ },
++ "$defs": {
++ "task": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "title",
++ "ref"
++ ],
++ "properties": {
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200,
++ "description": "What the task was, in the person's own words."
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200,
++ "description": "The task's id in its source."
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri",
++ "description": "The task's page, when it has one."
++ }
++ }
++ },
++ "step": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "at",
++ "title",
++ "status"
++ ],
++ "properties": {
++ "at": {
++ "type": "string",
++ "format": "date-time",
++ "description": "When the step began."
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "status": {
++ "enum": [
++ "started",
++ "passed",
++ "failed",
++ "skipped"
++ ],
++ "description": "The same statuses as live.agent-stream-step@1."
++ },
++ "detail": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 500
++ },
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ }
++ }
++ },
++ "output": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title"
++ ],
++ "properties": {
++ "kind": {
++ "enum": [
++ "pr",
++ "file",
++ "page",
++ "deploy",
++ "clip",
++ "vod"
++ ],
++ "description": "What came out."
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "state": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 60,
++ "description": "A pull request's state ('open', 'merged'), when the source knows it."
++ }
++ }
++ },
++ "proof": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "tests",
++ "screenshots",
++ "review"
++ ],
++ "properties": {
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ },
++ "description": "The finished-task tests (Codes' proof)."
++ },
++ "screenshots": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "description": "The screenshots' media ids."
++ },
++ "review": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "verdict"
++ ],
++ "properties": {
++ "verdict": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 40
++ },
++ "notes": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2000
++ }
++ },
++ "description": "The second opinion, in one line, with its notes folded."
++ }
++ }
++ }
++ }
++ }
++ },
++ "report.session-write-request": {
++ "version": "1.0.0",
++ "owner": "report",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/report/session-write-request.v1.json",
++ "title": "ReportSessionWriteRequest",
++ "description": "report.session-write-request@1 (the Agent Streams plan, S3): the body of POST /internal/session-reports on OpenVibe.Report (capability report.session.write). The caller is a first-party service - Codes, Actor or Live - holding that capability for the audience openvibe.report; the body names the person the session was theirs. The route is idempotent per (SOURCE, TASK.REF): a repeat of the same session's task answers the report already stored, with created false. The report's id is Report's own (rps_<ULID>); the body never carries one. Every text field passes the house redactor before anything is stored, so no secret and no raw transcript is ever stored.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "owner",
++ "source",
++ "task",
++ "started_at",
++ "ended_at",
++ "worked_seconds",
++ "outcome",
++ "summary"
++ ],
++ "properties": {
++ "owner": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The person the session was theirs."
++ },
++ "source": {
++ "enum": [
++ "codes",
++ "actor",
++ "desk",
++ "node"
++ ]
++ },
++ "task": {
++ "$ref": "#/$defs/task"
++ },
++ "started_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "ended_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "worked_seconds": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "outcome": {
++ "enum": [
++ "done",
++ "stopped",
++ "failed"
++ ]
++ },
++ "stopped_because": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 300
++ },
++ "summary": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 600
++ },
++ "timeline": {
++ "type": "array",
++ "items": {
++ "$ref": "#/$defs/step"
++ }
++ },
++ "outputs": {
++ "type": "array",
++ "items": {
++ "$ref": "#/$defs/output"
++ }
++ },
++ "proof": {
++ "$ref": "#/$defs/proof"
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "models": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ }
++ },
++ "highlights": {
++ "type": "array",
++ "maxItems": 5,
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ }
++ },
++ "stream": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "ags_id"
++ ],
++ "properties": {
++ "ags_id": {
++ "type": "string",
++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "vod_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ }
++ }
++ },
++ "visibility": {
++ "enum": [
++ "private",
++ "unlisted",
++ "public"
++ ],
++ "description": "Who may see it. Absent means private."
++ },
++ "stream_only": {
++ "type": "boolean",
++ "description": "Live's stream-only report: the session is the stream itself and no tool will finish it. Absent or false means a normal session report."
++ }
++ },
++ "$defs": {
++ "task": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "title",
++ "ref"
++ ],
++ "properties": {
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ }
++ }
++ },
++ "step": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "at",
++ "title",
++ "status"
++ ],
++ "properties": {
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "status": {
++ "enum": [
++ "started",
++ "passed",
++ "failed",
++ "skipped"
++ ]
++ },
++ "detail": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 500
++ },
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ }
++ }
++ },
++ "output": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title"
++ ],
++ "properties": {
++ "kind": {
++ "enum": [
++ "pr",
++ "file",
++ "page",
++ "deploy",
++ "clip",
++ "vod"
++ ]
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "state": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 60
++ }
++ }
++ },
++ "proof": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "tests",
++ "screenshots",
++ "review"
++ ],
++ "properties": {
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "screenshots": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ }
++ },
++ "review": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "verdict"
++ ],
++ "properties": {
++ "verdict": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 40
++ },
++ "notes": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2000
++ }
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "report.session-write-result": {
++ "version": "1.0.0",
++ "owner": "report",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/report/session-write-result.v1.json",
++ "title": "ReportSessionWriteResult",
++ "description": "report.session-write-result@1: what POST /internal/session-reports on OpenVibe.Report answers. ID is the report's id, URL its page (openvibe.report/s/<id>) and CREATED says whether this call stored the report or found the one it had already stored (the route is idempotent per source and task ref).",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "url",
++ "created"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^rps_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "url": {
++ "type": "string",
++ "format": "uri",
++ "pattern": "^https://openvibe\\.report/s/"
++ },
++ "created": {
++ "type": "boolean",
++ "description": "True when this call stored the report, false when it was already there."
++ }
++ }
++ }
}
}
}
ddiff --git a/generated/openapi/actor.json b/generated/openapi/actor.json
iindex c3ff37ec..7ca1d1d7 100644
---- a/generated/openapi/actor.json
++++ b/generated/openapi/actor.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Actor API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Actor as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex 25a59fda..6953ad2a 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.299.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bench.json b/generated/openapi/bench.json
iindex c57d89fc..4b04a017 100644
---- a/generated/openapi/bench.json
++++ b/generated/openapi/bench.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Bench API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Bench as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 98cfb942..7dc5395d 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.299.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/blog.json b/generated/openapi/blog.json
iindex f4ea6b2a..079d09d1 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.299.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/bot.json b/generated/openapi/bot.json
iindex e76740c2..7f1a5cdb 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.299.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 19c40df1..e04c5df1 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.299.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 44d99e3a..35c62b9e 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.299.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 5c3bab5d..6d7b389f 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.299.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 43b0f19a..46624748 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.299.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 1ad85d28..9c2a167e 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.299.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/domains.json b/generated/openapi/domains.json
iindex 3326c15f..b2f74560 100644
---- a/generated/openapi/domains.json
++++ b/generated/openapi/domains.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Domains API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Domains as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 2b4b1e5d..44a5ba0d 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.299.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/food.json b/generated/openapi/food.json
iindex d5b41852..68c7489d 100644
---- a/generated/openapi/food.json
++++ b/generated/openapi/food.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Food API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Food as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 a8d0516a..348ce62d 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.299.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 663bd452..4874f59d 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.299.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.300.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/index.json b/generated/openapi/index.json
iindex 276913fd..7523e825 100644
---- a/generated/openapi/index.json
++++ b/generated/openapi/index.json
@@@ -180,8 +180,8 @@
"service": "report",
"name": "OpenVibe.Report",
"origin": "https://openvibe.report",
-- "operations": 6,
-- "capabilities": 2
++ "operations": 7,
++ "capabilities": 3
},
{
"service": "reviews",
ddiff --git a/generated/openapi/inventory.json b/generated/openapi/inventory.json
iindex a17abc6d..ed2d99d9 100644
---- a/generated/openapi/inventory.json
++++ b/generated/openapi/inventory.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Inventory API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Inventory as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 a419fcb1..ac89f685 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.299.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/media-hub.json b/generated/openapi/media-hub.json
iindex 13fa03be..b01c8602 100644
---- a/generated/openapi/media-hub.json
++++ b/generated/openapi/media-hub.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.MediaHub API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.MediaHub as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 4b1970a0..e952ddd7 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.299.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 557c1a69..6da4190d 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.299.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 ab239149..f89b05ab 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.299.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 99d0514e..3294e5b3 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRestream API",
-- "version": "0.299.0",
-- "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenRestream as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/play.json b/generated/openapi/play.json
iindex faa4e3de..490578db 100644
---- a/generated/openapi/play.json
++++ b/generated/openapi/play.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Play API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Play as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/quest.json b/generated/openapi/quest.json
iindex 2b0c0535..fafa5a0e 100644
---- a/generated/openapi/quest.json
++++ b/generated/openapi/quest.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Quest API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Quest as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/report.json b/generated/openapi/report.json
iindex a4c29de4..54e76715 100644
---- a/generated/openapi/report.json
++++ b/generated/openapi/report.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Report API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Report as the OpenVibe contracts describe them (openvibe-contracts 0.300.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"
@@@ -542,6 +542,62 @@
}
}
}
++ },
++ "/internal/session-reports": {
++ "post": {
++ "operationId": "post_internal_session_reports",
++ "summary": "Write one agent session's report on OpenVibe.Report (the Agent Streams plan, S3).",
++ "description": "**report.session.write** (first-party): Write one agent session's report on OpenVibe.Report (the Agent Streams plan, S3). POST /internal/session-reports stores the report of a Codes task, an Actor task, a desk session or a session on a person's own machine, and answers the report's page. The route is idempotent per (source, task ref): the same session's task always answers the same report. The caller is a first-party service - Codes, Actor or Live - with a service token that holds this capability for the audience openvibe.report; Network grants it to exactly those principals. The body names the person the session was theirs, and a service may only write a report for the person it acts for. Every text field passes the house redactor before anything is stored: the raw transcript and secrets never reach the report.",
++ "tags": [
++ "report.session"
++ ],
++ "x-openvibe-capabilities": [
++ "report.session.write"
++ ],
++ "x-openvibe-visibility": [
++ "first-party"
++ ],
++ "x-openvibe-quota-class": "standard",
++ "security": [
++ {
++ "openvibeToken": [
++ "report.session.write"
++ ]
++ }
++ ],
++ "requestBody": {
++ "required": false,
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/report.session-write-request.v1"
++ }
++ }
++ }
++ },
++ "responses": {
++ "2XX": {
++ "description": "Success",
++ "content": {
++ "application/json": {
++ "schema": {
++ "$ref": "#/components/schemas/report.session-write-result.v1"
++ }
++ }
++ }
++ },
++ "default": {
++ "description": "An error (RFC 9457 problem details)",
++ "content": {
++ "application/problem+json": {
++ "schema": {
++ "$ref": "#/components/schemas/errors.problem.v1"
++ }
++ }
++ }
++ }
++ }
++ }
}
},
"components": {
@@@ -1352,6 +1408,364 @@
}
}
}
++ },
++ "report.session-write-request.v1": {
++ "title": "ReportSessionWriteRequest",
++ "description": "report.session-write-request@1 (the Agent Streams plan, S3): the body of POST /internal/session-reports on OpenVibe.Report (capability report.session.write). The caller is a first-party service - Codes, Actor or Live - holding that capability for the audience openvibe.report; the body names the person the session was theirs. The route is idempotent per (SOURCE, TASK.REF): a repeat of the same session's task answers the report already stored, with created false. The report's id is Report's own (rps_<ULID>); the body never carries one. Every text field passes the house redactor before anything is stored, so no secret and no raw transcript is ever stored.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "owner",
++ "source",
++ "task",
++ "started_at",
++ "ended_at",
++ "worked_seconds",
++ "outcome",
++ "summary"
++ ],
++ "properties": {
++ "owner": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The person the session was theirs."
++ },
++ "source": {
++ "enum": [
++ "codes",
++ "actor",
++ "desk",
++ "node"
++ ]
++ },
++ "task": {
++ "$ref": "#/components/schemas/report.session-write-request.v1/$defs/task"
++ },
++ "started_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "ended_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "worked_seconds": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "outcome": {
++ "enum": [
++ "done",
++ "stopped",
++ "failed"
++ ]
++ },
++ "stopped_because": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 300
++ },
++ "summary": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 600
++ },
++ "timeline": {
++ "type": "array",
++ "items": {
++ "$ref": "#/components/schemas/report.session-write-request.v1/$defs/step"
++ }
++ },
++ "outputs": {
++ "type": "array",
++ "items": {
++ "$ref": "#/components/schemas/report.session-write-request.v1/$defs/output"
++ }
++ },
++ "proof": {
++ "$ref": "#/components/schemas/report.session-write-request.v1/$defs/proof"
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "models": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ }
++ },
++ "highlights": {
++ "type": "array",
++ "maxItems": 5,
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ }
++ },
++ "stream": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "ags_id"
++ ],
++ "properties": {
++ "ags_id": {
++ "type": "string",
++ "pattern": "^ags_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "vod_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 120
++ }
++ }
++ },
++ "visibility": {
++ "enum": [
++ "private",
++ "unlisted",
++ "public"
++ ],
++ "description": "Who may see it. Absent means private."
++ },
++ "stream_only": {
++ "type": "boolean",
++ "description": "Live's stream-only report: the session is the stream itself and no tool will finish it. Absent or false means a normal session report."
++ }
++ },
++ "$defs": {
++ "task": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "title",
++ "ref"
++ ],
++ "properties": {
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "ref": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ }
++ }
++ },
++ "step": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "at",
++ "title",
++ "status"
++ ],
++ "properties": {
++ "at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "status": {
++ "enum": [
++ "started",
++ "passed",
++ "failed",
++ "skipped"
++ ]
++ },
++ "detail": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 500
++ },
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "cost_usd": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ }
++ }
++ },
++ "output": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "kind",
++ "title"
++ ],
++ "properties": {
++ "kind": {
++ "enum": [
++ "pr",
++ "file",
++ "page",
++ "deploy",
++ "clip",
++ "vod"
++ ]
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ },
++ "title": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ },
++ "state": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 60
++ }
++ }
++ },
++ "proof": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "tests",
++ "screenshots",
++ "review"
++ ],
++ "properties": {
++ "tests": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "passed",
++ "failed"
++ ],
++ "properties": {
++ "passed": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "failed": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ },
++ "screenshots": {
++ "type": "array",
++ "items": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 200
++ }
++ },
++ "review": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "required": [
++ "verdict"
++ ],
++ "properties": {
++ "verdict": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 40
++ },
++ "notes": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "maxLength": 2000
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "report.session-write-result.v1": {
++ "title": "ReportSessionWriteResult",
++ "description": "report.session-write-result@1: what POST /internal/session-reports on OpenVibe.Report answers. ID is the report's id, URL its page (openvibe.report/s/<id>) and CREATED says whether this call stored the report or found the one it had already stored (the route is idempotent per source and task ref).",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "url",
++ "created"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^rps_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "url": {
++ "type": "string",
++ "format": "uri",
++ "pattern": "^https://openvibe\\.report/s/"
++ },
++ "created": {
++ "type": "boolean",
++ "description": "True when this call stored the report, false when it was already there."
++ }
++ }
}
},
"securitySchemes": {
ddiff --git a/generated/openapi/reviews.json b/generated/openapi/reviews.json
iindex 2af338f7..3346ec66 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.299.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/run.json b/generated/openapi/run.json
iindex e25697e3..285e8d28 100644
---- a/generated/openapi/run.json
++++ b/generated/openapi/run.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Run API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Run as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 f7c265a9..3b3527da 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.299.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/services.json b/generated/openapi/services.json
iindex fc37d66c..93a996c2 100644
---- a/generated/openapi/services.json
++++ b/generated/openapi/services.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Services API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Services as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 5e65008b..2811001d 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.299.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 02950b2d..1d2a0e60 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.299.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 c5743f0e..a17b5268 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.299.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/today.json b/generated/openapi/today.json
iindex cb249518..5803da47 100644
---- a/generated/openapi/today.json
++++ b/generated/openapi/today.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Today API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Today as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 b474e2e0..63b98870 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.299.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 79caa775..82c55aff 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.299.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 00d998f1..18520e54 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.299.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/vision.json b/generated/openapi/vision.json
iindex 5713645a..b93f5ad4 100644
---- a/generated/openapi/vision.json
++++ b/generated/openapi/vision.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Vision API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Vision as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/watch.json b/generated/openapi/watch.json
iindex de4c6af5..8a010fa0 100644
---- a/generated/openapi/watch.json
++++ b/generated/openapi/watch.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Watch API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Watch as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 03e867ce..d006e236 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.299.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/work.json b/generated/openapi/work.json
iindex 56375a47..7e708d98 100644
---- a/generated/openapi/work.json
++++ b/generated/openapi/work.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Work API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Work as the OpenVibe contracts describe them (openvibe-contracts 0.300.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/zone.json b/generated/openapi/zone.json
iindex 5652298a..cb237d9e 100644
---- a/generated/openapi/zone.json
++++ b/generated/openapi/zone.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenVibe.Zone API",
-- "version": "0.299.0",
-- "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.299.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.300.0",
++ "description": "Routes of OpenVibe.Zone as the OpenVibe contracts describe them (openvibe-contracts 0.300.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 c37d8b9b..b61d142f 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -292454,3 +292454,222 @@ export interface LiveAgentStreamChangedPayload {
};
at: string;
}
++
++/** [email protected] (owner: report) */
++/**
++ * report.session@1 (the Agent Streams plan, S3): the report of one agent session, whatever ran it - a Codes task, an Actor task, a desk session or a session on a person's own machine. OWNER is the person it belongs to, SOURCE where the work ran and TASK the task it is about, with a link back to it. TIMELINE holds the steps as they happened (the same shape as live.agent-stream-step@1). OUTPUTS are what came out (a pull request, files, pages, a deploy, a clip, the VOD). PROOF is Codes' finished-task proof: the tests, the screenshots and the review. COST_USD and MODELS say what it cost and which models ran. HIGHLIGHTS are up to five one-line moments. STREAM is the agent stream it streamed on, when it did. VISIBILITY is who may see it: private (the default), unlisted (anyone with the link) or public. NEVER IN A REPORT: the raw transcript (the source service keeps it for the owner, privately), secrets (the house redactor runs over every text field before anything is stored) and code or diffs (a link to the pull request is fine; its content shows only when the repository is public).
++ */
++export interface ReportSession {
++ /**
++ * The report's id (ULID, Crockford base32).
++ */
++ id: string;
++ /**
++ * The person the session was theirs.
++ */
++ owner: string;
++ /**
++ * Where the session ran.
++ */
++ source: "codes" | "actor" | "desk" | "node";
++ task: {
++ /**
++ * What the task was, in the person's own words.
++ */
++ title: string;
++ /**
++ * The task's id in its source.
++ */
++ ref: string;
++ /**
++ * The task's page, when it has one.
++ */
++ url?: string | null;
++ };
++ started_at: string;
++ ended_at: string;
++ /**
++ * How long the agent worked (the page's 'worked 42 min').
++ */
++ worked_seconds: number;
++ /**
++ * How the session ended. A session that did not finish says why in stopped_because.
++ */
++ outcome: "done" | "stopped" | "failed";
++ /**
++ * Why it stopped, in plain words. Present when the outcome is not done.
++ */
++ stopped_because?: string;
++ /**
++ * What was asked and what happened, in plain words.
++ */
++ summary: string;
++ /**
++ * The steps, in the order they happened.
++ */
++ timeline: {
++ /**
++ * When the step began.
++ */
++ at: string;
++ title: string;
++ /**
++ * The same statuses as live.agent-stream-step@1.
++ */
++ status: "started" | "passed" | "failed" | "skipped";
++ detail?: string | null;
++ tests?: {
++ passed: number;
++ failed: number;
++ } | null;
++ cost_usd?: number | null;
++ }[];
++ outputs: {
++ /**
++ * What came out.
++ */
++ kind: "pr" | "file" | "page" | "deploy" | "clip" | "vod";
++ url?: string | null;
++ title: string;
++ /**
++ * A pull request's state ('open', 'merged'), when the source knows it.
++ */
++ state?: string | null;
++ }[];
++ proof: {
++ /**
++ * The finished-task tests (Codes' proof).
++ */
++ tests: {
++ passed: number;
++ failed: number;
++ } | null;
++ /**
++ * The screenshots' media ids.
++ */
++ screenshots: string[];
++ /**
++ * The second opinion, in one line, with its notes folded.
++ */
++ review: {
++ verdict: string;
++ notes?: string | null;
++ } | null;
++ };
++ /**
++ * What the session cost, in dollars.
++ */
++ cost_usd: number | null;
++ /**
++ * Which models ran.
++ */
++ models: string[];
++ /**
++ * Up to five one-line moments.
++ *
++ * @maxItems 5
++ */
++ highlights:
++ | []
++ | [string]
++ | [string, string]
++ | [string, string, string]
++ | [string, string, string, string]
++ | [string, string, string, string, string];
++ /**
++ * The agent stream the session streamed on, when it did.
++ */
++ stream: {
++ ags_id: string;
++ vod_id?: string | null;
++ } | null;
++ visibility: "private" | "unlisted" | "public";
++}
++
++/** [email protected] (owner: report) */
++/**
++ * report.session-write-request@1 (the Agent Streams plan, S3): the body of POST /internal/session-reports on OpenVibe.Report (capability report.session.write). The caller is a first-party service - Codes, Actor or Live - holding that capability for the audience openvibe.report; the body names the person the session was theirs. The route is idempotent per (SOURCE, TASK.REF): a repeat of the same session's task answers the report already stored, with created false. The report's id is Report's own (rps_<ULID>); the body never carries one. Every text field passes the house redactor before anything is stored, so no secret and no raw transcript is ever stored.
++ */
++export interface ReportSessionWriteRequest {
++ /**
++ * The person the session was theirs.
++ */
++ owner: string;
++ source: "codes" | "actor" | "desk" | "node";
++ task: {
++ title: string;
++ ref: string;
++ url?: string | null;
++ };
++ started_at: string;
++ ended_at: string;
++ worked_seconds: number;
++ outcome: "done" | "stopped" | "failed";
++ stopped_because?: string;
++ summary: string;
++ timeline?: {
++ at: string;
++ title: string;
++ status: "started" | "passed" | "failed" | "skipped";
++ detail?: string | null;
++ tests?: {
++ passed: number;
++ failed: number;
++ } | null;
++ cost_usd?: number | null;
++ }[];
++ outputs?: {
++ kind: "pr" | "file" | "page" | "deploy" | "clip" | "vod";
++ url?: string | null;
++ title: string;
++ state?: string | null;
++ }[];
++ proof?: {
++ tests: {
++ passed: number;
++ failed: number;
++ } | null;
++ screenshots: string[];
++ review: {
++ verdict: string;
++ notes?: string | null;
++ } | null;
++ };
++ cost_usd?: number | null;
++ models?: string[];
++ /**
++ * @maxItems 5
++ */
++ highlights?:
++ | []
++ | [string]
++ | [string, string]
++ | [string, string, string]
++ | [string, string, string, string]
++ | [string, string, string, string, string];
++ stream?: {
++ ags_id: string;
++ vod_id?: string | null;
++ } | null;
++ /**
++ * Who may see it. Absent means private.
++ */
++ visibility?: "private" | "unlisted" | "public";
++ /**
++ * Live's stream-only report: the session is the stream itself and no tool will finish it. Absent or false means a normal session report.
++ */
++ stream_only?: boolean;
++}
++
++/** [email protected] (owner: report) */
++/**
++ * report.session-write-result@1: what POST /internal/session-reports on OpenVibe.Report answers. ID is the report's id, URL its page (openvibe.report/s/<id>) and CREATED says whether this call stored the report or found the one it had already stored (the route is idempotent per source and task ref).
++ */
++export interface ReportSessionWriteResult {
++ id: string;
++ url: string;
++ /**
++ * True when this call stored the report, false when it was already there.
++ */
++ created: boolean;
++}
ddiff --git a/manifests/capabilities/report.session.write.json b/manifests/capabilities/report.session.write.json
nnew file mode 100644
iindex 00000000..bfd1122c
---- /dev/null
++++ b/manifests/capabilities/report.session.write.json
@@@ -0,0 +1,22 @@
++{
++ "id": "report.session.write",
++ "version": "1.0",
++ "owner": "report",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Write one agent session's report on OpenVibe.Report (the Agent Streams plan, S3). POST /internal/session-reports stores the report of a Codes task, an Actor task, a desk session or a session on a person's own machine, and answers the report's page. The route is idempotent per (source, task ref): the same session's task always answers the same report. The caller is a first-party service - Codes, Actor or Live - with a service token that holds this capability for the audience openvibe.report; Network grants it to exactly those principals. The body names the person the session was theirs, and a service may only write a report for the person it acts for. Every text field passes the house redactor before anything is stored: the raw transcript and secrets never reach the report.",
++ "inputSchema": "report.session-write-request@1",
++ "outputSchema": "report.session-write-result@1",
++ "permissions": [
++ "report:write"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "standard",
++ "events": [],
++ "implementedBy": [
++ "POST /internal/session-reports"
++ ],
++ "sensitive": true
++}
ddiff --git a/manifests/services/report.json b/manifests/services/report.json
iindex 6f54a24f..210108a3 100644
---- a/manifests/services/report.json
++++ b/manifests/services/report.json
@@@ -17,7 +17,8 @@
},
"capabilities": [
"report.ai_usage.read",
-- "report.config.manage"
++ "report.config.manage",
++ "report.session.write"
],
"eventsProduced": [
"report.index_document.deleted",
ddiff --git a/package.json b/package.json
iindex 7d9cf3b2..03a86957 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.299.0",
++ "version": "0.300.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",