openvibers/openvibe.contracts Commits

v0.20.0: OpenVibe.Reviews is alpha (reviews.* capabilities)

OP OpenVibers committed 23 Sept 2026 · ca29f75eee · 10 files, +229 −9


Changes

ddiff --git a/manifests/capabilities/reviews.correction.submit.json b/manifests/capabilities/reviews.correction.submit.json
nnew file mode 100644
iindex 00000000..c5a4967f
---- /dev/null
++++ b/manifests/capabilities/reviews.correction.submit.json
@@@ -0,0 +1,19 @@
++{
++ "id": "reviews.correction.submit",
++ "version": "1.0",
++ "owner": "reviews",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Send a correction (about an entity, alias, signal, summary or aggregate, with an optional evidence URL) to the editors' queue on behalf of the person named in X-OV-Subject. Corrections are read by editors and not published.",
++ "permissions": [
++ "reviews:correction:submit"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "reviews-corrections",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/entities/:ref/corrections"
++ ]
++}
ddiff --git a/manifests/capabilities/reviews.entity.manage.json b/manifests/capabilities/reviews.entity.manage.json
nnew file mode 100644
iindex 00000000..25e9122a
---- /dev/null
++++ b/manifests/capabilities/reviews.entity.manage.json
@@@ -0,0 +1,31 @@
++{
++ "id": "reviews.entity.manage",
++ "version": "1.0",
++ "owner": "reviews",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Editorial management of entities for the editor named in X-OV-Subject: create, edit, rename (old slugs redirect) and delete entities, add and remove aliases, typed links between entities or to another service's EntityRef, trust metadata (exclude a source or signal from aggregates with a visible reason, limitation and verification notes), and the correction queue.",
++ "permissions": [
++ "reviews:entity:manage"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "reviews-write",
++ "events": [
++ "reviews.index_document.upserted",
++ "reviews.index_document.deleted"
++ ],
++ "implementedBy": [
++ "POST /api/v1/entities",
++ "PATCH /api/v1/entities/:ref",
++ "DELETE /api/v1/entities/:ref",
++ "POST /api/v1/entities/:ref/aliases",
++ "DELETE /api/v1/entities/:ref/aliases/:id",
++ "POST /api/v1/entities/:ref/links",
++ "DELETE /api/v1/entities/:ref/links/:id",
++ "POST /api/v1/trust",
++ "GET /api/v1/corrections",
++ "PATCH /api/v1/corrections/:id"
++ ]
++}
ddiff --git a/manifests/capabilities/reviews.entity.merge.json b/manifests/capabilities/reviews.entity.merge.json
nnew file mode 100644
iindex 00000000..18935fd1
---- /dev/null
++++ b/manifests/capabilities/reviews.entity.merge.json
@@@ -0,0 +1,21 @@
++{
++ "id": "reviews.entity.merge",
++ "version": "1.0",
++ "owner": "reviews",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Merge one entity into another, decided by the editor named in X-OV-Subject (never a service on its own). Nothing is rewritten: the merged entity keeps its aliases and its signals keep their attribution; an audited merged_into link records who, when and why, and the target's aggregate is recomputed over both. Reversible with reviews.entity.split.",
++ "permissions": [
++ "reviews:entity:merge"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "reviews-write",
++ "events": [
++ "reviews.entity.merged"
++ ],
++ "implementedBy": [
++ "POST /api/v1/entities/:ref/merge"
++ ]
++}
ddiff --git a/manifests/capabilities/reviews.entity.resolve.json b/manifests/capabilities/reviews.entity.resolve.json
nnew file mode 100644
iindex 00000000..fff1d3d9
---- /dev/null
++++ b/manifests/capabilities/reviews.entity.resolve.json
@@@ -0,0 +1,30 @@
++{
++ "id": "reviews.entity.resolve",
++ "version": "1.0",
++ "owner": "reviews",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Resolve a name, URL, GTIN/SKU/MPN, source binding or external id to an entity (deterministic rules; a name alone yields candidates, never a match), read entity pages as JSON (aggregate with inputs, signals with provenance, summary), their history and summary revisions, and — for an editor named in X-OV-Subject — read the resolution queue and confirm or ignore an ambiguous source item.",
++ "permissions": [
++ "reviews:entity:resolve"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "reviews-read",
++ "events": [
++ "reviews.signal.added",
++ "reviews.signal.removed"
++ ],
++ "implementedBy": [
++ "POST /api/v1/resolve",
++ "GET /api/v1/entities",
++ "GET /api/v1/entities/:ref",
++ "GET /api/v1/entities/:ref/history",
++ "GET /api/v1/entities/:ref/aggregate",
++ "GET /api/v1/entities/:ref/summary/revisions/:n",
++ "GET /api/v1/items",
++ "GET /api/v1/items/:id",
++ "POST /api/v1/items/:id/resolution"
++ ]
++}
ddiff --git a/manifests/capabilities/reviews.entity.split.json b/manifests/capabilities/reviews.entity.split.json
nnew file mode 100644
iindex 00000000..8231ae39
---- /dev/null
++++ b/manifests/capabilities/reviews.entity.split.json
@@@ -0,0 +1,21 @@
++{
++ "id": "reviews.entity.split",
++ "version": "1.0",
++ "owner": "reviews",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Undo a merge, decided by the editor named in X-OV-Subject: ends the merged_into link (audited) and restores the pre-merge attribution exactly; both aggregates are recomputed and a summary that cited the split-off signals is flagged with a pending revision.",
++ "permissions": [
++ "reviews:entity:split"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "reviews-write",
++ "events": [
++ "reviews.entity.split"
++ ],
++ "implementedBy": [
++ "POST /api/v1/entities/:ref/split"
++ ]
++}
ddiff --git a/manifests/capabilities/reviews.signal.import.json b/manifests/capabilities/reviews.signal.import.json
nnew file mode 100644
iindex 00000000..ee061254
---- /dev/null
++++ b/manifests/capabilities/reviews.signal.import.json
@@@ -0,0 +1,23 @@
++{
++ "id": "reviews.signal.import",
++ "version": "1.0",
++ "owner": "reviews",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Import review signals from OpenVibe.Sources: one item by id, or the next pages of category-reviews items in change order. Reviews fetches the item itself (sources.item.read), keeps its provenance (source, item revision, retrieval time, licence note) and only the signal fields, never review text. Removed or revised items withdraw or replace their signal; the next aggregate revision reflects it.",
++ "permissions": [
++ "reviews:signal:import"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "reviews-write",
++ "events": [
++ "reviews.signal.added",
++ "reviews.signal.removed"
++ ],
++ "implementedBy": [
++ "POST /api/v1/signals/import",
++ "POST /api/v1/sources/sync"
++ ]
++}
ddiff --git a/manifests/capabilities/reviews.summary.propose.json b/manifests/capabilities/reviews.summary.propose.json
nnew file mode 100644
iindex 00000000..cd9c541f
---- /dev/null
++++ b/manifests/capabilities/reviews.summary.propose.json
@@@ -0,0 +1,19 @@
++{
++ "id": "reviews.summary.propose",
++ "version": "1.0",
++ "owner": "reviews",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "The OpenVibe.AI seam (workflow reviews.summarize_entity): propose a summary revision whose every pro and con cites signals of the entity. It is stored with ai authorship (workflow and run id, stub-provider flag), is never published by this call, stays out of pages, feeds and Search until a person approves it, and can never carry a rating (rating fields and rating text are refused).",
++ "permissions": [
++ "reviews:summary:propose"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "reviews-write",
++ "events": [],
++ "implementedBy": [
++ "POST /api/v1/entities/:ref/summary/proposals"
++ ]
++}
ddiff --git a/manifests/capabilities/reviews.summary.publish.json b/manifests/capabilities/reviews.summary.publish.json
nnew file mode 100644
iindex 00000000..d462c90c
---- /dev/null
++++ b/manifests/capabilities/reviews.summary.publish.json
@@@ -0,0 +1,26 @@
++{
++ "id": "reviews.summary.publish",
++ "version": "1.0",
++ "owner": "reviews",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Write, review (approve or reject), publish and unpublish summary revisions as the editor named in X-OV-Subject. Publishing refuses AI or system-prepared revisions without a person's approval and any revision with a point that cites no live signal of the entity.",
++ "permissions": [
++ "reviews:summary:publish"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "reviews-write",
++ "events": [
++ "reviews.summary.published",
++ "reviews.summary.updated",
++ "reviews.summary.unpublished"
++ ],
++ "implementedBy": [
++ "POST /api/v1/entities/:ref/summary/revisions",
++ "POST /api/v1/entities/:ref/summary/revisions/:n/review",
++ "POST /api/v1/entities/:ref/summary/publish",
++ "POST /api/v1/entities/:ref/summary/unpublish"
++ ]
++}
ddiff --git a/manifests/services/reviews.json b/manifests/services/reviews.json
iindex 0c0e4442..4edeadb4 100644
---- a/manifests/services/reviews.json
++++ b/manifests/services/reviews.json
@@@ -1,16 +1,46 @@
{
"version": "0.1.0",
"contractRanges": {
-- "openvibe-contracts": "^0.1.0"
++ "openvibe-contracts": ">=0.19.0 <1.0.0"
},
"id": "reviews",
"name": "OpenVibe.Reviews",
-- "status": "placeholder",
++ "status": "alpha",
"repository": "OpenVibers/OpenVibe.Reviews",
-- "domains": [],
-- "capabilities": [],
-- "eventsProduced": [],
-- "eventsConsumed": [],
-- "namespacesOwned": [],
-- "notes": "Review signals gathered across sources with provenance, entity resolution and honest aggregates. Charter only; no runtime."
++ "domains": [
++ "openvibe.reviews"
++ ],
++ "publicOrigin": "https://openvibe.reviews",
++ "health": "/api/health",
++ "ready": "/api/ready",
++ "capabilities": [
++ "reviews.entity.resolve",
++ "reviews.entity.manage",
++ "reviews.entity.merge",
++ "reviews.entity.split",
++ "reviews.signal.import",
++ "reviews.summary.propose",
++ "reviews.summary.publish",
++ "reviews.correction.submit"
++ ],
++ "eventsProduced": [
++ "reviews.entity.merged",
++ "reviews.entity.split",
++ "reviews.signal.added",
++ "reviews.signal.removed",
++ "reviews.summary.published",
++ "reviews.summary.updated",
++ "reviews.summary.unpublished",
++ "reviews.index_document.upserted",
++ "reviews.index_document.deleted"
++ ],
++ "eventsConsumed": [
++ "sources.item.created",
++ "sources.item.updated",
++ "sources.item.removed"
++ ],
++ "namespacesOwned": [
++ "reviews.*"
++ ],
++ "notes": "Entities with aliases and typed links; resolution of OpenVibe.Sources review items by deterministic rules (source binding, URL, GTIN/SKU/MPN) with editor confirmation for name-only and conflicting matches; merges that rewrite nothing and splits that restore attribution exactly, both audited; typed signals with provenance (source item, item revision, retrieval time, licence note) and trust metadata; aggregates computed only from signals present (method reviews-aggregate@1, inputs and exclusions exposed, absent without qualifying signals, a new revision on every change); editor-written or AI-drafted-and-approved summaries whose points cite signals and never carry a rating; source removal withdraws signals, flags citing summaries and prepares a pending revision; corrections queue; Community discussion referenced, not copied. Server-rendered pages useful without JavaScript; AggregateRating/Product/Review JSON-LD only when signals back it; sitemaps, feeds and Search index events from the openvibe-publishing v0.2.0 gate. Not deployed; openvibe.reviews stays on OpenVibe.Sites until launch."
}
ddiff --git a/package.json b/package.json
iindex ab3c9fbe..2927089e 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.19.0",
++ "version": "0.20.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",