Reference
The envelope
One wrapper, shared by every message on every topic. It is a closed object: unknown top-level fields fail validation, and the legacy source and signature fields are hard-rejected.
Anatomy
Every field, one at a time
Click a key to read what it carries and where it trips people up.
som_version
The schema pack version the payload conforms to — "0.3.2" on the current pack.
Informative only. Never branch on it — message_type is what identifies the payload family. Traffic recorded before 12 Aug 2026 reads 0.2.0, the retired SOM-048 wire freeze.
Integration
The five rules that bite
Nearly every integration problem reported against SOM comes back to one of these.
som_version is informative
It carries the schema pack version the payload conforms to — "0.3.2" today. Don’t gate on it, don’t branch on it. message_type is what identifies the payload family. Traffic recorded before 12 Aug 2026 reads 0.2.0: that was a wire freeze, since retired, and readers who took it for the payload shape concluded they were on the wrong schema.
correlation_id is required
Thread it end-to-end. A downstream event must be traceable back to the story or action that caused it. Skill outputs echo the inbound envelope’s id; republished story versions keep theirs.
timestamp lives on the envelope
Never inside the payload. There is no signature field either — both settled in the same design decision.
originating_system, not source
Renamed at v0.3; the old field is hard-rejected. system_id and system_type are required. The newsroom system value is ncs — there is no newsroom value in the enum.
Message types are suffixed
On the wire it is skill.warning.raised, not skill.warning; telling.started, not telling. Consumers parse the suffixed form for routing.
Validate before you publish
The vendored JSON Schemas are the source of truth — not any prose description, including this page. Drop your candidate payload next to the shipped examples and run the repo’s validator.
Addressing
Field paths are relative to the payload
Skill rules address fields by dot-notation path. The executor walks the path against the payload object — never the envelope.
Rule config field | Resolves to |
|---|---|
headline | payload.headline — string |
lifecycle.phase | payload.lifecycle.phase — string |
compliance | payload.compliance — array, checked for empty/present |
priority.level | payload.priority.level — string |
premise.premise_changed | payload.premise.premise_changed — boolean |
assets[].acquisition_state | One array wildcard, supported by field_changed only |
Most rule types check an array field for presence or absence as a whole. The field_changed type additionally supports one [] wildcard, matching elements across story versions by their asset_id / source_id / flag_id / id. Anything more selective — “any compliance flag of type X” — means a custom rule type in the executor.
Payload
skill.warning.raised
The most common outbound payload: an editorial warning raised by a skill against a story, or against one surface of it. Twelve normative fields, plus the optional instance binding.
warning_id
Identity of this warning. One warning, one pending row, one approve/reject.
hold — the executor must withhold all output on the affected fields until resolved, and subscribers must not use held content.
flag — mark output as requiring review; a subscriber may show a visual warning.
inform — advisory only. No blocking action, no mandatory response.
A story can air on several surfaces at once. When a warning applies to one of them, set instance_ref to that instance_id. Omit it for story-wide warnings.
It is singular on purpose: one warning, one pending row, one approve/reject per surface. Two surfaces means two warnings with two ids.
A warning referencing an instance_id that doesn’t exist should be rejected by the consumer — fail closed.
Instance scoping rides in the payload, never in the topic name. Do not split skill warnings across som.skills.staging.{instance}-style topics.
Migration
Renames that break old configs
If a rule config or producer predates the v0.3.x migration, these paths have moved — or gone.
| Old path | Now |
|---|---|
sources[] | editorial_source[] — credibility enum TRUSTED | VERIFIED | ENDORSED | UNVERIFIED |
skills_config.broadcaster | skills_config.newsroom |
collaboration.version | collaboration.editing_version |
instances[] | Hard-rejected since v0.3 — links and tellings model distribution instead |
ai_enrichments[] | Hard-rejected since v0.3.2 — generative output that publishes is an assets[] entry with provenance; claims about content are assertions[] |
Extensions
The sanctioned escape hatch
Anything outside the canonical schema rides under payload.extensions["com.{vendor}.{field}"], where {vendor} is the reverse-DNS short form of the broadcaster or skill author. The namespace prevents collisions and keeps a clean upgrade path: anything promoted into the spec drops its prefix.
{
"warning_id": "wrn-019536b1-0001",
"skill_id": "nbcu/editorial-standards",
"severity": "flag",
"detail": "Informal term 'cops' in headline.",
"extensions": {
"com.nbcu.citations": [
{ "source_id": "nbcu-style-guide-2026",
"quote": "Use 'police' or 'officers'. Avoid 'cops' in headlines." }
],
"com.nbcu.rationale": "Term is on the Standards informal-terms list."
}
}- Consumers that don’t recognise an extension key must ignore it silently.
- Vendor-specific enum values follow a different convention:
x-plus the lowercase token, underscores preserved —x-graphics_pack, neverx-GRAPHICS_PACK. - The reference implementation uses the hatch itself, for
com.ibc-poc.capture_completeon delivery events.