Skip to content

Available now

How an executor behaves ​

What a skill executor does on a SOM bus: what it reads, what it publishes and when, and how it behaves on redelivery, late snapshots and errors. It's language-neutral. The contract is a draft for review, for the suite som-1.0.0+lib-0.2.2.

Every rule names its source: SOM, the skill library, an RND position (P-nn, see RND positions: ours, not the standard) or the bus. "Must", "should" and "may" are used as in RFC 2119. A "must" that rests on a position binds RND's reference executor and test tools, and nothing else.

1. Identity ​

RuleSource
The executor publishes as a connected producer app. Its system_id must be one the connection may stampThe bus: producer.system_id_not_allowed
The connection must be granted skill.warning.raised (or skill.*)The bus: producer.message_type_not_allowed
system_type must be a SOM 1.0 value. Which one: the value closest to the tool the executor sits besideSOM; P-02

2. What it subscribes to ​

RuleSource
For each configured instance, the skill's recall_on list. In a house, the configured instances are the ones it registered for youSkill library
Always story.context, even if no recall_on names it: nothing can be evaluated without the latest snapshotP-06
recall_on entries match the envelope's message_type, never topicSOM; P-03
Message types it doesn't handle, and extensions it doesn't recognise, are ignored without failingSOM

On the bus, a subscription is a consumer connection filtered by message_type: see Subscriptions and filters. Only 3 of the 15 topics the library names have a SOM 1.0 schema; see Topics without a 1.0 schema.

3. Evaluation ​

RuleSource
An evaluation reads the whole snapshotSOM
A trigger that isn't a snapshot is a wake-up: evaluate against the latest snapshot held for that story. No snapshot held, no evaluationP-06
The outcome depends only on the snapshot, the configured instance and the skill version: no clock, no randomness, no call-outs that change the answerP-06
Never change content: no story.context, no asset edits, no config writesSkill library
Never publish story.context because of a warning, not even to turn a flag into a gateP-13
Absent is a quiet non-match. Present but unreadable, or config missing, fails closed at the loudest severity allowedSkill library
A configured instance never triggers on a warning it raised itselfP-14
Most evaluations raise nothing, and that's normalSkill library

4. A declaration's life ​

EventThe executor publishesSource
The condition starts to holdOne warning: a new warning_id, a new skill_warning_refSkill library; P-08, P-09
A later snapshot, nothing changedNothingP-08
A later snapshot, the warning would now differ (severity, blocks, affected_fields, the values in detail)One new warning: new warning_id, same skill_warning_refP-08
The condition stops holding, or a valid clearance is recordedNothing on the bus. The closure is kept in the executor's own state and logP-11
The same condition holds again after closingA new declaration: new warning_id, the skill_warning_ref counter goes upP-09
The story becomes KILLED, SPIKED or ARCHIVEDNothing. Open declarations close; no new ones openP-12

A warning is never "retracted" by publishing a correction: SOM 1.0 has no message for it.

5. Delivery ​

Idempotency ​

RuleSource
A trigger delivered twice produces the warnings of one delivery, not twoSkill library
Key each emission on (configured instance, trigger message_id). Store the outgoing message before publishing it, and on a retry send the stored bytesP-10
The bus answers the same message_id and content with 200 duplicate, and any other content with 409The bus: Retries and idempotency
Keep the emission record for at least the bus's 7-day idempotency windowP-10

Order and late snapshots ​

RuleSource
Don't rely on order across storiesSOM
The bus delivers in order per correlation_id, and refuses a snapshot whose sequence_number doesn't increaseThe bus
Still, evaluate a snapshot only if its sequence_number is higher than the highest already evaluated for that story. Replays and redrives can deliver old onesP-07

Acknowledging a trigger ​

Acknowledge a trigger (or delete it from your queue) only after every warning it caused has been accepted (202) or answered as a duplicate (200). A crash between evaluation and publish then ends in a redelivery, not a lost warning.

6. Errors ​

SituationThe executor
400 from the busHas a defect. Doesn't retry; logs the rule ids; acknowledges the trigger so it doesn't loop
401 or 403Has a configuration or credential problem. Doesn't retry the message; alerts
409 message_id.reusedHas a defect: the retry wasn't byte-identical. Doesn't retry
413Shortens detail. Media never travels the bus
503, a timeout, a network failureRetries the stored bytes with backoff; doesn't acknowledge the trigger until it succeeds
A trigger that won't parseLogs it and acknowledges it. There's nothing to evaluate

7. Timing ​

RuleSource
An executor should publish within 5 seconds of receiving its triggerP-15
The skill harness in test runs fails a case with no warning after 30 seconds, and passes a no-trigger case if nothing arrives in that timeP-15

8. Versions ​

RuleSource
A configured instance is registered against one skill file at one skill_version, and its warnings carry that version. See RegistrationsSkill library; P-04
Never emit a skill_version you don't implementThis contract
A new library release is a new suite (som-1.0.0+lib-0.2.3), never an edit of this oneThis contract
A 1.x som_version on a trigger changes nothingSOM

9. Registrations ​

Available now In a house, the house decides which configured instances your

executor runs, and with which values. It registers each one (skill, version, instance_label, values and its authority scale) and binds it to your executor's connection. See Run skills in your house.

RuleSource
Read your registrations with your consumer connection's own credential: GET /v1/tenants/{t}/consumers/{c}/skills, where {c} is your client id. You get only the configured instances bound to that connectionThe bus
Values always come from the registration, never from the story. instance_label is the warning's rule_idSkill library; P-04
A story with no skills_config gets every configured instance you read. A story with one gets only those whose skill_id is in its active_skills (an empty list: none). A listed skill_version that differs from the registered one skips that instance on that story, and you log whyP-04
Compare authorities on the registration's authority_scale, most senior first. An authority not on it ranks below the declaring oneP-16
Read again at startup and at least every 5 minutes. A higher revision means the house changed the values or the binding; a configured instance that's gone is removed or bound elsewhere, and you stop evaluating itThe bus
If the read fails (503 skills.unavailable), keep running what you read last and retry with backoffThe bus

The answer:

json
{
  "suite": "som-1.0.0+lib-0.2.2",
  "connection_id": "c…",
  "narrowing": "P-04",
  "registrations": [
    {
      "registration_id": "k…",
      "skill_id": "smart-stories/raise-flag-on-match",
      "skill_version": "0.2.2",
      "instance_label": "house-breaking-indicative-category",
      "values": { "match_field": "lifecycle.phase", "match_value": "BREAKING", "flag_name": "BREAKING", "clearing_authority": "duty-editor" },
      "authority_scale": ["editor-in-chief", "duty-editor", "producer"],
      "connection_id": "c…",
      "revision": 1,
      "updated_at": "2026-09-27T12:00:00.000Z"
    }
  ]
}

The bus checks every registration against the skill's config surface when the house registers it: unknown fields are refused, and every configured field path that reads the story (match_field, watched_field, declared_fields and the like) must be a field of the SOM 1.0 story.context schema.

Test it ​

The skill harness in Test runs triggers your executor with fixtures in your workspace and checks every warning against this contract. You can also test a skill by hand. A test run plays in your own vendor workspace, which is not a house, so there your executor loads the harness's configured instance itself.

SOM is an open standard maintained by the SOM working group. This service is not endorsed by it.