openvibers/openvibe.contracts Commits

Capability schemas (WS-C task 4), Search first: search.query@1, search.query-result@1, search.write-result@1 on search.query.run, search.query.delegate and search.document.write (unreleased)

OP OpenVibers committed 25 Sept 2026 · 20c2bea7b3 · 16 files, +608 −3


Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex fbdd262c..d9dacd18 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
++## Unreleased
++
++Capability schemas (roadmap WS-C task 4), starting with Search: **`search.query@1`** (the query string of `GET /api/v1/search` and `/suggest`: q, owner, type, lang, facets, limit, cursor, `facet.<key>`), **`search.query-result@1`** (a page of hits the caller may see, `next_cursor`, facet counts; never an ACL or a total) and **`search.write-result@1`** (`PUT /api/v1/documents/…`: applied or unchanged; stale and conflicting revisions are 409 problems). `search.query.run` and `search.query.delegate` name the first two; `search.document.write` names the third as its output. Fixtures for each. Additive.
++
## 0.49.0 — 2026-09-25
Platform blocks (roadmap WS-E task 5). **`network.block.changed`**: a person blocked or unblocked someone (`blocker`, `blocked`, `active`, a per-pair `revision`); Network keeps the blocks, keyed by subjects, and Chat and Community consume the event. New capability **`network.blocks.read`** (first-party, never for apps): `GET /internal/blocks?subject=` lists who a person blocked and who blocked them. Fixtures for a block and an unblock. Additive.
ddiff --git a/contracts/catalog.json b/contracts/catalog.json
iindex b163f3f0..29c45514 100644
---- a/contracts/catalog.json
++++ b/contracts/catalog.json
@@@ -146,6 +146,33 @@
"status": "active",
"adr": "ADR-018"
},
++ {
++ "id": "search.query",
++ "version": "1.0.0",
++ "owner": "search",
++ "schema": "search/query.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "search.query-result",
++ "version": "1.0.0",
++ "owner": "search",
++ "schema": "search/query-result.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
++ {
++ "id": "search.write-result",
++ "version": "1.0.0",
++ "owner": "search",
++ "schema": "search/write-result.v1.json",
++ "visibility": "first-party",
++ "compatibility": "backward",
++ "status": "active"
++ },
{
"id": "sources.source",
"version": "1.0.0",
ddiff --git a/contracts/search/query-result.v1.json b/contracts/search/query-result.v1.json
nnew file mode 100644
iindex 00000000..599bd32c
---- /dev/null
++++ b/contracts/search/query-result.v1.json
@@@ -0,0 +1,40 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/search/query-result.v1.json",
++ "title": "SearchQueryResult",
++ "description": "search.query-result@1: the answer of GET /api/v1/search — one page of hits the caller may see, a cursor for the next page, and facet counts when asked. Never a total count and never an ACL.",
++ "type": "object",
++ "required": ["results", "next_cursor"],
++ "additionalProperties": false,
++ "properties": {
++ "results": {
++ "type": "array",
++ "maxItems": 100,
++ "items": {
++ "type": "object",
++ "required": ["owner", "type", "id"],
++ "additionalProperties": false,
++ "properties": {
++ "owner": { "type": "string" },
++ "type": { "type": "string" },
++ "id": { "type": "string" },
++ "revision": { "type": "integer", "minimum": 0 },
++ "visibility": { "type": "string" },
++ "title": { "type": ["string", "null"] },
++ "summary": { "type": ["string", "null"] },
++ "canonical_url": { "type": ["string", "null"] },
++ "facets": { "type": ["object", "null"] },
++ "language": { "type": ["string", "null"] },
++ "authorship": { "type": ["string", "null"] },
++ "provenance": { "type": ["array", "object", "null"] },
++ "published_at": { "type": ["string", "null"] },
++ "updated_at": { "type": ["string", "null"] },
++ "indexable": { "type": "boolean", "description": "false for a noindex document the caller may still see." },
++ "snippet_html": { "type": ["string", "null"], "description": "Escaped text with <mark> around the matches; nothing else." }
++ }
++ }
++ },
++ "next_cursor": { "type": ["string", "null"] },
++ "facets": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "object", "required": ["value", "count"], "properties": { "value": { "type": "string" }, "count": { "type": "integer", "minimum": 0 } } } } }
++ }
++}
ddiff --git a/contracts/search/query.v1.json b/contracts/search/query.v1.json
nnew file mode 100644
iindex 00000000..bc91cd74
---- /dev/null
++++ b/contracts/search/query.v1.json
@@@ -0,0 +1,23 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/search/query.v1.json",
++ "title": "SearchQuery",
++ "description": "search.query@1: the query string of GET /api/v1/search (and, with q/owner/type/limit only, GET /api/v1/suggest), capabilities search.query.run and search.query.delegate. Who sees what is decided by Search per hit: anonymous callers get public, published, indexable documents; a person also restricted documents naming them; a delegating service passes X-OV-Subject. Filters narrow; they never widen visibility.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "q": { "type": "string", "maxLength": 200, "description": "Words to match (FTS5; empty lists by recency)." },
++ "owner": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,31}$", "description": "One owner service (live, community, wiki, …)." },
++ "type": { "type": "string", "pattern": "^[a-z][a-z0-9_-]{0,31}$", "description": "One document type within the owner (channel, vod, thread, …)." },
++ "lang": { "type": "string", "pattern": "^[a-zA-Z]{2,3}(-[A-Za-z0-9]{2,8})*$", "description": "BCP 47 language." },
++ "facets": { "type": "string", "maxLength": 400, "description": "Comma-separated facet keys to count over what the caller can see." },
++ "limit": { "type": ["integer", "string"], "pattern": "^[0-9]{1,3}$", "minimum": 1, "maximum": 100 },
++ "cursor": { "type": "string", "maxLength": 512, "description": "next_cursor of the previous page." }
++ },
++ "patternProperties": {
++ "^facet\\.[a-z][a-z0-9_]{0,39}$": {
++ "description": "A facet filter (facet.<key>=<value>); repeat the parameter for several values.",
++ "oneOf": [ { "type": "string", "maxLength": 200 }, { "type": "array", "maxItems": 20, "items": { "type": "string", "maxLength": 200 } } ]
++ }
++ }
++}
ddiff --git a/contracts/search/write-result.v1.json b/contracts/search/write-result.v1.json
nnew file mode 100644
iindex 00000000..d93a0340
---- /dev/null
++++ b/contracts/search/write-result.v1.json
@@@ -0,0 +1,15 @@
++{
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/search/write-result.v1.json",
++ "title": "SearchWriteResult",
++ "description": "search.write-result@1: the answer of PUT /api/v1/documents/:owner/:type/:id (search.document.write). applied: stored (or a tombstone recorded); unchanged: the same revision with the same content. A revision older than the stored one is a 409 problem search.stale_revision; the same revision with different content is 409 search.revision_conflict.",
++ "type": "object",
++ "required": ["outcome", "revision"],
++ "additionalProperties": false,
++ "properties": {
++ "outcome": { "enum": ["applied", "unchanged"] },
++ "revision": { "type": "integer", "minimum": 1 },
++ "stored_revision": { "type": ["integer", "null"], "description": "What Search held before this write (null: nothing)." },
++ "deleted": { "type": "boolean" }
++ }
++}
ddiff --git a/fixtures/search.query-result/invalid/leaks-acl.json b/fixtures/search.query-result/invalid/leaks-acl.json
nnew file mode 100644
iindex 00000000..9179b7db
---- /dev/null
++++ b/fixtures/search.query-result/invalid/leaks-acl.json
@@@ -0,0 +1 @@
++{ "results": [ { "owner": "live", "type": "vod", "id": "912", "acl": ["usr_x"] } ], "next_cursor": null }
ddiff --git a/fixtures/search.query-result/valid/page.json b/fixtures/search.query-result/valid/page.json
nnew file mode 100644
iindex 00000000..abb50b7c
---- /dev/null
++++ b/fixtures/search.query-result/valid/page.json
@@@ -0,0 +1 @@
++{ "results": [ { "owner": "live", "type": "vod", "id": "912", "revision": 3, "visibility": "public", "title": "Building a forum", "summary": null, "canonical_url": "https://openvibe.live/vod/912", "facets": { "channel": "alex" }, "language": null, "authorship": "human", "provenance": [], "published_at": "2026-09-24T19:00:00.000Z", "updated_at": null, "indexable": true, "snippet_html": "building a <mark>forum</mark>" } ], "next_cursor": null }
ddiff --git a/fixtures/search.query/invalid/bad-facet-key.json b/fixtures/search.query/invalid/bad-facet-key.json
nnew file mode 100644
iindex 00000000..a63cfc37
---- /dev/null
++++ b/fixtures/search.query/invalid/bad-facet-key.json
@@@ -0,0 +1 @@
++{ "q": "x", "facet.Bad Key": "y" }
ddiff --git a/fixtures/search.query/valid/filtered.json b/fixtures/search.query/valid/filtered.json
nnew file mode 100644
iindex 00000000..71421098
---- /dev/null
++++ b/fixtures/search.query/valid/filtered.json
@@@ -0,0 +1 @@
++{ "q": "minecraft", "owner": "live", "type": "vod", "limit": "24", "facet.channel": "alex", "facets": "category,channel" }
ddiff --git a/fixtures/search.write-result/invalid/stale-is-a-problem.json b/fixtures/search.write-result/invalid/stale-is-a-problem.json
nnew file mode 100644
iindex 00000000..6f638642
---- /dev/null
++++ b/fixtures/search.write-result/invalid/stale-is-a-problem.json
@@@ -0,0 +1 @@
++{ "outcome": "stale", "revision": 1 }
ddiff --git a/fixtures/search.write-result/valid/applied.json b/fixtures/search.write-result/valid/applied.json
nnew file mode 100644
iindex 00000000..42db74e1
---- /dev/null
++++ b/fixtures/search.write-result/valid/applied.json
@@@ -0,0 +1 @@
++{ "outcome": "applied", "revision": 2, "stored_revision": 1, "deleted": false }
ddiff --git a/generated/json-schema/bundle.json b/generated/json-schema/bundle.json
iindex 6d1c7e5f..b0fd814d 100644
---- a/generated/json-schema/bundle.json
++++ b/generated/json-schema/bundle.json
@@@ -1860,6 +1860,262 @@
}
}
},
++ "search.query": {
++ "version": "1.0.0",
++ "owner": "search",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/search/query.v1.json",
++ "title": "SearchQuery",
++ "description": "search.query@1: the query string of GET /api/v1/search (and, with q/owner/type/limit only, GET /api/v1/suggest), capabilities search.query.run and search.query.delegate. Who sees what is decided by Search per hit: anonymous callers get public, published, indexable documents; a person also restricted documents naming them; a delegating service passes X-OV-Subject. Filters narrow; they never widen visibility.",
++ "type": "object",
++ "additionalProperties": false,
++ "properties": {
++ "q": {
++ "type": "string",
++ "maxLength": 200,
++ "description": "Words to match (FTS5; empty lists by recency)."
++ },
++ "owner": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_-]{0,31}$",
++ "description": "One owner service (live, community, wiki, …)."
++ },
++ "type": {
++ "type": "string",
++ "pattern": "^[a-z][a-z0-9_-]{0,31}$",
++ "description": "One document type within the owner (channel, vod, thread, …)."
++ },
++ "lang": {
++ "type": "string",
++ "pattern": "^[a-zA-Z]{2,3}(-[A-Za-z0-9]{2,8})*$",
++ "description": "BCP 47 language."
++ },
++ "facets": {
++ "type": "string",
++ "maxLength": 400,
++ "description": "Comma-separated facet keys to count over what the caller can see."
++ },
++ "limit": {
++ "type": [
++ "integer",
++ "string"
++ ],
++ "pattern": "^[0-9]{1,3}$",
++ "minimum": 1,
++ "maximum": 100
++ },
++ "cursor": {
++ "type": "string",
++ "maxLength": 512,
++ "description": "next_cursor of the previous page."
++ }
++ },
++ "patternProperties": {
++ "^facet\\.[a-z][a-z0-9_]{0,39}$": {
++ "description": "A facet filter (facet.<key>=<value>); repeat the parameter for several values.",
++ "oneOf": [
++ {
++ "type": "string",
++ "maxLength": 200
++ },
++ {
++ "type": "array",
++ "maxItems": 20,
++ "items": {
++ "type": "string",
++ "maxLength": 200
++ }
++ }
++ ]
++ }
++ }
++ }
++ },
++ "search.query-result": {
++ "version": "1.0.0",
++ "owner": "search",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/search/query-result.v1.json",
++ "title": "SearchQueryResult",
++ "description": "search.query-result@1: the answer of GET /api/v1/search — one page of hits the caller may see, a cursor for the next page, and facet counts when asked. Never a total count and never an ACL.",
++ "type": "object",
++ "required": [
++ "results",
++ "next_cursor"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "results": {
++ "type": "array",
++ "maxItems": 100,
++ "items": {
++ "type": "object",
++ "required": [
++ "owner",
++ "type",
++ "id"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "owner": {
++ "type": "string"
++ },
++ "type": {
++ "type": "string"
++ },
++ "id": {
++ "type": "string"
++ },
++ "revision": {
++ "type": "integer",
++ "minimum": 0
++ },
++ "visibility": {
++ "type": "string"
++ },
++ "title": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "summary": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "canonical_url": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "facets": {
++ "type": [
++ "object",
++ "null"
++ ]
++ },
++ "language": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "authorship": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "provenance": {
++ "type": [
++ "array",
++ "object",
++ "null"
++ ]
++ },
++ "published_at": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "updated_at": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "indexable": {
++ "type": "boolean",
++ "description": "false for a noindex document the caller may still see."
++ },
++ "snippet_html": {
++ "type": [
++ "string",
++ "null"
++ ],
++ "description": "Escaped text with <mark> around the matches; nothing else."
++ }
++ }
++ }
++ },
++ "next_cursor": {
++ "type": [
++ "string",
++ "null"
++ ]
++ },
++ "facets": {
++ "type": "object",
++ "additionalProperties": {
++ "type": "array",
++ "items": {
++ "type": "object",
++ "required": [
++ "value",
++ "count"
++ ],
++ "properties": {
++ "value": {
++ "type": "string"
++ },
++ "count": {
++ "type": "integer",
++ "minimum": 0
++ }
++ }
++ }
++ }
++ }
++ }
++ }
++ },
++ "search.write-result": {
++ "version": "1.0.0",
++ "owner": "search",
++ "status": "active",
++ "schema": {
++ "$schema": "https://json-schema.org/draft/2020-12/schema",
++ "$id": "https://openvibe.network/contracts/search/write-result.v1.json",
++ "title": "SearchWriteResult",
++ "description": "search.write-result@1: the answer of PUT /api/v1/documents/:owner/:type/:id (search.document.write). applied: stored (or a tombstone recorded); unchanged: the same revision with the same content. A revision older than the stored one is a 409 problem search.stale_revision; the same revision with different content is 409 search.revision_conflict.",
++ "type": "object",
++ "required": [
++ "outcome",
++ "revision"
++ ],
++ "additionalProperties": false,
++ "properties": {
++ "outcome": {
++ "enum": [
++ "applied",
++ "unchanged"
++ ]
++ },
++ "revision": {
++ "type": "integer",
++ "minimum": 1
++ },
++ "stored_revision": {
++ "type": [
++ "integer",
++ "null"
++ ],
++ "description": "What Search held before this write (null: nothing)."
++ },
++ "deleted": {
++ "type": "boolean"
++ }
++ }
++ }
++ },
"sources.source": {
"version": "1.0.0",
"owner": "sources",
ddiff --git a/generated/typescript/index.d.ts b/generated/typescript/index.d.ts
iindex 95b600ec..e2c233fc 100644
---- a/generated/typescript/index.d.ts
++++ b/generated/typescript/index.d.ts
@@@ -839,6 +839,235 @@ export interface IndexDocument {
};
}
++/** [email protected] (owner: search) */
++/**
++ * search.query@1: the query string of GET /api/v1/search (and, with q/owner/type/limit only, GET /api/v1/suggest), capabilities search.query.run and search.query.delegate. Who sees what is decided by Search per hit: anonymous callers get public, published, indexable documents; a person also restricted documents naming them; a delegating service passes X-OV-Subject. Filters narrow; they never widen visibility.
++ */
++export interface SearchQuery {
++ /**
++ * Words to match (FTS5; empty lists by recency).
++ */
++ q?: string;
++ /**
++ * One owner service (live, community, wiki, …).
++ */
++ owner?: string;
++ /**
++ * One document type within the owner (channel, vod, thread, …).
++ */
++ type?: string;
++ /**
++ * BCP 47 language.
++ */
++ lang?: string;
++ /**
++ * Comma-separated facet keys to count over what the caller can see.
++ */
++ facets?: string;
++ limit?: number | string;
++ /**
++ * next_cursor of the previous page.
++ */
++ cursor?: string;
++ /**
++ * A facet filter (facet.<key>=<value>); repeat the parameter for several values.
++ *
++ * This interface was referenced by `SearchQuery`'s JSON-Schema definition
++ * via the `patternProperty` "^facet\.[a-z][a-z0-9_]{0,39}$".
++ */
++ [k: string]:
++ | string
++ | []
++ | [string]
++ | [string, string]
++ | [string, string, string]
++ | [string, string, string, string]
++ | [string, string, string, string, string]
++ | [string, string, string, string, string, string]
++ | [string, string, string, string, string, string, string]
++ | [string, string, string, string, string, string, string, string]
++ | [string, string, string, string, string, string, string, string, string]
++ | [string, string, string, string, string, string, string, string, string, string]
++ | [string, string, string, string, string, string, string, string, string, string, string]
++ | [string, string, string, string, string, string, string, string, string, string, string, string]
++ | [string, string, string, string, string, string, string, string, string, string, string, string, string]
++ | [string, string, string, string, string, string, string, string, string, string, string, string, string, string]
++ | [
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string
++ ]
++ | [
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string
++ ]
++ | [
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string
++ ]
++ | [
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string
++ ]
++ | [
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string
++ ]
++ | [
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string,
++ string
++ ];
++}
++
++/** [email protected] (owner: search) */
++/**
++ * search.query-result@1: the answer of GET /api/v1/search — one page of hits the caller may see, a cursor for the next page, and facet counts when asked. Never a total count and never an ACL.
++ */
++export interface SearchQueryResult {
++ /**
++ * @maxItems 100
++ */
++ results: {
++ owner: string;
++ type: string;
++ id: string;
++ revision?: number;
++ visibility?: string;
++ title?: string | null;
++ summary?: string | null;
++ canonical_url?: string | null;
++ facets?: {} | null;
++ language?: string | null;
++ authorship?: string | null;
++ provenance?: unknown[] | {} | null;
++ published_at?: string | null;
++ updated_at?: string | null;
++ /**
++ * false for a noindex document the caller may still see.
++ */
++ indexable?: boolean;
++ /**
++ * Escaped text with <mark> around the matches; nothing else.
++ */
++ snippet_html?: string | null;
++ }[];
++ next_cursor: string | null;
++ facets?: {
++ [k: string]:
++ | {
++ value: string;
++ count: number;
++ }[]
++ | undefined;
++ };
++}
++
++/** [email protected] (owner: search) */
++/**
++ * search.write-result@1: the answer of PUT /api/v1/documents/:owner/:type/:id (search.document.write). applied: stored (or a tombstone recorded); unchanged: the same revision with the same content. A revision older than the stored one is a 409 problem search.stale_revision; the same revision with different content is 409 search.revision_conflict.
++ */
++export interface SearchWriteResult {
++ outcome: "applied" | "unchanged";
++ revision: number;
++ /**
++ * What Search held before this write (null: nothing).
++ */
++ stored_revision?: number | null;
++ deleted?: boolean;
++}
++
/** [email protected] (owner: sources) */
/**
* A registered source (roadmap §4.2 B, Wave 14): where it is fetched from and on what terms. Credentials are referenced by environment-variable NAME only. A source's existence is never permission to fetch: robots and terms are verified before it is enabled, and the fetcher re-checks robots.txt on every run.
ddiff --git a/manifests/capabilities/search.document.write.json b/manifests/capabilities/search.document.write.json
iindex db4255f2..28d45225 100644
---- a/manifests/capabilities/search.document.write.json
++++ b/manifests/capabilities/search.document.write.json
@@@ -22,5 +22,6 @@
"GET /api/v1/owners/:owner/documents",
"GET /api/v1/owners/:owner/documents/:type/:id",
"GET /api/v1/owners/:owner/rejections"
-- ]
++ ],
++ "outputSchema": "search.write-result@1"
}
ddiff --git a/manifests/capabilities/search.query.delegate.json b/manifests/capabilities/search.query.delegate.json
iindex fd4e9ea6..acb1c849 100644
---- a/manifests/capabilities/search.query.delegate.json
++++ b/manifests/capabilities/search.query.delegate.json
@@@ -17,5 +17,7 @@
"GET /api/v1/search",
"GET /api/v1/suggest",
"GET /api/v1/documents/:owner/:type/:id"
-- ]
++ ],
++ "inputSchema": "search.query@1",
++ "outputSchema": "search.query-result@1"
}
ddiff --git a/manifests/capabilities/search.query.run.json b/manifests/capabilities/search.query.run.json
iindex 23f283bf..e94bffd6 100644
---- a/manifests/capabilities/search.query.run.json
++++ b/manifests/capabilities/search.query.run.json
@@@ -17,5 +17,7 @@
"GET /api/v1/search",
"GET /api/v1/suggest",
"GET /api/v1/documents/:owner/:type/:id"
-- ]
++ ],
++ "inputSchema": "search.query@1",
++ "outputSchema": "search.query-result@1"
}