openvibers/openvibe.contracts Commits

Watch contracts, events, capabilities and placeholder service manifest (planned); document runtime:<class>; release 0.102.0 (#47)

OP OpenVibers committed 5 Oct 2026 · 4bae5c93b8 · 64 files, +5002 −61

Release 0.102.0 is complete. Here is the change list and verification.

**Schemas (all new, planned, owner `watch`, first-party)**
- `contracts/watch/watch.v1.json:1` — `watch.watch@1` (source/extraction/comparison/condition/actions/budget/retention); source/cadence/extraction/comparison/condition/action/budget/retention live in `$defs` so the request reuses them.
- `contracts/watch/watch-request.v1.json:1` — `watch.watch-request@1` (create/patch body; every field optional, create rules in code).
- `contracts/watch/watch-result.v1.json:1` — `watch.watch-result@1` (`{watches}`/`{watch}`/`{id,status}`/`{id,deleted:true}`).
- `contracts/watch/observation.v1.json:1` — `watch.observation@1` (immutable observation).
- `contracts/watch/check-run.v1.json:1` — `watch.check-run@1` (immutable run; the migration's 12 terminal states).
- `contracts/events/payloads/watch.observation.recorded.v1.json:1` — subject `{watch}`, internal, low, `service:watch`.
- `contracts/events/payloads/watch.watch.triggered.v1.json:1` — subject `{watch}`, internal, important; Network → `WATCH_TRIGGERED` for `recipient`.
- `contracts/events/payloads/watch.check.failed.v1.json:1` — internal, normal, `consecutive_failures`.

**Fixtures** (valid + invalid each): `fixtures/watch.watch/{valid/price-threshold,invalid/missing-owner}.json:1`, `fixtures/watch.watch-request/{valid/create-event-watch,invalid/unknown-status}.json:1`, `fixtures/watch.watch-result/{valid/paused,invalid/not-deleted}.json:1`, `fixtures/watch.observation/{valid/price-changed,invalid/missing-check-run}.json:1`, `fixtures/watch.check-run/{valid/http-changed,invalid/unknown-state}.json:1`, `fixtures/watch.observation.recorded/{valid/price-changed,invalid/missing-owner}.json:1`, `fixtures/watch.watch.triggered/{valid/price-below,invalid/missing-observation}.json:1`, `fixtures/watch.check.failed/{valid/http-error,invalid/zero-failures}.json:1`.

**Catalog / manifests / docs / release**
- `contracts/catalog.json:4190` — the 8 entries, status `planned`, inserted at the end of the `trade.*` block.
- `manifests/capabilities/watch.watch.read.json:1`, `watch.watch.manage.json:1`, `watch.observation.read.json:1`, `watch.check.run.json:1` — planned; `inputSchema`/`outputSchema` (`common.no-body@1`, `watch.watch-request@1`, `watch.watch-result@1`, `watch.observation@1`, `watch.check-run@1`); `implementedBy` empty (no routes exist).
- `manifests/services/watch.json:1` — placeholder like `run.json` (no site/health/internalOrigin; lifecycle all `none`; `>=0.102.0 <1.0.0`).
- `manifests/products/openvibe.watch.json:30` — `relationships.service: "watch"` (needed so `product-catalog.test.js` sees one service serving the domain, exactly as `openvibe.run`→`run`).
- `contracts/platform/resource-offer.v1.json:69` — `capabilities` description now documents `runtime:<class>` for a kind harness beside the reserved `worker:<class>` names (docs-only).
- `CHANGELOG.md:7`, `STATUS.json:12,26`, `package.json:3`, `package-lock.json:3,9` — 0.102.0 release entry/line/feature/version, as the 0.101.0 commit did.
- `generated/` — `npm run generate`: 26 OpenAPI docs (version line), `json-schema/bundle.json`, `typescript/index.d.ts`; no `openapi/watch.json` (planned capabilities are excluded).
- `lib/ids.js:9` — **untouched**: `watch:'wch'`, `observation:'wco'`, `check:'ckr'` were already present.

**Repo-convention deviations from the dossier (stated as requested)**
- The dossier's `watch.triggered` became **`watch.watch.triggered`** (file an

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 192b9da7..23cf4b82 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,28 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
++## 0.102.0 — 2026-10-05
++
++**The Watch contracts** (plan T18). Additive: eight new planned contracts, four planned capabilities and the Watch placeholder manifest, no existing schema changed.
++- `watch.watch@1` (new, owner `watch`, first-party, **planned**): a user-defined persistent observation — a source (a push event, a
++ webhook, a conditional HTTP URL, a feed or API, a local Node probe, or a Run check), how a value is extracted, how it is compared with
++ the last observation, the condition that fires, the actions it wakes (notification, event, webhook, Actor task, Codes run, Run job),
++ its budget and retention. Valid and invalid fixtures in `fixtures/watch.watch/`.
++- `watch.watch-request@1` (the create/patch body), `watch.watch-result@1` (the list/watch and pause/resume/delete answers),
++ `watch.observation@1` (one recorded value, immutable) and `watch.check-run@1` (one check execution, immutable, with the twelve
++ terminal states the service's `check_runs.state` CHECK allows), each with fixtures. The request reuses `watch.watch@1`'s `$defs`
++ rather than restating the source and condition shapes.
++- Events: `watch.observation.recorded` (subject `watch`, internal, low), `watch.watch.triggered` (internal, important; Network turns
++ it into a `WATCH_TRIGGERED` notification for `payload.recipient`) and `watch.check.failed` (internal, normal, with
++ `consecutive_failures`). **The dossier's `watch.triggered` is named `watch.watch.triggered` here**: the repo's event-type pattern
++ (`test/run.js:123`) requires at least three dot-separated segments, as every existing type has.
++- Capabilities `watch.watch.read`, `watch.watch.manage`, `watch.observation.read` and `watch.check.run` (all planned, first-party),
++ and `manifests/services/watch.json`, a placeholder like Run's: the OpenVibe.Watch repository does not exist yet, so nothing is
++ built. `manifests/products/openvibe.watch.json` now names `watch` as its service, as `openvibe.run` names `run`.
++- `contracts/platform/resource-offer.v1.json`: the `capabilities` description now documents `runtime:<class>` for a kind harness
++ beside the reserved `worker:<class>` names (a docs-only change; Codes already advertises them). `lib/ids.js` already carried
++ `watch`/`observation`/`check`, so it is untouched.
++
## 0.101.0 — 2026-10-05
**The task contract** (plan T17, ADR-044). Additive: one new planned contract and its ADR, no existing schema changed.
ddiff --git a/STATUS.json b/STATUS.json
iindex 8ec4b88d..e2fa395b 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -3,11 +3,13 @@
"stage": "alpha",
"code": true,
"wave": "W1",
-- "dependsOn": ["OpenVibe.Network"],
++ "dependsOn": [
++ "OpenVibe.Network"
++ ],
"plan": "OpenVibe Development Roadmap (combined), Wave 1; implementation plan rev 3 section 3.1",
"deployed": false,
"deployment": "none of its own: a library and artifact repository published as release tags; services pin a tag and deploy it with their own releases",
-- "contracts": "openvibe-contracts v0.101.0 (this package; the newest tag)",
++ "contracts": "openvibe-contracts v0.102.0 (this package; the newest tag)",
"features": [
"589 JSON Schemas with valid and invalid fixtures",
"31 service manifests with lifecycle declarations",
@@@ -20,7 +22,8 @@
"documentation-currency check (scripts/docs-currency.js)",
"generated estate: docs/ESTATE.md and manifests/repositories/ from the checkouts (scripts/estate.js; --check fails on drift)",
"chat.ticket-conversation@1 and the planned chat.ticket.write capability: a per-ticket conversation keyed by ticket id and calling service, with author_kind person|agent|staff",
-- "platform.task@1 (planned, owner network) and ADR-044: one task at OpenVibe.Actor's router with a mode, a per-task and per-day budget, result, cost and explanation, SSE progress, cancel and webhooks"
++ "platform.task@1 (planned, owner network) and ADR-044: one task at OpenVibe.Actor's router with a mode, a per-task and per-day budget, result, cost and explanation, SSE progress, cancel and webhooks",
++ "watch.watch@1 and the other Watch contracts (plan T18, planned), three watch events, four capabilities and the placeholder service manifest: user-defined persistent observations over pages, feeds, APIs, events and devices"
],
"updated": "2026-10-05"
}
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex 0275a5ae..1acf461d 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -4186,6 +4186,78 @@
"compatibility": "backward",
"status": "active"
},
++ {
++ "id": "watch.watch",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "watch/watch.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "planned"
++ },
++ {
++ "id": "watch.watch-request",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "watch/watch-request.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "planned"
++ },
++ {
++ "id": "watch.watch-result",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "watch/watch-result.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "planned"
++ },
++ {
++ "id": "watch.observation",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "watch/observation.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "planned"
++ },
++ {
++ "id": "watch.check-run",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "watch/check-run.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "planned"
++ },
++ {
++ "id": "watch.observation.recorded",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "events/payloads/watch.observation.recorded.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "planned"
++ },
++ {
++ "id": "watch.watch.triggered",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "events/payloads/watch.watch.triggered.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "planned"
++ },
++ {
++ "id": "watch.check.failed",
++ "version": "1.0.0",
++ "owner": "watch",
++ "schema": "events/payloads/watch.check.failed.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "planned"
++ },
{
"id": "games.player.joined",
"version": "1.0.0",
ddiff --git a/contracts/events/payloads/watch.check.failed.v1.json b/contracts/events/payloads/watch.check.failed.v1.json
nnew file mode 100644
iindex 00000000..bd25c3f9
---- /dev/null
++++ b/contracts/events/payloads/watch.check.failed.v1.json
@@@ -0,0 +1,17 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.check.failed.v1.json",
++ "title": "WatchCheckFailedPayload",
++ "description": "watch.check.failed v1 (OpenVibe.Watch, plan T18): a check ended in a failure state. consecutive_failures is how many runs in a row have failed, so a consumer can tell a blip from a watch that is down. Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority normal, actor service:watch.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["watch_id", "state", "carrier", "http_status", "error_code", "consecutive_failures"],
++ "properties": {
++ "watch_id": { "type": "string", "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "state": { "enum": ["http_error", "timeout", "parse_error", "rate_limited", "budget_exceeded", "skipped", "disabled"] },
++ "carrier": { "type": ["string", "null"], "enum": ["event", "webhook", "http", "feed", "api", "node", "run", null] },
++ "http_status": { "type": ["integer", "null"] },
++ "error_code": { "type": ["string", "null"] },
++ "consecutive_failures": { "type": "integer", "minimum": 1 }
++ }
++}
ddiff --git a/contracts/events/payloads/watch.observation.recorded.v1.json b/contracts/events/payloads/watch.observation.recorded.v1.json
nnew file mode 100644
iindex 00000000..f0349c0e
---- /dev/null
++++ b/contracts/events/payloads/watch.observation.recorded.v1.json
@@@ -0,0 +1,18 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.observation.recorded.v1.json",
++ "title": "WatchObservationRecordedPayload",
++ "description": "watch.observation.recorded v1 (OpenVibe.Watch, plan T18): a check recorded an observation for a watch. It carries the extracted value as the source stated it and its hash, never the raw body. Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority low, actor service:watch. Watch's own records are the full observation (watch.observation@1); this event is the notification that one exists.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["watch_id", "owner", "observed_at", "value", "value_hash", "changed", "condition_met"],
++ "properties": {
++ "watch_id": { "type": "string", "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "owner": { "type": "string", "pattern": "^(usr|agt)_[0-9A-HJKMNP-TV-Z]{26}$", "description": "The watch owner's subject id: who this observation is for." },
++ "observed_at": { "type": "string", "format": "date-time" },
++ "value": { "description": "The extracted value as the source stated it; null when it stated none." },
++ "value_hash": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "SHA-256 hex of the canonical value." },
++ "changed": { "type": "boolean" },
++ "condition_met": { "type": "boolean" }
++ }
++}
ddiff --git a/contracts/events/payloads/watch.watch.triggered.v1.json b/contracts/events/payloads/watch.watch.triggered.v1.json
nnew file mode 100644
iindex 00000000..d5982ee2
---- /dev/null
++++ b/contracts/events/payloads/watch.watch.triggered.v1.json
@@@ -0,0 +1,28 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.watch.triggered.v1.json",
++ "title": "WatchTriggeredPayload",
++ "description": "watch.watch.triggered v1 (OpenVibe.Watch, plan T18; the dossier's watch.triggered, named with three segments as every event type is here — the repo's event-type pattern requires at least three): a watch's condition fired. OpenVibe.Network turns it into a WATCH_TRIGGERED notification for payload.recipient (mirrors deals.watch.matched). Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority important, actor service:watch.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["watch_id", "recipient", "project_id", "name", "condition", "observation", "fired_at"],
++ "properties": {
++ "watch_id": { "type": "string", "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "recipient": { "type": "string", "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$", "description": "The watch owner's user subject id: who is notified." },
++ "project_id": { "type": ["string", "null"], "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "name": { "type": "string", "minLength": 1, "maxLength": 120 },
++ "condition": { "$ref": "../../watch/watch.v1.json#/$defs/condition" },
++ "observation": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["id", "observed_at", "value", "previous_value"],
++ "properties": {
++ "id": { "type": "string", "pattern": "^wco_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "observed_at": { "type": "string", "format": "date-time" },
++ "value": { "description": "The value that fired the condition." },
++ "previous_value": { "description": "The previous observation's value; null when there was none." }
++ }
++ },
++ "fired_at": { "type": "string", "format": "date-time" }
++ }
++}
ddiff --git a/contracts/platform/resource-offer.v1.json b/contracts/platform/resource-offer.v1.json
iindex d3681973..63f0b91d 100644
---- a/contracts/platform/resource-offer.v1.json
++++ b/contracts/platform/resource-offer.v1.json
@@@ -66,7 +66,7 @@
"type": "string",
"pattern": "^[a-z][a-z0-9-]*:[a-z0-9.-]+$"
},
-- "description": "e.g. node:http, worker:browser, worker:ffmpeg, worker:ai-gpu, events:gateway, events:durable, object:r2. Kind harness: task:edit, task:review, task:browse, task:run, task:test and task:plan for the task kinds it takes (its detail's task_capabilities), and harness:mcp, harness:resume, harness:host-access and harness:long-autonomy for its detail's capabilities that are true. The `worker:<class>` names that map to platform.runtime-class@1 values are reserved for OpenVibe.Node's job worker, one per class: worker:function, worker:code, worker:browser, worker:linux, worker:desktop and worker:gpu ($defs.reservedWorkerCapabilities). A node advertises the name of each class it runs (Node's status.capabilities.worker); every other `worker:` name (worker:ffmpeg, worker:ai-gpu) is an ordinary capability name."
++ "description": "e.g. node:http, worker:browser, worker:ffmpeg, worker:ai-gpu, events:gateway, events:durable, object:r2. Kind harness: task:edit, task:review, task:browse, task:run, task:test and task:plan for the task kinds it takes (its detail's task_capabilities), and harness:mcp, harness:resume, harness:host-access and harness:long-autonomy for its detail's capabilities that are true. The `worker:<class>` names that map to platform.runtime-class@1 values are reserved for OpenVibe.Node's job worker, one per class: worker:function, worker:code, worker:browser, worker:linux, worker:desktop and worker:gpu ($defs.reservedWorkerCapabilities). A node advertises the name of each class it runs (Node's status.capabilities.worker); every other `worker:` name (worker:ffmpeg, worker:ai-gpu) is an ordinary capability name. Beside them, a kind harness names `runtime:<class>` for each platform.runtime-class@1 class it can run (runtime:function, runtime:code, runtime:browser, runtime:linux, runtime:desktop, runtime:gpu); these are ordinary capability names, not reserved, and OpenVibe.Codes already advertises the classes it offers."
},
"capacity": {
"type": "object",
ddiff --git a/contracts/watch/check-run.v1.json b/contracts/watch/check-run.v1.json
nnew file mode 100644
iindex 00000000..f7564435
---- /dev/null
++++ b/contracts/watch/check-run.v1.json
@@@ -0,0 +1,23 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/check-run.v1.json",
++ "title": "WatchCheckRun",
++ "description": "watch.check-run@1: one execution of a watch's check (plan T18), by schedule, manually, or from a delivered event or webhook. carrier names the mechanism that carried it; state is the terminal state (the same values the service's check_runs.state CHECK allows). observations is how many observations the run recorded and triggers how many conditions it fired; cost_usd is what the run cost. Rows are immutable.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["id", "watch_id", "trigger", "carrier", "started_at", "finished_at", "state", "http_status", "observations", "triggers", "cost_usd", "detail"],
++ "properties": {
++ "id": { "type": "string", "pattern": "^ckr_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "watch_id": { "type": "string", "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "trigger": { "enum": ["schedule", "manual", "event", "webhook"] },
++ "carrier": { "type": ["string", "null"], "enum": ["event", "webhook", "http", "feed", "api", "node", "run", null] },
++ "started_at": { "type": "string", "format": "date-time" },
++ "finished_at": { "type": "string", "format": "date-time" },
++ "state": { "enum": ["ok", "not_modified", "no_change", "changed", "condition_met", "http_error", "timeout", "parse_error", "rate_limited", "budget_exceeded", "skipped", "disabled"] },
++ "http_status": { "type": ["integer", "null"] },
++ "observations": { "type": "integer", "minimum": 0 },
++ "triggers": { "type": "integer", "minimum": 0 },
++ "cost_usd": { "type": "number", "minimum": 0 },
++ "detail": { "type": ["string", "null"] }
++ }
++}
ddiff --git a/contracts/watch/observation.v1.json b/contracts/watch/observation.v1.json
nnew file mode 100644
iindex 00000000..891951e2
---- /dev/null
++++ b/contracts/watch/observation.v1.json
@@@ -0,0 +1,21 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/observation.v1.json",
++ "title": "WatchObservation",
++ "description": "watch.observation@1: one value a check recorded for a watch (plan T18): what was extracted, when, from which check run, and whether it changed or met the condition. value is the extracted value exactly as the source stated it, never inferred; snapshot is a capped copy of the raw body kept according to the watch's retention. Rows are immutable.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["id", "watch_id", "check_run_id", "observed_at", "value", "value_hash", "previous_hash", "changed", "condition_met", "snapshot"],
++ "properties": {
++ "id": { "type": "string", "pattern": "^wco_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "watch_id": { "type": "string", "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "check_run_id": { "type": "string", "pattern": "^ckr_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "observed_at": { "type": "string", "format": "date-time" },
++ "value": { "description": "The extracted value as the source stated it: text, a decimal number, a structured object." },
++ "value_hash": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "SHA-256 hex of the canonical value." },
++ "previous_hash": { "type": ["string", "null"], "pattern": "^[0-9a-f]{64}$", "description": "SHA-256 of the previous observation's value; null for the first observation." },
++ "changed": { "type": "boolean" },
++ "condition_met": { "type": "boolean" },
++ "snapshot": { "type": ["string", "null"] }
++ }
++}
ddiff --git a/contracts/watch/watch-request.v1.json b/contracts/watch/watch-request.v1.json
nnew file mode 100644
iindex 00000000..41dbab6f
---- /dev/null
++++ b/contracts/watch/watch-request.v1.json
@@@ -0,0 +1,21 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/watch-request.v1.json",
++ "title": "WatchRequest",
++ "description": "watch.watch-request@1: the body of POST /api/v1/watches and PATCH /api/v1/watches/:id on OpenVibe.Watch (watch.watch.manage; the acting person). Every field is optional on a patch; a create requires source, extraction, condition and action, which the service enforces in code (422 watch.invalid).",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "name": { "type": "string", "minLength": 1, "maxLength": 120 },
++ "labels": { "type": "object", "additionalProperties": { "type": "string", "maxLength": 60 } },
++ "source": { "$ref": "watch.v1.json#/$defs/source" },
++ "cadence": { "$ref": "watch.v1.json#/$defs/cadence" },
++ "extraction": { "$ref": "watch.v1.json#/$defs/extraction" },
++ "comparison": { "$ref": "watch.v1.json#/$defs/comparison" },
++ "condition": { "$ref": "watch.v1.json#/$defs/condition" },
++ "action": { "type": "array", "minItems": 1, "maxItems": 8, "items": { "$ref": "watch.v1.json#/$defs/action" } },
++ "budget": { "$ref": "watch.v1.json#/$defs/budget" },
++ "retention": { "$ref": "watch.v1.json#/$defs/retention" },
++ "status": { "enum": ["active", "paused", "disabled", "failed"] }
++ }
++}
ddiff --git a/contracts/watch/watch-result.v1.json b/contracts/watch/watch-result.v1.json
nnew file mode 100644
iindex 00000000..aa127468
---- /dev/null
++++ b/contracts/watch/watch-result.v1.json
@@@ -0,0 +1,38 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/watch-result.v1.json",
++ "title": "WatchResult",
++ "description": "watch.watch-result@1: answers of the watch routes on OpenVibe.Watch. GET /api/v1/watches → { watches } and POST /api/v1/watches → 201 { watch } (watch.watch.read, watch.watch.manage); PATCH → { watch }; POST /:id/pause and /:id/resume → { id, status }; DELETE /api/v1/watches/:id → { id, deleted: true }.",
++ "anyOf": [
++ {
++ "type": "object",
++ "required": ["watches"],
++ "additionalProperties": false,
++ "properties": { "watches": { "type": "array", "items": { "$ref": "watch.v1.json" } } }
++ },
++ {
++ "type": "object",
++ "required": ["watch"],
++ "additionalProperties": false,
++ "properties": { "watch": { "$ref": "watch.v1.json" } }
++ },
++ {
++ "type": "object",
++ "required": ["id", "status"],
++ "additionalProperties": false,
++ "properties": {
++ "id": { "type": "string", "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "status": { "enum": ["active", "paused", "disabled", "failed"] }
++ }
++ },
++ {
++ "type": "object",
++ "required": ["id", "deleted"],
++ "additionalProperties": false,
++ "properties": {
++ "id": { "type": "string", "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "deleted": { "const": true }
++ }
++ }
++ ]
++}
ddiff --git a/contracts/watch/watch.v1.json b/contracts/watch/watch.v1.json
nnew file mode 100644
iindex 00000000..96ac5228
---- /dev/null
++++ b/contracts/watch/watch.v1.json
@@@ -0,0 +1,102 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/watch.v1.json",
++ "title": "Watch",
++ "description": "watch.watch@1: a user-defined persistent observation (plan T18). It names a source (a push event, a webhook, a conditional HTTP URL, a feed or API, a local Node probe, or an expensive Run check), how a value is extracted, how it is compared with the last observation, the condition that fires, the actions it wakes, its budget and its retention. Carrier preference is binding: an event or webhook source is used when one exists, then ETag/Last-Modified, then a feed, then an API, and browser polling through Run only when none works. A price or stock is 'as of' the observation, null when it stated none.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": ["id", "owner", "status", "source", "extraction", "condition", "action", "created_at", "updated_at"],
++ "properties": {
++ "id": { "type": "string", "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "project_id": { "type": ["string", "null"], "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$" },
++ "owner": { "type": "string", "description": "The acting person or agent the watch belongs to: usr_…, agt_… or svc:…." },
++ "name": { "type": "string", "minLength": 1, "maxLength": 120 },
++ "labels": { "type": "object", "additionalProperties": { "type": "string", "maxLength": 60 } },
++ "status": { "enum": ["active", "paused", "disabled", "failed"] },
++ "source": { "$ref": "#/$defs/source" },
++ "cadence": { "$ref": "#/$defs/cadence" },
++ "extraction": { "$ref": "#/$defs/extraction" },
++ "comparison": { "$ref": "#/$defs/comparison" },
++ "condition": { "$ref": "#/$defs/condition" },
++ "action": { "type": "array", "minItems": 1, "maxItems": 8, "items": { "$ref": "#/$defs/action" } },
++ "budget": { "$ref": "#/$defs/budget" },
++ "retention": { "$ref": "#/$defs/retention" },
++ "health": { "type": ["object", "null"], "additionalProperties": true },
++ "created_at": { "type": "string", "format": "date-time" },
++ "updated_at": { "type": "string", "format": "date-time" }
++ },
++ "$defs": {
++ "auth": {
++ "type": "object",
++ "required": ["mode"],
++ "additionalProperties": false,
++ "properties": {
++ "mode": { "enum": ["none", "header", "bearer", "query"] },
++ "env": { "type": ["string", "null"], "pattern": "^WATCH_CRED_[A-Z0-9_]{2,60}$", "description": "The name of the environment variable holding the credential; Watch reads it by name at fetch time and never stores the value." },
++ "header": { "type": ["string", "null"] },
++ "param": { "type": ["string", "null"] }
++ }
++ },
++ "source": {
++ "oneOf": [
++ { "type": "object", "required": ["kind"], "additionalProperties": false,
++ "properties": { "kind": { "const": "webhook" }, "endpoint": { "type": "string", "pattern": "^/internal/hooks/" } } },
++ { "type": "object", "required": ["kind", "pattern"], "additionalProperties": false,
++ "properties": { "kind": { "const": "event" }, "pattern": { "type": "string", "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_*]+){1,}$" },
++ "filter": { "type": ["object", "null"], "additionalProperties": { "type": ["string", "number", "boolean", "null"] } } } },
++ { "type": "object", "required": ["kind", "url"], "additionalProperties": false,
++ "properties": { "kind": { "enum": ["http", "feed", "api"] }, "url": { "type": "string", "format": "uri", "pattern": "^https?://" },
++ "method": { "enum": ["GET", "HEAD"] }, "format": { "enum": ["rss", "atom", "json", null] },
++ "items_path": { "type": ["string", "null"] }, "fields": { "type": ["object", "null"], "additionalProperties": { "type": "string" } },
++ "auth": { "$ref": "#/$defs/auth" }, "headers": { "type": "object", "additionalProperties": { "type": "string" } },
++ "conditional": { "type": "boolean", "description": "Send If-None-Match / If-Modified-Since from the stored ETag/Last-Modified when the server gave one." } } },
++ { "type": "object", "required": ["kind", "node_id", "probe"], "additionalProperties": false,
++ "properties": { "kind": { "const": "node" }, "node_id": { "type": "string" }, "probe": { "type": "object", "additionalProperties": true } } },
++ { "type": "object", "required": ["kind", "runtime", "steps"], "additionalProperties": false,
++ "properties": { "kind": { "const": "run" }, "runtime": { "enum": ["browser", "code", "desktop"] },
++ "url": { "type": ["string", "null"], "format": "uri" }, "steps": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": true } },
++ "workload": { "$ref": "../platform/workload-requirements.v1.json" } } }
++ ]
++ },
++ "cadence": {
++ "type": ["object", "null"], "additionalProperties": false,
++ "description": "Required for http/feed/api/node sources; null for event/webhook sources (they never poll).",
++ "properties": { "every_sec": { "type": "integer", "minimum": 30, "maximum": 2592000 }, "jitter_sec": { "type": "integer", "minimum": 0, "maximum": 3600 }, "timezone": { "type": ["string", "null"] } }
++ },
++ "extraction": {
++ "type": "object", "additionalProperties": false,
++ "properties": { "kind": { "enum": ["text", "html", "json", "regex", "css", "jsonpath", "ai"] },
++ "selector": { "type": ["string", "null"] }, "fields": { "type": ["object", "null"], "additionalProperties": { "type": "string" } },
++ "value_path": { "type": ["string", "null"] }, "ai": { "type": ["object", "null"], "additionalProperties": true } }
++ },
++ "comparison": {
++ "type": ["object", "null"], "additionalProperties": false,
++ "properties": { "mode": { "enum": ["changed", "threshold", "none"] }, "tolerance": { "type": ["number", "null"] }, "percent": { "type": ["number", "null"] } }
++ },
++ "condition": {
++ "type": "object", "additionalProperties": false,
++ "properties": { "op": { "enum": ["changed", "gt", "gte", "lt", "lte", "eq", "ne", "contains", "matches", "exists", "absent"] },
++ "value": { "type": ["string", "number", "null"] }, "for_sec": { "type": ["integer", "null"], "minimum": 0 } }
++ },
++ "action": { "oneOf": [
++ { "type": "object", "required": ["kind"], "additionalProperties": false,
++ "properties": { "kind": { "const": "notification" }, "category": { "enum": ["service", "social", "system"] }, "priority": { "enum": ["low", "normal", "high", "critical"] } } },
++ { "type": "object", "required": ["kind", "event_type"], "additionalProperties": false,
++ "properties": { "kind": { "const": "event" }, "event_type": { "type": "string" }, "payload": { "type": ["object", "null"], "additionalProperties": true } } },
++ { "type": "object", "required": ["kind", "url", "secret_env"], "additionalProperties": false,
++ "properties": { "kind": { "const": "webhook" }, "url": { "type": "string", "format": "uri", "pattern": "^https://" }, "secret_env": { "type": "string", "pattern": "^WATCH_HOOK_[A-Z0-9_]{2,60}$" } } },
++ { "type": "object", "required": ["kind", "brief"], "additionalProperties": false,
++ "properties": { "kind": { "const": "actor-task" }, "brief": { "type": "string", "maxLength": 8000 }, "budget_usd": { "type": ["number", "null"] } } },
++ { "type": "object", "required": ["kind", "repo", "brief"], "additionalProperties": false,
++ "properties": { "kind": { "const": "codes-run" }, "repo": { "type": "string" }, "brief": { "type": "string", "maxLength": 8000 } } },
++ { "type": "object", "required": ["kind", "runtime", "command"], "additionalProperties": false,
++ "properties": { "kind": { "const": "run-job" }, "runtime": { "enum": ["function", "code", "browser", "linux"] }, "command": { "type": "string" }, "workload": { "type": ["object", "null"], "additionalProperties": true } } } ] },
++ "budget": {
++ "type": "object", "additionalProperties": false,
++ "properties": { "checks_per_day": { "type": ["integer", "null"], "minimum": 1 }, "usd_per_month": { "type": ["number", "null"], "minimum": 0 },
++ "max_runtime_ms": { "type": ["integer", "null"], "minimum": 100 }, "max_bytes": { "type": ["integer", "null"], "minimum": 1024 } }
++ },
++ "retention": { "type": "object", "additionalProperties": false,
++ "properties": { "observations_days": { "type": ["integer", "null"], "minimum": 1 }, "keep_snapshots": { "type": "boolean" } } }
++ }
++}
ddiff --git a/fixtures/watch.check-run/invalid/unknown-state.json b/fixtures/watch.check-run/invalid/unknown-state.json
nnew file mode 100644
iindex 00000000..3272d24e
---- /dev/null
++++ b/fixtures/watch.check-run/invalid/unknown-state.json
@@@ -0,0 +1,14 @@
++{
++ "id": "ckr_01JAB2C3D4E5F6G7H8J9K0MNPT",
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "trigger": "schedule",
++ "carrier": "http",
++ "started_at": "2026-10-05T09:00:00.000Z",
++ "finished_at": "2026-10-05T09:00:01.250Z",
++ "state": "exploded",
++ "http_status": 200,
++ "observations": 1,
++ "triggers": 0,
++ "cost_usd": 0,
++ "detail": null
++}
ddiff --git a/fixtures/watch.check-run/valid/http-changed.json b/fixtures/watch.check-run/valid/http-changed.json
nnew file mode 100644
iindex 00000000..f5d0ccfb
---- /dev/null
++++ b/fixtures/watch.check-run/valid/http-changed.json
@@@ -0,0 +1,14 @@
++{
++ "id": "ckr_01JAB2C3D4E5F6G7H8J9K0MNPT",
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "trigger": "schedule",
++ "carrier": "http",
++ "started_at": "2026-10-05T09:00:00.000Z",
++ "finished_at": "2026-10-05T09:00:01.250Z",
++ "state": "changed",
++ "http_status": 200,
++ "observations": 1,
++ "triggers": 0,
++ "cost_usd": 0,
++ "detail": null
++}
ddiff --git a/fixtures/watch.check.failed/invalid/zero-failures.json b/fixtures/watch.check.failed/invalid/zero-failures.json
nnew file mode 100644
iindex 00000000..c075c817
---- /dev/null
++++ b/fixtures/watch.check.failed/invalid/zero-failures.json
@@@ -0,0 +1,8 @@
++{
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "state": "timeout",
++ "carrier": "api",
++ "http_status": null,
++ "error_code": "deadline_exceeded",
++ "consecutive_failures": 0
++}
ddiff --git a/fixtures/watch.check.failed/valid/http-error.json b/fixtures/watch.check.failed/valid/http-error.json
nnew file mode 100644
iindex 00000000..4766a367
---- /dev/null
++++ b/fixtures/watch.check.failed/valid/http-error.json
@@@ -0,0 +1,8 @@
++{
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "state": "http_error",
++ "carrier": "http",
++ "http_status": 503,
++ "error_code": "upstream_unavailable",
++ "consecutive_failures": 2
++}
ddiff --git a/fixtures/watch.observation.recorded/invalid/missing-owner.json b/fixtures/watch.observation.recorded/invalid/missing-owner.json
nnew file mode 100644
iindex 00000000..b321ae55
---- /dev/null
++++ b/fixtures/watch.observation.recorded/invalid/missing-owner.json
@@@ -0,0 +1,8 @@
++{
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "observed_at": "2026-10-05T09:00:00.000Z",
++ "value": 189.99,
++ "value_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
++ "changed": true,
++ "condition_met": true
++}
ddiff --git a/fixtures/watch.observation.recorded/valid/price-changed.json b/fixtures/watch.observation.recorded/valid/price-changed.json
nnew file mode 100644
iindex 00000000..2ea7d203
---- /dev/null
++++ b/fixtures/watch.observation.recorded/valid/price-changed.json
@@@ -0,0 +1,9 @@
++{
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
++ "observed_at": "2026-10-05T09:00:00.000Z",
++ "value": 189.99,
++ "value_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
++ "changed": true,
++ "condition_met": true
++}
ddiff --git a/fixtures/watch.observation/invalid/missing-check-run.json b/fixtures/watch.observation/invalid/missing-check-run.json
nnew file mode 100644
iindex 00000000..c25f9d06
---- /dev/null
++++ b/fixtures/watch.observation/invalid/missing-check-run.json
@@@ -0,0 +1,11 @@
++{
++ "id": "wco_01JAB2C3D4E5F6G7H8J9K0MNPS",
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "observed_at": "2026-10-05T09:00:00.000Z",
++ "value": 189.99,
++ "value_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
++ "previous_hash": null,
++ "changed": true,
++ "condition_met": true,
++ "snapshot": null
++}
ddiff --git a/fixtures/watch.observation/valid/price-changed.json b/fixtures/watch.observation/valid/price-changed.json
nnew file mode 100644
iindex 00000000..c0f7ba0b
---- /dev/null
++++ b/fixtures/watch.observation/valid/price-changed.json
@@@ -0,0 +1,12 @@
++{
++ "id": "wco_01JAB2C3D4E5F6G7H8J9K0MNPS",
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "check_run_id": "ckr_01JAB2C3D4E5F6G7H8J9K0MNPT",
++ "observed_at": "2026-10-05T09:00:00.000Z",
++ "value": 189.99,
++ "value_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
++ "previous_hash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
++ "changed": true,
++ "condition_met": true,
++ "snapshot": "{\"price\":189.99,\"currency\":\"USD\"}"
++}
ddiff --git a/fixtures/watch.watch-request/invalid/unknown-status.json b/fixtures/watch.watch-request/invalid/unknown-status.json
nnew file mode 100644
iindex 00000000..dd428de9
---- /dev/null
++++ b/fixtures/watch.watch-request/invalid/unknown-status.json
@@@ -0,0 +1,7 @@
++{
++ "name": "Release 0.102.0 published",
++ "source": { "kind": "event", "pattern": "host.release.published" },
++ "condition": { "op": "changed" },
++ "action": [ { "kind": "notification" } ],
++ "status": "archived"
++}
ddiff --git a/fixtures/watch.watch-request/valid/create-event-watch.json b/fixtures/watch.watch-request/valid/create-event-watch.json
nnew file mode 100644
iindex 00000000..52b49dbf
---- /dev/null
++++ b/fixtures/watch.watch-request/valid/create-event-watch.json
@@@ -0,0 +1,12 @@
++{
++ "name": "Release 0.102.0 published",
++ "source": { "kind": "event", "pattern": "host.release.published", "filter": null },
++ "cadence": null,
++ "extraction": { "kind": "json", "selector": null, "fields": null, "value_path": "$.release", "ai": null },
++ "comparison": { "mode": "changed", "tolerance": null, "percent": null },
++ "condition": { "op": "changed", "value": null, "for_sec": null },
++ "action": [ { "kind": "notification", "category": "service", "priority": "normal" } ],
++ "budget": { "checks_per_day": 100, "usd_per_month": 0, "max_runtime_ms": 5000, "max_bytes": 1048576 },
++ "retention": { "observations_days": 30, "keep_snapshots": false },
++ "status": "active"
++}
ddiff --git a/fixtures/watch.watch-result/invalid/not-deleted.json b/fixtures/watch.watch-result/invalid/not-deleted.json
nnew file mode 100644
iindex 00000000..920d1a4f
---- /dev/null
++++ b/fixtures/watch.watch-result/invalid/not-deleted.json
@@@ -0,0 +1 @@
++{ "id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ", "deleted": false }
ddiff --git a/fixtures/watch.watch-result/valid/paused.json b/fixtures/watch.watch-result/valid/paused.json
nnew file mode 100644
iindex 00000000..a41f7832
---- /dev/null
++++ b/fixtures/watch.watch-result/valid/paused.json
@@@ -0,0 +1 @@
++{ "id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ", "status": "paused" }
ddiff --git a/fixtures/watch.watch.triggered/invalid/missing-observation.json b/fixtures/watch.watch.triggered/invalid/missing-observation.json
nnew file mode 100644
iindex 00000000..23083aa5
---- /dev/null
++++ b/fixtures/watch.watch.triggered/invalid/missing-observation.json
@@@ -0,0 +1,8 @@
++{
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "recipient": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
++ "project_id": null,
++ "name": "Steam Deck OLED price",
++ "condition": { "op": "lt", "value": 199, "for_sec": null },
++ "fired_at": "2026-10-05T09:00:01.250Z"
++}
ddiff --git a/fixtures/watch.watch.triggered/valid/price-below.json b/fixtures/watch.watch.triggered/valid/price-below.json
nnew file mode 100644
iindex 00000000..c3bbab99
---- /dev/null
++++ b/fixtures/watch.watch.triggered/valid/price-below.json
@@@ -0,0 +1,14 @@
++{
++ "watch_id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "recipient": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
++ "project_id": null,
++ "name": "Steam Deck OLED price",
++ "condition": { "op": "lt", "value": 199, "for_sec": null },
++ "observation": {
++ "id": "wco_01JAB2C3D4E5F6G7H8J9K0MNPS",
++ "observed_at": "2026-10-05T09:00:00.000Z",
++ "value": 189.99,
++ "previous_value": 209.99
++ },
++ "fired_at": "2026-10-05T09:00:01.250Z"
++}
ddiff --git a/fixtures/watch.watch/invalid/missing-owner.json b/fixtures/watch.watch/invalid/missing-owner.json
nnew file mode 100644
iindex 00000000..13363711
---- /dev/null
++++ b/fixtures/watch.watch/invalid/missing-owner.json
@@@ -0,0 +1,11 @@
++{
++ "id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "name": "Steam Deck OLED price",
++ "status": "active",
++ "source": { "kind": "api", "url": "https://openvibe.deals/api/offers/steam-deck-oled" },
++ "extraction": { "kind": "jsonpath", "value_path": "$.price" },
++ "condition": { "op": "lt", "value": 199 },
++ "action": [ { "kind": "notification" } ],
++ "created_at": "2026-10-05T08:00:00.000Z",
++ "updated_at": "2026-10-05T08:00:00.000Z"
++}
ddiff --git a/fixtures/watch.watch/valid/price-threshold.json b/fixtures/watch.watch/valid/price-threshold.json
nnew file mode 100644
iindex 00000000..07528fb2
---- /dev/null
++++ b/fixtures/watch.watch/valid/price-threshold.json
@@@ -0,0 +1,29 @@
++{
++ "id": "wch_01JAB2C3D4E5F6G7H8J9K0MNPQ",
++ "project_id": null,
++ "owner": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR",
++ "name": "Steam Deck OLED price",
++ "labels": { "topic": "hardware" },
++ "status": "active",
++ "source": {
++ "kind": "api",
++ "url": "https://openvibe.deals/api/offers/steam-deck-oled",
++ "method": "GET",
++ "format": "json",
++ "items_path": "offers",
++ "fields": { "price": "price", "currency": "currency" },
++ "auth": { "mode": "none" },
++ "headers": {},
++ "conditional": true
++ },
++ "cadence": { "every_sec": 3600, "jitter_sec": 60, "timezone": null },
++ "extraction": { "kind": "jsonpath", "selector": null, "fields": null, "value_path": "$.offers[0].price", "ai": null },
++ "comparison": { "mode": "threshold", "tolerance": 0.01, "percent": null },
++ "condition": { "op": "lt", "value": 199, "for_sec": null },
++ "action": [ { "kind": "notification", "category": "service", "priority": "high" } ],
++ "budget": { "checks_per_day": 100, "usd_per_month": 0, "max_runtime_ms": 20000, "max_bytes": 5242880 },
++ "retention": { "observations_days": 90, "keep_snapshots": false },
++ "health": null,
++ "created_at": "2026-10-05T08:00:00.000Z",
++ "updated_at": "2026-10-05T08:00:00.000Z"
++}
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex 83203743..acc62372 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -46078,6 +46078,1184 @@
}
}
},
++ "watch.watch": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "planned",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/watch.v1.json",
++ "title": "Watch",
++ "description": "watch.watch@1: a user-defined persistent observation (plan T18). It names a source (a push event, a webhook, a conditional HTTP URL, a feed or API, a local Node probe, or an expensive Run check), how a value is extracted, how it is compared with the last observation, the condition that fires, the actions it wakes, its budget and its retention. Carrier preference is binding: an event or webhook source is used when one exists, then ETag/Last-Modified, then a feed, then an API, and browser polling through Run only when none works. A price or stock is 'as of' the observation, null when it stated none.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "owner",
++ "status",
++ "source",
++ "extraction",
++ "condition",
++ "action",
++ "created_at",
++ "updated_at"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "project_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "owner": {
++ "type": "string",
++ "description": "The acting person or agent the watch belongs to: usr_…, agt_… or svc:…."
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "labels": {
++ "type": "object",
++ "additionalProperties": {
++ "type": "string",
++ "maxLength": 60
++ }
++ },
++ "status": {
++ "enum": [
++ "active",
++ "paused",
++ "disabled",
++ "failed"
++ ]
++ },
++ "source": {
++ "$ref": "#/$defs/source"
++ },
++ "cadence": {
++ "$ref": "#/$defs/cadence"
++ },
++ "extraction": {
++ "$ref": "#/$defs/extraction"
++ },
++ "comparison": {
++ "$ref": "#/$defs/comparison"
++ },
++ "condition": {
++ "$ref": "#/$defs/condition"
++ },
++ "action": {
++ "type": "array",
++ "minItems": 1,
++ "maxItems": 8,
++ "items": {
++ "$ref": "#/$defs/action"
++ }
++ },
++ "budget": {
++ "$ref": "#/$defs/budget"
++ },
++ "retention": {
++ "$ref": "#/$defs/retention"
++ },
++ "health": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": true
++ },
++ "created_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "updated_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ },
++ "$defs": {
++ "auth": {
++ "type": "object",
++ "required": [
++ "mode"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "mode": {
++ "enum": [
++ "none",
++ "header",
++ "bearer",
++ "query"
++ ]
++ },
++ "env": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^WATCH_CRED_[A-Z0-9_]{2,60}$",
++ "description": "The name of the environment variable holding the credential; Watch reads it by name at fetch time and never stores the value."
++ },
++ "header": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "param": {
++ "type": [
++ "string",
++ "null"
++ ]
++ }
++ }
++ },
++ "source": {
++ "oneOf": [
++ {
++ "type": "object",
++ "required": [
++ "kind"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "webhook"
++ },
++ "endpoint": {
++ "type": "string",
++ "pattern": "^/internal/hooks/"
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "pattern"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "event"
++ },
++ "pattern": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_-]*(\\.[a-z0-9_*]+){1,}$"
++ },
++ "filter": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": {
++ "type": [
++ "string",
++ "number",
++ "boolean",
++ "null"
++ ]
++ }
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "url"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "enum": [
++ "http",
++ "feed",
++ "api"
++ ]
++ },
++ "url": {
++ "type": "string",
++ "format": "uri",
++ "pattern": "^https?://"
++ },
++ "method": {
++ "enum": [
++ "GET",
++ "HEAD"
++ ]
++ },
++ "format": {
++ "enum": [
++ "rss",
++ "atom",
++ "json",
++ null
++ ]
++ },
++ "items_path": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "fields": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": {
++ "type": "string"
++ }
++ },
++ "auth": {
++ "$ref": "#/$defs/auth"
++ },
++ "headers": {
++ "type": "object",
++ "additionalProperties": {
++ "type": "string"
++ }
++ },
++ "conditional": {
++ "type": "boolean",
++ "description": "Send If-None-Match / If-Modified-Since from the stored ETag/Last-Modified when the server gave one."
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "node_id",
++ "probe"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "node"
++ },
++ "node_id": {
++ "type": "string"
++ },
++ "probe": {
++ "type": "object",
++ "additionalProperties": true
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "runtime",
++ "steps"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "run"
++ },
++ "runtime": {
++ "enum": [
++ "browser",
++ "code",
++ "desktop"
++ ]
++ },
++ "url": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "format": "uri"
++ },
++ "steps": {
++ "type": "array",
++ "minItems": 1,
++ "items": {
++ "type": "object",
++ "additionalProperties": true
++ }
++ },
++ "workload": {
++ "$ref": "../platform/workload-requirements.v1.json"
++ }
++ }
++ }
++ ]
++ },
++ "cadence": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "description": "Required for http/feed/api/node sources; null for event/webhook sources (they never poll).",
++ "properties": {
++ "every_sec": {
++ "type": "integer",
++ "minimum": 30,
++ "maximum": 2592000
++ },
++ "jitter_sec": {
++ "type": "integer",
++ "minimum": 0,
++ "maximum": 3600
++ },
++ "timezone": {
++ "type": [
++ "string",
++ "null"
++ ]
++ }
++ }
++ },
++ "extraction": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "enum": [
++ "text",
++ "html",
++ "json",
++ "regex",
++ "css",
++ "jsonpath",
++ "ai"
++ ]
++ },
++ "selector": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "fields": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": {
++ "type": "string"
++ }
++ },
++ "value_path": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "ai": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": true
++ }
++ }
++ },
++ "comparison": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "mode": {
++ "enum": [
++ "changed",
++ "threshold",
++ "none"
++ ]
++ },
++ "tolerance": {
++ "type": [
++ "number",
++ "null"
++ ]
++ },
++ "percent": {
++ "type": [
++ "number",
++ "null"
++ ]
++ }
++ }
++ },
++ "condition": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "op": {
++ "enum": [
++ "changed",
++ "gt",
++ "gte",
++ "lt",
++ "lte",
++ "eq",
++ "ne",
++ "contains",
++ "matches",
++ "exists",
++ "absent"
++ ]
++ },
++ "value": {
++ "type": [
++ "string",
++ "number",
++ "null"
++ ]
++ },
++ "for_sec": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 0
++ }
++ }
++ },
++ "action": {
++ "oneOf": [
++ {
++ "type": "object",
++ "required": [
++ "kind"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "notification"
++ },
++ "category": {
++ "enum": [
++ "service",
++ "social",
++ "system"
++ ]
++ },
++ "priority": {
++ "enum": [
++ "low",
++ "normal",
++ "high",
++ "critical"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "event_type"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "event"
++ },
++ "event_type": {
++ "type": "string"
++ },
++ "payload": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": true
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "url",
++ "secret_env"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "webhook"
++ },
++ "url": {
++ "type": "string",
++ "format": "uri",
++ "pattern": "^https://"
++ },
++ "secret_env": {
++ "type": "string",
++ "pattern": "^WATCH_HOOK_[A-Z0-9_]{2,60}$"
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "brief"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "actor-task"
++ },
++ "brief": {
++ "type": "string",
++ "maxLength": 8000
++ },
++ "budget_usd": {
++ "type": [
++ "number",
++ "null"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "repo",
++ "brief"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "codes-run"
++ },
++ "repo": {
++ "type": "string"
++ },
++ "brief": {
++ "type": "string",
++ "maxLength": 8000
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "kind",
++ "runtime",
++ "command"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "kind": {
++ "const": "run-job"
++ },
++ "runtime": {
++ "enum": [
++ "function",
++ "code",
++ "browser",
++ "linux"
++ ]
++ },
++ "command": {
++ "type": "string"
++ },
++ "workload": {
++ "type": [
++ "object",
++ "null"
++ ],
++ "additionalProperties": true
++ }
++ }
++ }
++ ]
++ },
++ "budget": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "checks_per_day": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 1
++ },
++ "usd_per_month": {
++ "type": [
++ "number",
++ "null"
++ ],
++ "minimum": 0
++ },
++ "max_runtime_ms": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 100
++ },
++ "max_bytes": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 1024
++ }
++ }
++ },
++ "retention": {
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "observations_days": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "minimum": 1
++ },
++ "keep_snapshots": {
++ "type": "boolean"
++ }
++ }
++ }
++ }
++ }
++ },
++ "watch.watch-request": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "planned",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/watch-request.v1.json",
++ "title": "WatchRequest",
++ "description": "watch.watch-request@1: the body of POST /api/v1/watches and PATCH /api/v1/watches/:id on OpenVibe.Watch (watch.watch.manage; the acting person). Every field is optional on a patch; a create requires source, extraction, condition and action, which the service enforces in code (422 watch.invalid).",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "labels": {
++ "type": "object",
++ "additionalProperties": {
++ "type": "string",
++ "maxLength": 60
++ }
++ },
++ "source": {
++ "$ref": "watch.v1.json#/$defs/source"
++ },
++ "cadence": {
++ "$ref": "watch.v1.json#/$defs/cadence"
++ },
++ "extraction": {
++ "$ref": "watch.v1.json#/$defs/extraction"
++ },
++ "comparison": {
++ "$ref": "watch.v1.json#/$defs/comparison"
++ },
++ "condition": {
++ "$ref": "watch.v1.json#/$defs/condition"
++ },
++ "action": {
++ "type": "array",
++ "minItems": 1,
++ "maxItems": 8,
++ "items": {
++ "$ref": "watch.v1.json#/$defs/action"
++ }
++ },
++ "budget": {
++ "$ref": "watch.v1.json#/$defs/budget"
++ },
++ "retention": {
++ "$ref": "watch.v1.json#/$defs/retention"
++ },
++ "status": {
++ "enum": [
++ "active",
++ "paused",
++ "disabled",
++ "failed"
++ ]
++ }
++ }
++ }
++ },
++ "watch.watch-result": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "planned",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/watch-result.v1.json",
++ "title": "WatchResult",
++ "description": "watch.watch-result@1: answers of the watch routes on OpenVibe.Watch. GET /api/v1/watches → { watches } and POST /api/v1/watches → 201 { watch } (watch.watch.read, watch.watch.manage); PATCH → { watch }; POST /:id/pause and /:id/resume → { id, status }; DELETE /api/v1/watches/:id → { id, deleted: true }.",
++ "anyOf": [
++ {
++ "type": "object",
++ "required": [
++ "watches"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "watches": {
++ "type": "array",
++ "items": {
++ "$ref": "watch.v1.json"
++ }
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "watch"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "watch": {
++ "$ref": "watch.v1.json"
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "id",
++ "status"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "status": {
++ "enum": [
++ "active",
++ "paused",
++ "disabled",
++ "failed"
++ ]
++ }
++ }
++ },
++ {
++ "type": "object",
++ "required": [
++ "id",
++ "deleted"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "deleted": {
++ "const": true
++ }
++ }
++ }
++ ]
++ }
++ },
++ "watch.observation": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "planned",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/observation.v1.json",
++ "title": "WatchObservation",
++ "description": "watch.observation@1: one value a check recorded for a watch (plan T18): what was extracted, when, from which check run, and whether it changed or met the condition. value is the extracted value exactly as the source stated it, never inferred; snapshot is a capped copy of the raw body kept according to the watch's retention. Rows are immutable.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "watch_id",
++ "check_run_id",
++ "observed_at",
++ "value",
++ "value_hash",
++ "previous_hash",
++ "changed",
++ "condition_met",
++ "snapshot"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^wco_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "watch_id": {
++ "type": "string",
++ "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "check_run_id": {
++ "type": "string",
++ "pattern": "^ckr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "observed_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "value": {
++ "description": "The extracted value as the source stated it: text, a decimal number, a structured object."
++ },
++ "value_hash": {
++ "type": "string",
++ "pattern": "^[0-9a-f]{64}$",
++ "description": "SHA-256 hex of the canonical value."
++ },
++ "previous_hash": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^[0-9a-f]{64}$",
++ "description": "SHA-256 of the previous observation's value; null for the first observation."
++ },
++ "changed": {
++ "type": "boolean"
++ },
++ "condition_met": {
++ "type": "boolean"
++ },
++ "snapshot": {
++ "type": [
++ "string",
++ "null"
++ ]
++ }
++ }
++ }
++ },
++ "watch.check-run": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "planned",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/watch/check-run.v1.json",
++ "title": "WatchCheckRun",
++ "description": "watch.check-run@1: one execution of a watch's check (plan T18), by schedule, manually, or from a delivered event or webhook. carrier names the mechanism that carried it; state is the terminal state (the same values the service's check_runs.state CHECK allows). observations is how many observations the run recorded and triggers how many conditions it fired; cost_usd is what the run cost. Rows are immutable.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "watch_id",
++ "trigger",
++ "carrier",
++ "started_at",
++ "finished_at",
++ "state",
++ "http_status",
++ "observations",
++ "triggers",
++ "cost_usd",
++ "detail"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^ckr_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "watch_id": {
++ "type": "string",
++ "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "trigger": {
++ "enum": [
++ "schedule",
++ "manual",
++ "event",
++ "webhook"
++ ]
++ },
++ "carrier": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "enum": [
++ "event",
++ "webhook",
++ "http",
++ "feed",
++ "api",
++ "node",
++ "run",
++ null
++ ]
++ },
++ "started_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "finished_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "state": {
++ "enum": [
++ "ok",
++ "not_modified",
++ "no_change",
++ "changed",
++ "condition_met",
++ "http_error",
++ "timeout",
++ "parse_error",
++ "rate_limited",
++ "budget_exceeded",
++ "skipped",
++ "disabled"
++ ]
++ },
++ "http_status": {
++ "type": [
++ "integer",
++ "null"
++ ]
++ },
++ "observations": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "triggers": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "cost_usd": {
++ "type": "number",
++ "minimum": 0
++ },
++ "detail": {
++ "type": [
++ "string",
++ "null"
++ ]
++ }
++ }
++ }
++ },
++ "watch.observation.recorded": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "planned",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.observation.recorded.v1.json",
++ "title": "WatchObservationRecordedPayload",
++ "description": "watch.observation.recorded v1 (OpenVibe.Watch, plan T18): a check recorded an observation for a watch. It carries the extracted value as the source stated it and its hash, never the raw body. Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority low, actor service:watch. Watch's own records are the full observation (watch.observation@1); this event is the notification that one exists.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "watch_id",
++ "owner",
++ "observed_at",
++ "value",
++ "value_hash",
++ "changed",
++ "condition_met"
++ ],
++ "properties": {
++ "watch_id": {
++ "type": "string",
++ "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "owner": {
++ "type": "string",
++ "pattern": "^(usr|agt)_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The watch owner's subject id: who this observation is for."
++ },
++ "observed_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "value": {
++ "description": "The extracted value as the source stated it; null when it stated none."
++ },
++ "value_hash": {
++ "type": "string",
++ "pattern": "^[0-9a-f]{64}$",
++ "description": "SHA-256 hex of the canonical value."
++ },
++ "changed": {
++ "type": "boolean"
++ },
++ "condition_met": {
++ "type": "boolean"
++ }
++ }
++ }
++ },
++ "watch.watch.triggered": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "planned",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.watch.triggered.v1.json",
++ "title": "WatchTriggeredPayload",
++ "description": "watch.watch.triggered v1 (OpenVibe.Watch, plan T18; the dossier's watch.triggered, named with three segments as every event type is here — the repo's event-type pattern requires at least three): a watch's condition fired. OpenVibe.Network turns it into a WATCH_TRIGGERED notification for payload.recipient (mirrors deals.watch.matched). Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority important, actor service:watch.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "watch_id",
++ "recipient",
++ "project_id",
++ "name",
++ "condition",
++ "observation",
++ "fired_at"
++ ],
++ "properties": {
++ "watch_id": {
++ "type": "string",
++ "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "recipient": {
++ "type": "string",
++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$",
++ "description": "The watch owner's user subject id: who is notified."
++ },
++ "project_id": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "name": {
++ "type": "string",
++ "minLength": 1,
++ "maxLength": 120
++ },
++ "condition": {
++ "$ref": "../../watch/watch.v1.json#/$defs/condition"
++ },
++ "observation": {
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "id",
++ "observed_at",
++ "value",
++ "previous_value"
++ ],
++ "properties": {
++ "id": {
++ "type": "string",
++ "pattern": "^wco_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "observed_at": {
++ "type": "string",
++ "format": "date-time"
++ },
++ "value": {
++ "description": "The value that fired the condition."
++ },
++ "previous_value": {
++ "description": "The previous observation's value; null when there was none."
++ }
++ }
++ },
++ "fired_at": {
++ "type": "string",
++ "format": "date-time"
++ }
++ }
++ }
++ },
++ "watch.check.failed": {
++ "version": "1.0.0",
++ "owner": "watch",
++ "status": "planned",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/events/payloads/watch.check.failed.v1.json",
++ "title": "WatchCheckFailedPayload",
++ "description": "watch.check.failed v1 (OpenVibe.Watch, plan T18): a check ended in a failure state. consecutive_failures is how many runs in a row have failed, so a consumer can tell a blip from a watch that is down. Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority normal, actor service:watch.",
++ "type": "object",
++ "additionalProperties": false,
++ "required": [
++ "watch_id",
++ "state",
++ "carrier",
++ "http_status",
++ "error_code",
++ "consecutive_failures"
++ ],
++ "properties": {
++ "watch_id": {
++ "type": "string",
++ "pattern": "^wch_[0-9A-HJKMNP-TV-Z]{26}$"
++ },
++ "state": {
++ "enum": [
++ "http_error",
++ "timeout",
++ "parse_error",
++ "rate_limited",
++ "budget_exceeded",
++ "skipped",
++ "disabled"
++ ]
++ },
++ "carrier": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "enum": [
++ "event",
++ "webhook",
++ "http",
++ "feed",
++ "api",
++ "node",
++ "run",
++ null
++ ]
++ },
++ "http_status": {
++ "type": [
++ "integer",
++ "null"
++ ]
++ },
++ "error_code": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "consecutive_failures": {
++ "type": "integer",
++ "minimum": 1
++ }
++ }
++ }
++ },
"games.player.joined": {
"version": "1.0.0",
"owner": "games",
@@@ -61560,7 +62738,7 @@
"type": "string",
"pattern": "^[a-z][a-z0-9-]*:[a-z0-9.-]+$"
},
-- "description": "e.g. node:http, worker:browser, worker:ffmpeg, worker:ai-gpu, events:gateway, events:durable, object:r2. Kind harness: task:edit, task:review, task:browse, task:run, task:test and task:plan for the task kinds it takes (its detail's task_capabilities), and harness:mcp, harness:resume, harness:host-access and harness:long-autonomy for its detail's capabilities that are true. The `worker:<class>` names that map to platform.runtime-class@1 values are reserved for OpenVibe.Node's job worker, one per class: worker:function, worker:code, worker:browser, worker:linux, worker:desktop and worker:gpu ($defs.reservedWorkerCapabilities). A node advertises the name of each class it runs (Node's status.capabilities.worker); every other `worker:` name (worker:ffmpeg, worker:ai-gpu) is an ordinary capability name."
++ "description": "e.g. node:http, worker:browser, worker:ffmpeg, worker:ai-gpu, events:gateway, events:durable, object:r2. Kind harness: task:edit, task:review, task:browse, task:run, task:test and task:plan for the task kinds it takes (its detail's task_capabilities), and harness:mcp, harness:resume, harness:host-access and harness:long-autonomy for its detail's capabilities that are true. The `worker:<class>` names that map to platform.runtime-class@1 values are reserved for OpenVibe.Node's job worker, one per class: worker:function, worker:code, worker:browser, worker:linux, worker:desktop and worker:gpu ($defs.reservedWorkerCapabilities). A node advertises the name of each class it runs (Node's status.capabilities.worker); every other `worker:` name (worker:ffmpeg, worker:ai-gpu) is an ordinary capability name. Beside them, a kind harness names `runtime:<class>` for each platform.runtime-class@1 class it can run (runtime:function, runtime:code, runtime:browser, runtime:linux, runtime:desktop, runtime:gpu); these are ordinary capability names, not reserved, and OpenVibe.Codes already advertises the classes it offers."
},
"capacity": {
"type": "object",
ddiff --git a/generated/openapi/ai.json b/generated/openapi/ai.json
iindex ae082da1..c9228388 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.101.0",
-- "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.AI as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 99b61a6c..58867efb 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.101.0",
-- "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Billing as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 4030a573..1353793f 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.101.0",
-- "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Blog as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 aa5eecf0..e237c984 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.101.0",
-- "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Bot as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 f272b837..6165bfe4 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.101.0",
-- "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Chat as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 98f24c54..2fb5e46a 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.101.0",
-- "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Codes as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 4a22f712..7c587bc9 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.101.0",
-- "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Community as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 a5ed1565..fc0f24ec 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.101.0",
-- "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Coupons as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 946d196e..b73977d2 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.101.0",
-- "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Deals as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 e4336857..3ef82e4f 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.101.0",
-- "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Events as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 cd9abae8..48044a31 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.101.0",
-- "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Games as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 ae541a21..500e060e 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.101.0",
-- "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Host as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 ecc1b170..e473868a 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.101.0",
-- "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Live as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 c83f55e1..de280ed7 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.101.0",
-- "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Media as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 e528dbc4..93f685a3 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.101.0",
-- "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Network as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 040918c5..f8bcdd03 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.101.0",
-- "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.News as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 0a3ee74d..c4c0d20b 100644
---- a/generated/openapi/openre.json
++++ b/generated/openapi/openre.json
@@@ -3,8 +3,8 @@
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "OpenRe.Stream API",
-- "version": "0.101.0",
-- "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenRe.Stream as the OpenVibe contracts describe them (openvibe-contracts 0.102.0): each operation lists the capabilities it performs; a token for the service's audience must carry one of them unless the route is open. Generated by openvibe-contracts lib/openapi.js; do not edit.",
"license": {
"name": "MIT",
"identifier": "MIT"
ddiff --git a/generated/openapi/reviews.json b/generated/openapi/reviews.json
iindex f9155017..6baace4c 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.101.0",
-- "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Reviews as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 9514946a..e21ac475 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.101.0",
-- "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Search as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 f9374a35..d32d22d8 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.101.0",
-- "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Sources as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 16c1f982..1d6a8fda 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.101.0",
-- "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Space as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 ff00b107..aa16c196 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.101.0",
-- "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Tips as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 5fb90a91..c7c5c67c 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.101.0",
-- "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Tools as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 58b61d8d..2eaccc16 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.101.0",
-- "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Trade as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 d39a578a..8d78c9a6 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.101.0",
-- "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.VIP as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 da9bf98d..a09e5a74 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.101.0",
-- "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.101.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.102.0",
++ "description": "Routes of OpenVibe.Wiki as the OpenVibe contracts describe them (openvibe-contracts 0.102.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 ca130f3a..5216b1ac 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -46238,6 +46238,3098 @@ export interface TradeWatchlist {
}[];
}
++/** [email protected] (owner: watch) */
++/**
++ * watch.watch@1: a user-defined persistent observation (plan T18). It names a source (a push event, a webhook, a conditional HTTP URL, a feed or API, a local Node probe, or an expensive Run check), how a value is extracted, how it is compared with the last observation, the condition that fires, the actions it wakes, its budget and its retention. Carrier preference is binding: an event or webhook source is used when one exists, then ETag/Last-Modified, then a feed, then an API, and browser polling through Run only when none works. A price or stock is 'as of' the observation, null when it stated none.
++ */
++export interface Watch {
++ id: string;
++ project_id?: string | null;
++ /**
++ * The acting person or agent the watch belongs to: usr_…, agt_… or svc:….
++ */
++ owner: string;
++ name?: string;
++ labels?: {
++ [k: string]: string | undefined;
++ };
++ status: "active" | "paused" | "disabled" | "failed";
++ source:
++ | {
++ kind: "webhook";
++ endpoint?: string;
++ }
++ | {
++ kind: "event";
++ pattern: string;
++ filter?: {
++ [k: string]: (string | number | boolean | null) | undefined;
++ } | null;
++ }
++ | {
++ kind: "http" | "feed" | "api";
++ url: string;
++ method?: "GET" | "HEAD";
++ format?: "rss" | "atom" | "json" | null;
++ items_path?: string | null;
++ fields?: {
++ [k: string]: string | undefined;
++ } | null;
++ auth?: {
++ mode: "none" | "header" | "bearer" | "query";
++ /**
++ * The name of the environment variable holding the credential; Watch reads it by name at fetch time and never stores the value.
++ */
++ env?: string | null;
++ header?: string | null;
++ param?: string | null;
++ };
++ headers?: {
++ [k: string]: string | undefined;
++ };
++ /**
++ * Send If-None-Match / If-Modified-Since from the stored ETag/Last-Modified when the server gave one.
++ */
++ conditional?: boolean;
++ }
++ | {
++ kind: "node";
++ node_id: string;
++ probe: {
++ [k: string]: unknown | undefined;
++ };
++ }
++ | {
++ kind: "run";
++ runtime: "browser" | "code" | "desktop";
++ url?: string | null;
++ /**
++ * @minItems 1
++ */
++ steps: [
++ {
++ [k: string]: unknown | undefined;
++ },
++ ...{
++ [k: string]: unknown | undefined;
++ }[]
++ ];
++ workload?: WorkloadRequirements;
++ };
++ /**
++ * Required for http/feed/api/node sources; null for event/webhook sources (they never poll).
++ */
++ cadence?: {
++ every_sec?: number;
++ jitter_sec?: number;
++ timezone?: string | null;
++ } | null;
++ extraction: {
++ kind?: "text" | "html" | "json" | "regex" | "css" | "jsonpath" | "ai";
++ selector?: string | null;
++ fields?: {
++ [k: string]: string | undefined;
++ } | null;
++ value_path?: string | null;
++ ai?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ };
++ comparison?: {
++ mode?: "changed" | "threshold" | "none";
++ tolerance?: number | null;
++ percent?: number | null;
++ } | null;
++ condition: {
++ op?: "changed" | "gt" | "gte" | "lt" | "lte" | "eq" | "ne" | "contains" | "matches" | "exists" | "absent";
++ value?: string | number | null;
++ for_sec?: number | null;
++ };
++ /**
++ * @minItems 1
++ * @maxItems 8
++ */
++ action:
++ | [
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ];
++ budget?: {
++ checks_per_day?: number | null;
++ usd_per_month?: number | null;
++ max_runtime_ms?: number | null;
++ max_bytes?: number | null;
++ };
++ retention?: {
++ observations_days?: number | null;
++ keep_snapshots?: boolean;
++ };
++ health?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ created_at: string;
++ updated_at: string;
++}
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.watch-request@1: the body of POST /api/v1/watches and PATCH /api/v1/watches/:id on OpenVibe.Watch (watch.watch.manage; the acting person). Every field is optional on a patch; a create requires source, extraction, condition and action, which the service enforces in code (422 watch.invalid).
++ */
++export interface WatchRequest {
++ name?: string;
++ labels?: {
++ [k: string]: string | undefined;
++ };
++ source?:
++ | {
++ kind: "webhook";
++ endpoint?: string;
++ }
++ | {
++ kind: "event";
++ pattern: string;
++ filter?: {
++ [k: string]: (string | number | boolean | null) | undefined;
++ } | null;
++ }
++ | {
++ kind: "http" | "feed" | "api";
++ url: string;
++ method?: "GET" | "HEAD";
++ format?: "rss" | "atom" | "json" | null;
++ items_path?: string | null;
++ fields?: {
++ [k: string]: string | undefined;
++ } | null;
++ auth?: {
++ mode: "none" | "header" | "bearer" | "query";
++ /**
++ * The name of the environment variable holding the credential; Watch reads it by name at fetch time and never stores the value.
++ */
++ env?: string | null;
++ header?: string | null;
++ param?: string | null;
++ };
++ headers?: {
++ [k: string]: string | undefined;
++ };
++ /**
++ * Send If-None-Match / If-Modified-Since from the stored ETag/Last-Modified when the server gave one.
++ */
++ conditional?: boolean;
++ }
++ | {
++ kind: "node";
++ node_id: string;
++ probe: {
++ [k: string]: unknown | undefined;
++ };
++ }
++ | {
++ kind: "run";
++ runtime: "browser" | "code" | "desktop";
++ url?: string | null;
++ /**
++ * @minItems 1
++ */
++ steps: [
++ {
++ [k: string]: unknown | undefined;
++ },
++ ...{
++ [k: string]: unknown | undefined;
++ }[]
++ ];
++ workload?: WorkloadRequirements;
++ };
++ /**
++ * Required for http/feed/api/node sources; null for event/webhook sources (they never poll).
++ */
++ cadence?: {
++ every_sec?: number;
++ jitter_sec?: number;
++ timezone?: string | null;
++ } | null;
++ extraction?: {
++ kind?: "text" | "html" | "json" | "regex" | "css" | "jsonpath" | "ai";
++ selector?: string | null;
++ fields?: {
++ [k: string]: string | undefined;
++ } | null;
++ value_path?: string | null;
++ ai?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ };
++ comparison?: {
++ mode?: "changed" | "threshold" | "none";
++ tolerance?: number | null;
++ percent?: number | null;
++ } | null;
++ condition?: {
++ op?: "changed" | "gt" | "gte" | "lt" | "lte" | "eq" | "ne" | "contains" | "matches" | "exists" | "absent";
++ value?: string | number | null;
++ for_sec?: number | null;
++ };
++ /**
++ * @minItems 1
++ * @maxItems 8
++ */
++ action?:
++ | [
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ]
++ | [
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ ),
++ (
++ | {
++ kind: "notification";
++ category?: "service" | "social" | "system";
++ priority?: "low" | "normal" | "high" | "critical";
++ }
++ | {
++ kind: "event";
++ event_type: string;
++ payload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ | {
++ kind: "webhook";
++ url: string;
++ secret_env: string;
++ }
++ | {
++ kind: "actor-task";
++ brief: string;
++ budget_usd?: number | null;
++ }
++ | {
++ kind: "codes-run";
++ repo: string;
++ brief: string;
++ }
++ | {
++ kind: "run-job";
++ runtime: "function" | "code" | "browser" | "linux";
++ command: string;
++ workload?: {
++ [k: string]: unknown | undefined;
++ } | null;
++ }
++ )
++ ];
++ budget?: {
++ checks_per_day?: number | null;
++ usd_per_month?: number | null;
++ max_runtime_ms?: number | null;
++ max_bytes?: number | null;
++ };
++ retention?: {
++ observations_days?: number | null;
++ keep_snapshots?: boolean;
++ };
++ status?: "active" | "paused" | "disabled" | "failed";
++}
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.watch-result@1: answers of the watch routes on OpenVibe.Watch. GET /api/v1/watches → { watches } and POST /api/v1/watches → 201 { watch } (watch.watch.read, watch.watch.manage); PATCH → { watch }; POST /:id/pause and /:id/resume → { id, status }; DELETE /api/v1/watches/:id → { id, deleted: true }.
++ */
++export type WatchResult =
++ | {
++ watches: Watch[];
++ }
++ | {
++ watch: Watch;
++ }
++ | {
++ id: string;
++ status: "active" | "paused" | "disabled" | "failed";
++ }
++ | {
++ id: string;
++ deleted: true;
++ };
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.observation@1: one value a check recorded for a watch (plan T18): what was extracted, when, from which check run, and whether it changed or met the condition. value is the extracted value exactly as the source stated it, never inferred; snapshot is a capped copy of the raw body kept according to the watch's retention. Rows are immutable.
++ */
++export interface WatchObservation {
++ id: string;
++ watch_id: string;
++ check_run_id: string;
++ observed_at: string;
++ /**
++ * The extracted value as the source stated it: text, a decimal number, a structured object.
++ */
++ value: {
++ [k: string]: unknown | undefined;
++ };
++ /**
++ * SHA-256 hex of the canonical value.
++ */
++ value_hash: string;
++ /**
++ * SHA-256 of the previous observation's value; null for the first observation.
++ */
++ previous_hash: string | null;
++ changed: boolean;
++ condition_met: boolean;
++ snapshot: string | null;
++}
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.check-run@1: one execution of a watch's check (plan T18), by schedule, manually, or from a delivered event or webhook. carrier names the mechanism that carried it; state is the terminal state (the same values the service's check_runs.state CHECK allows). observations is how many observations the run recorded and triggers how many conditions it fired; cost_usd is what the run cost. Rows are immutable.
++ */
++export interface WatchCheckRun {
++ id: string;
++ watch_id: string;
++ trigger: "schedule" | "manual" | "event" | "webhook";
++ carrier: "event" | "webhook" | "http" | "feed" | "api" | "node" | "run" | null;
++ started_at: string;
++ finished_at: string;
++ state:
++ | "ok"
++ | "not_modified"
++ | "no_change"
++ | "changed"
++ | "condition_met"
++ | "http_error"
++ | "timeout"
++ | "parse_error"
++ | "rate_limited"
++ | "budget_exceeded"
++ | "skipped"
++ | "disabled";
++ http_status: number | null;
++ observations: number;
++ triggers: number;
++ cost_usd: number;
++ detail: string | null;
++}
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.observation.recorded v1 (OpenVibe.Watch, plan T18): a check recorded an observation for a watch. It carries the extracted value as the source stated it and its hash, never the raw body. Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority low, actor service:watch. Watch's own records are the full observation (watch.observation@1); this event is the notification that one exists.
++ */
++export interface WatchObservationRecordedPayload {
++ watch_id: string;
++ /**
++ * The watch owner's subject id: who this observation is for.
++ */
++ owner: string;
++ observed_at: string;
++ /**
++ * The extracted value as the source stated it; null when it stated none.
++ */
++ value: {
++ [k: string]: unknown | undefined;
++ };
++ /**
++ * SHA-256 hex of the canonical value.
++ */
++ value_hash: string;
++ changed: boolean;
++ condition_met: boolean;
++}
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.watch.triggered v1 (OpenVibe.Watch, plan T18; the dossier's watch.triggered, named with three segments as every event type is here — the repo's event-type pattern requires at least three): a watch's condition fired. OpenVibe.Network turns it into a WATCH_TRIGGERED notification for payload.recipient (mirrors deals.watch.matched). Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority important, actor service:watch.
++ */
++export interface WatchTriggeredPayload {
++ watch_id: string;
++ /**
++ * The watch owner's user subject id: who is notified.
++ */
++ recipient: string;
++ project_id: string | null;
++ name: string;
++ condition: {
++ op?: "changed" | "gt" | "gte" | "lt" | "lte" | "eq" | "ne" | "contains" | "matches" | "exists" | "absent";
++ value?: string | number | null;
++ for_sec?: number | null;
++ };
++ observation: {
++ id: string;
++ observed_at: string;
++ /**
++ * The value that fired the condition.
++ */
++ value: {
++ [k: string]: unknown | undefined;
++ };
++ /**
++ * The previous observation's value; null when there was none.
++ */
++ previous_value: {
++ [k: string]: unknown | undefined;
++ };
++ };
++ fired_at: string;
++}
++
++/** [email protected] (owner: watch) */
++/**
++ * watch.check.failed v1 (OpenVibe.Watch, plan T18): a check ended in a failure state. consecutive_failures is how many runs in a row have failed, so a consumer can tell a blip from a watch that is down. Envelope: subject { type: watch, id: <watch_id> }, visibility internal, priority normal, actor service:watch.
++ */
++export interface WatchCheckFailedPayload {
++ watch_id: string;
++ state: "http_error" | "timeout" | "parse_error" | "rate_limited" | "budget_exceeded" | "skipped" | "disabled";
++ carrier: "event" | "webhook" | "http" | "feed" | "api" | "node" | "run" | null;
++ http_status: number | null;
++ error_code: string | null;
++ consecutive_failures: number;
++}
++
/** [email protected] (owner: games) */
/**
* games.player.joined v1 (OpenVibe.Games apps/server/src/platform/gameEvents.ts playerJoinedEvent, via GameEventRecorder.recordJoin from game/gameServer.ts handleHello). A character entered the world: written to Games' event_outbox in a transaction of its own once the session exists and the welcome was sent (a new character's row is first written by its next save). restored is true when the character already existed in the database, false for a new one. Only emitted while Events publishing is configured. No position, appearance, inventory, rank or connection data. Envelope: subject { type: player, id: <player.id> }, visibility subject when the player has a Network subject and internal otherwise, priority low, actor user:<usr_...> or guest:<gst_...> from player.subject, else service:games. No consumer yet.
@@@ -51677,7 +54769,7 @@ export type ResourceOffer = {
*/
trust: "first-party" | "user-owned" | "partner" | "community" | "external";
/**
-- * e.g. node:http, worker:browser, worker:ffmpeg, worker:ai-gpu, events:gateway, events:durable, object:r2. Kind harness: task:edit, task:review, task:browse, task:run, task:test and task:plan for the task kinds it takes (its detail's task_capabilities), and harness:mcp, harness:resume, harness:host-access and harness:long-autonomy for its detail's capabilities that are true. The `worker:<class>` names that map to platform.runtime-class@1 values are reserved for OpenVibe.Node's job worker, one per class: worker:function, worker:code, worker:browser, worker:linux, worker:desktop and worker:gpu ($defs.reservedWorkerCapabilities). A node advertises the name of each class it runs (Node's status.capabilities.worker); every other `worker:` name (worker:ffmpeg, worker:ai-gpu) is an ordinary capability name.
++ * e.g. node:http, worker:browser, worker:ffmpeg, worker:ai-gpu, events:gateway, events:durable, object:r2. Kind harness: task:edit, task:review, task:browse, task:run, task:test and task:plan for the task kinds it takes (its detail's task_capabilities), and harness:mcp, harness:resume, harness:host-access and harness:long-autonomy for its detail's capabilities that are true. The `worker:<class>` names that map to platform.runtime-class@1 values are reserved for OpenVibe.Node's job worker, one per class: worker:function, worker:code, worker:browser, worker:linux, worker:desktop and worker:gpu ($defs.reservedWorkerCapabilities). A node advertises the name of each class it runs (Node's status.capabilities.worker); every other `worker:` name (worker:ffmpeg, worker:ai-gpu) is an ordinary capability name. Beside them, a kind harness names `runtime:<class>` for each platform.runtime-class@1 class it can run (runtime:function, runtime:code, runtime:browser, runtime:linux, runtime:desktop, runtime:gpu); these are ordinary capability names, not reserved, and OpenVibe.Codes already advertises the classes it offers.
*/
capabilities: string[];
capacity?: {
ddiff --git a/manifests/capabilities/watch.check.run.json b/manifests/capabilities/watch.check.run.json
nnew file mode 100644
iindex 00000000..4e5e6ba9
---- /dev/null
++++ b/manifests/capabilities/watch.check.run.json
@@@ -0,0 +1,19 @@
++{
++ "id": "watch.check.run",
++ "version": "1.0",
++ "owner": "watch",
++ "status": "planned",
++ "visibility": "first-party",
++ "description": "PLANNED (plan T18; OpenVibe.Watch is not built yet): Run one check of a watch now, outside its cadence: POST /api/v1/watches/:id/check (409 watch.busy when one is already running). It becomes active, and enters generated/openapi/watch.json, when OpenVibe.Watch implements the route.",
++ "permissions": [
++ "watch:run"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "watch-run",
++ "events": [],
++ "implementedBy": [],
++ "inputSchema": "common.no-body@1",
++ "outputSchema": "watch.check-run@1"
++}
ddiff --git a/manifests/capabilities/watch.observation.read.json b/manifests/capabilities/watch.observation.read.json
nnew file mode 100644
iindex 00000000..87e415a7
---- /dev/null
++++ b/manifests/capabilities/watch.observation.read.json
@@@ -0,0 +1,19 @@
++{
++ "id": "watch.observation.read",
++ "version": "1.0",
++ "owner": "watch",
++ "status": "planned",
++ "visibility": "first-party",
++ "description": "PLANNED (plan T18; OpenVibe.Watch is not built yet): Read a watch's observations and check runs: GET /api/v1/watches/:id/observations and GET /api/v1/watches/:id/checks. It becomes active, and enters generated/openapi/watch.json, when OpenVibe.Watch implements the routes.",
++ "permissions": [
++ "watch:read"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "watch-read",
++ "events": [],
++ "implementedBy": [],
++ "inputSchema": "common.no-body@1",
++ "outputSchema": "watch.observation@1"
++}
ddiff --git a/manifests/capabilities/watch.watch.manage.json b/manifests/capabilities/watch.watch.manage.json
nnew file mode 100644
iindex 00000000..a6c970fa
---- /dev/null
++++ b/manifests/capabilities/watch.watch.manage.json
@@@ -0,0 +1,24 @@
++{
++ "id": "watch.watch.manage",
++ "version": "1.0",
++ "owner": "watch",
++ "status": "planned",
++ "visibility": "first-party",
++ "description": "PLANNED (plan T18; OpenVibe.Watch is not built yet): Create, change, pause, resume and delete a watch: POST /api/v1/watches, PATCH /api/v1/watches/:id, POST /api/v1/watches/:id/pause, POST /api/v1/watches/:id/resume and DELETE /api/v1/watches/:id. It becomes active, and enters generated/openapi/watch.json, when OpenVibe.Watch implements the routes.",
++ "permissions": [
++ "watch:manage"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "watch-write",
++ "events": [
++ "watch.watch.created",
++ "watch.watch.updated",
++ "watch.watch.paused",
++ "watch.watch.removed"
++ ],
++ "implementedBy": [],
++ "inputSchema": "watch.watch-request@1",
++ "outputSchema": "watch.watch-result@1"
++}
ddiff --git a/manifests/capabilities/watch.watch.read.json b/manifests/capabilities/watch.watch.read.json
nnew file mode 100644
iindex 00000000..137c0df4
---- /dev/null
++++ b/manifests/capabilities/watch.watch.read.json
@@@ -0,0 +1,19 @@
++{
++ "id": "watch.watch.read",
++ "version": "1.0",
++ "owner": "watch",
++ "status": "planned",
++ "visibility": "first-party",
++ "description": "PLANNED (plan T18; OpenVibe.Watch is not built yet): List and read the acting person's or project's watches: GET /api/v1/watches and GET /api/v1/watches/:id. It becomes active, and enters generated/openapi/watch.json, when OpenVibe.Watch implements the routes.",
++ "permissions": [
++ "watch:read"
++ ],
++ "resourceConstraints": [
++ "owner"
++ ],
++ "quotaClass": "watch-read",
++ "events": [],
++ "implementedBy": [],
++ "inputSchema": "common.no-body@1",
++ "outputSchema": "watch.watch-result@1"
++}
ddiff --git a/manifests/products/openvibe.watch.json b/manifests/products/openvibe.watch.json
iindex 515ab22f..7290a706 100644
---- a/manifests/products/openvibe.watch.json
++++ b/manifests/products/openvibe.watch.json
@@@ -27,6 +27,7 @@
"keywords": "website change monitoring, uptime monitoring api, price drop alerts, restock alerts, release monitoring, youtube video analysis, security camera alerts",
"launch": "the watch service on the shared queue and workers",
"relationships": {
++ "service": "watch",
"noRepo": true,
"meanwhile": [
{
ddiff --git a/manifests/services/watch.json b/manifests/services/watch.json
nnew file mode 100644
iindex 00000000..4093328d
---- /dev/null
++++ b/manifests/services/watch.json
@@@ -0,0 +1,57 @@
++{
++ "version": "0.0.0",
++ "contractRanges": {
++ "openvibe-contracts": ">=0.102.0 <1.0.0"
++ },
++ "id": "watch",
++ "name": "OpenVibe.Watch",
++ "status": "placeholder",
++ "repository": "OpenVibers/OpenVibe.Watch",
++ "domains": [
++ "openvibe.watch"
++ ],
++ "publicOrigin": "https://openvibe.watch",
++ "exposure": {
++ "state": "placeholder",
++ "publicSite": null,
++ "note": "planned (plan T18); the OpenVibe.Watch repository does not exist yet, and nothing serves openvibe.watch"
++ },
++ "capabilities": [
++ "watch.watch.read",
++ "watch.watch.manage",
++ "watch.observation.read",
++ "watch.check.run"
++ ],
++ "eventsProduced": [
++ "watch.watch.created",
++ "watch.watch.updated",
++ "watch.watch.paused",
++ "watch.watch.removed",
++ "watch.observation.recorded",
++ "watch.watch.triggered",
++ "watch.check.failed"
++ ],
++ "eventsConsumed": [],
++ "namespacesOwned": [],
++ "lifecycle": {
++ "liveness": {
++ "none": "not built yet; nothing listens on a loopback address"
++ },
++ "shutdown": {
++ "none": "not built yet; nothing runs or drains"
++ },
++ "startupRecovery": {
++ "none": "not built yet; nothing starts"
++ },
++ "rollback": {
++ "none": "not built yet; nothing is released or rolled back"
++ },
++ "contracts": {
++ "range": ">=0.102.0 <1.0.0"
++ },
++ "leases": {
++ "none": "not built yet; nothing runs"
++ }
++ },
++ "notes": "The watch service of the network (plan T18): a user defines persistent observations and conditions over pages, feeds, APIs, events, releases, streams and local devices, and is told when they change or wakes an Actor task, a Codes run, a Run job or a webhook. Sources ingests structured sources, Run runs expensive browser/code checks, Node observes local/LAN things, Events transports the trigger. Planned: nothing is built; the OpenVibe.Watch repository does not exist yet."
++}
ddiff --git a/package-lock.json b/package-lock.json
iindex 9c4f7e21..626c49eb 100644
---- a/package-lock.json
++++ b/package-lock.json
@@@ -1,12 +1,12 @@
{
"name": "openvibe-contracts",
-- "version": "0.101.0",
++ "version": "0.102.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openvibe-contracts",
-- "version": "0.101.0",
++ "version": "0.102.0",
"license": "AGPL-3.0-only",
"dependencies": {
"ajv": "^8.17.1",
ddiff --git a/package.json b/package.json
iindex 14eae2fd..ed2e7bed 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.101.0",
++ "version": "0.102.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",