Skip to content
β—‡ AirawatOS Developer
🚧 Under development β€” this portal is being built track by track. Content will keep growing, and some sections are still placeholders.

Build

Events & Subscriptions β€” reacting when data changes

How one component triggers work when another writes to the registry β€” using a governed record, not code.

The registry isn't just storage; every write is an event. This is how the platform stays loosely coupled: a driver ingests data, an engine reacts, a person gets a task β€” and none of them call each other directly. They're wired together by a small governed record you can read, audit, and change without redeploying anything.

The one-paragraph model

When a component writes an object, the kernel persists a platform.event in the same request β€” a durable outbox, so a trigger is never silently dropped. A relay delivers each event at-least-once to the event dispatcher (the automation service), which matches it against your platform.subscription records (a WHEN β†’ THEN rule) and fires the matched action. No polling loops, no webhooks buried in code β€” the wiring is data.

component writes  ──►  kernel emits platform.event (durable outbox)
                                    β”‚  (relay, at-least-once + retry)
                                    β–Ό
                  event dispatcher: match platform.subscription (WHEN)
                                    β”‚
                                    β–Ό
                            fire the action (THEN) β€” a governed verb

Subscribe with a record

A subscription is a platform.subscription:

{
  "schema": "platform.subscription",
  "id": "ds:kmc:subscription/air-recommendation-to-action",
  "name": "Air advisory β†’ open action",
  "enabled": true,
  "match":  { "subject_schema": "governance.recommendation",   // WHEN this schema is written…
              "where": { "domain": ["air"] } },                //   …and these fields hold on the object
  "action": { "interface": "<a governed verb>" }               // THEN invoke this (see β€œgoverned action” below)
}

Writing (or editing) a subscription hot-reloads the dispatcher β€” no restart.

Worked example β€” the Air Intelligence action loop

The Air Intelligence solution already produces a natural chain:

So "sensor spike β†’ advisory β†’ an official has a task" happens with zero glue code β€” one platform.subscription, auto-wired at install from the decision-router's declared subscribes: block (see "Where you specify this").

The rule that saves you: never subscribe to bulk data

A driver may write thousands of facts per run. If every one emitted a trigger, you'd get a flood. So the kernel suppresses per-write events for a configured set of bulk fact/measure schemas β€” geo., cell., environment., air.quality, air.hotspot, several welfare.* fact subtypes, demographics., and more (the EVENT_SKIP_SCHEMA_PREFIXES guard β€” the exact list is deployment-configurable). Subscriptions never fire on the guarded schemas.

That is deliberate: subscriptions are for discrete signals β€” an alert, a decision, a recommendation, a single "run complete" record β€” not for data floods.

"How does an engine know a driver finished?"

Because the driver's data writes are (correctly) silent, you don't listen for them. Three real patterns:

Rule of thumb: bulk data β†’ chain by schedule/pipeline; a discrete milestone β†’ emit one record and subscribe.

Governed action (why the THEN names a verb, not a URL)

A subscription's action must name a governed verb (action.interface) β€” the automation dispatcher resolves it to its bound endpoint via the directory. It may not invoke a raw URL, because a hidden webhook would be an ungoverned side-channel. During migration this is enforced in shadow (a raw action.url still fires, with a warning); the target is strict (governed verbs only). So: make the thing you want to trigger a governed, bound verb, and name it in the action.

Where you specify this

  subscribes:
    - on: governance.recommendation      # WHEN this schema is written…
      where: { domain: [air] }           #   …and these fields hold (optional)
      action: decision.route             # THEN invoke this governed, bound verb

On install, the platform reads that block and auto-writes the governed platform.subscription for you β€” you never hand-author the subscription record, and the id is derived from (component, on) so re-installing is idempotent. The action names a verb that is already governed and bound (see "Governed action" above). This is how the Air Intelligence loop is wired: it lives in the decision-router's meta.

Checklist