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

FieldTypeRequiredDescriptionConstraints
cluster_idstringyes
  • pattern ^clu_[0-9A-HJKMNP-TV-Z]{26}$
actionenumyes
  • one of "created", "item_added", "merged", "split", "merge_reversed", "reopened", "split_reversed"
statusenumyesThe cluster's status after the change (in practice open: merged and dissolved clusters are not announced by their own event).
  • one of "open", "merged", "dissolved"
labelstringyesDerived 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.
  • minLength 1
item_countintegeryesEvery member item, duplicates and items removed upstream included.
  • minimum 0
item_idstringcreated by ingestion and item_added: the item that started or joined the cluster.
  • pattern ^nsi_[0-9A-HJKMNP-TV-Z]{26}$
ruleenumitem_added only: why the item joined.
  • one of "duplicate_of", "shared_terms"
scoreintegeritem_added with rule shared_terms only: 2 × shared entities + shared terms.
  • minimum 0
split_fromstringcreated by a split only: the cluster the items came from.
  • pattern ^clu_[0-9A-HJKMNP-TV-Z]{26}$
audit_idstringEvery editor action (and created by a split): the news_cluster_audit row.
  • pattern ^cla_[0-9A-HJKMNP-TV-Z]{26}$
absorbedstringmerged only: the cluster merged into this one (now status merged).
  • pattern ^clu_[0-9A-HJKMNP-TV-Z]{26}$
movedintegermerged and split only: how many items moved.
  • minimum 0
new_clusterstringsplit only: the cluster the items moved into (announced by its own created event).
  • pattern ^clu_[0-9A-HJKMNP-TV-Z]{26}$
restoredstringmerge_reversed only: the absorbed cluster, open again (announced by its own reopened event).
  • pattern ^clu_[0-9A-HJKMNP-TV-Z]{26}$
dissolvedstring | nullsplit_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.
  • pattern ^clu_[0-9A-HJKMNP-TV-Z]{26}$

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 }] }