NewsClusterUpdatedPayload news.cluster.updated@1
Generated at from
openvibe-contracts v0.34.2 and
openvibe-sdk v0.5.0.
- Version
- 1.0.0
- Owner
- news
- Visibility
- first-party
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/events/payloads/news.cluster.updated.v1.json
news.cluster.updated v1 (OpenVibe.News server/domain/clusters.js emit, from assign, merge, split and reverse). A story cluster changed, in the transaction that changed it. action: created (a new item started it, adds item_id; or an editor's split made it, adds split_from and audit_id), item_added (an ingested item joined it, adds item_id and rule: duplicate_of when the item follows the item it duplicates, shared_terms with the score when it shares enough entities and terms), merged (an editor merged another cluster into it: absorbed, audit_id, moved), split (an editor moved items out of it into a new cluster: new_cluster, audit_id, moved), merge_reversed (a merge into it was undone: restored, audit_id), reopened (the cluster a reversed merge had absorbed is open again: audit_id) or split_reversed (a split off it was undone: dissolved, audit_id). audit_id is the news_cluster_audit row (cla_…) of the merge, split or reversal. label, status and item_count describe the cluster after the change. Deliberately left out: the key terms and entities, the time window and each member's cluster_reason (GET /api/v1/clusters/:id with news.cluster.read). Envelope: subject { type: cluster, id: clu_… }, visibility internal, priority low, actor service:news (also for an editor's merge, split or reversal; the editor is recorded on the audit row).
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
cluster_id | string | yes |
| |
action | enum | yes |
| |
status | enum | yes | The cluster's status after the change (in practice open: merged and dissolved clusters are not announced by their own event). |
|
label | string | yes | Derived from the members' top entities (up to 3) or terms (up to 4), joined with ' · '; 'unlabelled' when there are none. Never written by a person or a model. |
|
item_count | integer | yes | Every member item, duplicates and items removed upstream included. |
|
item_id | string | created by ingestion and item_added: the item that started or joined the cluster. |
| |
rule | enum | item_added only: why the item joined. |
| |
score | integer | item_added with rule shared_terms only: 2 × shared entities + shared terms. |
| |
split_from | string | created by a split only: the cluster the items came from. |
| |
audit_id | string | Every editor action (and created by a split): the news_cluster_audit row. |
| |
absorbed | string | merged only: the cluster merged into this one (now status merged). |
| |
moved | integer | merged and split only: how many items moved. |
| |
new_cluster | string | split only: the cluster the items moved into (announced by its own created event). |
| |
restored | string | merge_reversed only: the absorbed cluster, open again (announced by its own reopened event). |
| |
dissolved | string | null | split_reversed only: the split-off cluster when it was left empty and dissolved; null when items that joined it after the split keep it open. |
|
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: created-by-split
{
"cluster_id": "clu_01K5S0A1B3D5F7H9K1M3P5R7SW",
"action": "created",
"status": "open",
"label": "jupiter",
"item_count": 1,
"split_from": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"audit_id": "cla_01K5S0C2E4G6J8M0P2R4T6V8XY"
}Valid: created
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "created",
"status": "open",
"label": "europa · europa clipper · falcon heavy",
"item_count": 1,
"item_id": "nsi_01K5RZ3M8Q2W7T4XC9V6B1N0JD"
}Valid: item-added-duplicate
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "item_added",
"status": "open",
"label": "europa clipper · jupiter · nasa",
"item_count": 3,
"item_id": "nsi_01K5RZ4F0A6H3K8PQ2S5W7Y9ZE",
"rule": "duplicate_of"
}Valid: item-added
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "item_added",
"status": "open",
"label": "europa clipper · jupiter · nasa",
"item_count": 2,
"item_id": "nsi_01K5RZ4F0A6H3K8PQ2S5W7Y9ZE",
"rule": "shared_terms",
"score": 10
}Valid: merge-reversed
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "merge_reversed",
"status": "open",
"label": "jupiter · europa clipper · nasa",
"item_count": 3,
"audit_id": "cla_01K5S0D3F5H7K9N1Q3S5V7X9Z1",
"restored": "clu_01K5RZ9B2C4E6G8J0M2P4R6T8V"
}Valid: merged
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "merged",
"status": "open",
"label": "jupiter · europa clipper · nasa",
"item_count": 5,
"absorbed": "clu_01K5RZ9B2C4E6G8J0M2P4R6T8V",
"audit_id": "cla_01K5S0C2E4G6J8M0P2R4T6V8XY",
"moved": 2
}Valid: reopened
{
"cluster_id": "clu_01K5RZ9B2C4E6G8J0M2P4R6T8V",
"action": "reopened",
"status": "open",
"label": "bakery · local · prize · regional",
"item_count": 2,
"audit_id": "cla_01K5S0D3F5H7K9N1Q3S5V7X9Z1"
}Valid: split-reversed-kept-open
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "split_reversed",
"status": "open",
"label": "unlabelled",
"item_count": 4,
"audit_id": "cla_01K5S0D3F5H7K9N1Q3S5V7X9Z1",
"dissolved": null
}Valid: split-reversed
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "split_reversed",
"status": "open",
"label": "jupiter · europa clipper · nasa",
"item_count": 4,
"audit_id": "cla_01K5S0D3F5H7K9N1Q3S5V7X9Z1",
"dissolved": "clu_01K5S0A1B3D5F7H9K1M3P5R7SW"
}Valid: split
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "split",
"status": "open",
"label": "europa clipper · jupiter · nasa",
"item_count": 3,
"new_cluster": "clu_01K5S0A1B3D5F7H9K1M3P5R7SW",
"audit_id": "cla_01K5S0C2E4G6J8M0P2R4T6V8XY",
"moved": 1
}Rejected: bad-audit-id
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "merged",
"status": "open",
"label": "jupiter",
"item_count": 5,
"absorbed": "clu_01K5RZ9B2C4E6G8J0M2P4R6T8V",
"audit_id": "aud_01K5S0C2E4G6J8M0P2R4T6V8XY",
"moved": 2
}Rejected: missing-label
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "created",
"status": "open",
"item_count": 1,
"item_id": "nsi_01K5RZ3M8Q2W7T4XC9V6B1N0JD"
}Rejected: terms-leaked
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "created",
"status": "open",
"label": "jupiter",
"item_count": 1,
"item_id": "nsi_01K5RZ3M8Q2W7T4XC9V6B1N0JD",
"terms": {
"jupiter": 1
}
}Rejected: unknown-action
{
"cluster_id": "clu_01K5RZ3M8R5D1F7H3K9N2Q4S6T",
"action": "renamed",
"status": "open",
"label": "jupiter",
"item_count": 1
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('news.cluster.updated@1', value); // { valid, errors: [{ path, message }] }