Adds preferred workplan REST/event surfaces, legacy-meter telemetry and weekly review summaries, documentation/dashboard terminology updates, dashboard API loading fixes, and close-out sync for STATE-WP-0052 and STATE-WP-0054.
4.9 KiB
NATS Event Subjects — State Hub
Part of CUST-WP-0040. Cross-reference: activity-core's
event-types/registry and ADR-001 (event bridge architecture).
The state hub publishes lifecycle events to NATS JetStream so that
activity-core can drive maintenance and reaction automation declaratively,
via ActivityDefinition rules — rather than the state hub creating tasks
itself.
This document is the authoritative subject naming convention for state hub
events. When adding a new event, add a row to the table below first and
keep the activity-core event-types/ registry in sync.
Naming convention
org.{producer}.{noun}.{verb}[.{qualifier}]
org— top-level namespace shared with activity-core (org.>){producer}— the publisher subsystem; the state hub usesstatehub{noun}— entity the event is about (repo,workstream,task, …){verb}— past-tense state transition (registered,completed,resolved, …){qualifier}— optional refinement (e.g.goal.activated)
All segments are lowercase ASCII. No camelCase, no dashes inside segments.
Why a statehub namespace?
Activity-core listens to activity.> for its internal task lifecycle and
org.> for org-wide lifecycle events. Multiple publishers will eventually
share org.> (e.g. railiance, kaizen). The {producer} segment keeps
those publishers from colliding on the same {noun}.{verb} shape.
Published subjects (v1.0)
| Subject | When | Required attributes |
|---|---|---|
org.statehub.repo.registered |
A new repo is registered via POST /repos/ |
repo_id, repo_slug, domain_slug, remote_url?, local_path? |
org.statehub.workplan.completed |
A workplan transitions to canonical status finished |
workplan_id, legacy_workstream_id, slug, title, topic_id, repo_id?, repo_goal_id? |
org.statehub.workstream.completed |
Legacy compatibility subject for completed workplans | workstream_id, slug, title, topic_id, repo_id?, repo_goal_id? |
org.statehub.decision.resolved |
A decision is resolved via POST /decisions/{id}/resolve |
decision_id, title, topic_id?, workstream_id?, decided_by, rationale_snippet |
org.statehub.domain.goal.activated |
A domain goal transitions to active |
goal_id, domain_id, domain_slug, title, superseded_goal_ids[] |
org.statehub.task.stale |
scripts/cleanup_stale_tasks.py cancels an out-of-date task |
task_id, workstream_id, workstream_status, task_title, task_status_before |
Envelope shape
Each message body conforms to the EventEnvelope schema in
api/events/envelope.py, mirrored from
activity-core/src/activity_core/models.py:
{
"id": "uuid v4 — stable, used for at-least-once dedup",
"type": "org.statehub.repo.registered",
"version": "1.0",
"timestamp": "2026-05-17T14:00:00Z",
"publisher": "state-hub",
"attributes": { "...": "event-specific" }
}
type matches the subject. publisher is always
state-hub for events emitted from this repo.
Stream
State hub events are published into the ACTIVITY_EVENTS JetStream
(subject filter org.>). The stream is owned by activity-core; the state
hub will auto-create it on first publish if it does not exist, so the
publisher works in dev environments without bootstrapping activity-core
first. In production both services point at the same NATS cluster and
activity-core's EventRouter consumes the stream durably.
Adding a new event
- Pick a subject following the convention above.
- Add a row to the table in this file (subject, trigger, attributes).
- Add a matching
event-types/entry in activity-core. - Wire
publish_event(subject, EventEnvelope.new(subject, attributes))at the site of the state transition (inside the same DB transaction only afterawait session.commit()— never publish optimistically). - Verify locally: run
nats sub 'org.statehub.>'while triggering the transition.
Versioning
version is bumped only when an attribute is removed or its semantics
change. Adding optional attributes does not require a version bump.
Activity-core consumers must tolerate unknown attribute keys.