Documentation
¶
Overview ¶
Package controlevent defines the control-plane event contract: the notification a control plane appends and a fleet chassis consumes.
See internal docs/todo-architecture-saas-fleet.md §3.1. An event is a semantic invalidation/version record — NEVER the payload itself. It carries identity, a content-addressed pointer (ArtifactRef), an integrity seal (Checksum) and the fleet position (ControlVersion). The bytes live in the artifact store, not in the log.
This package is the shared event contract: the chassis consumes events; a control plane produces them. It is intentionally dependency-free so both sides can depend on it.
Index ¶
Constants ¶
const ( // ControlModelVersion is the version of the event/contract shape. ControlModelVersion = 1 // CacheSchemaVersion is the version of the materialised local cache // shape an artifact restores into. CacheSchemaVersion = 1 )
Model/cache versions. A node rejects an artifact (or event) whose declared versions it cannot interpret (see snapshot.Verify). Bump deliberately when the on-the-wire contract or the materialised cache shape changes incompatibly.
const ( TypeStackActivated = "stack.activated" TypeTenantCreated = "tenant.created" TypeHostnameBound = "hostname.bound" TypeHostnameVerified = "hostname.verified" TypeHostnameRevoked = "hostname.revoked" TypeActorChanged = "actor.changed" TypeKeyChanged = "key.changed" TypeMembershipChanged = "membership.changed" TypeEntitlementUpdated = "entitlement.updated" TypeSystemOpstack = "system.opstack.updated" )
Event types. These are the existing admin-API mutations, externalised.
Variables ¶
var ErrInvalid = errors.New("controlevent: invalid event")
ErrInvalid wraps every Validate failure.
Functions ¶
func CompatibleCacheSchema ¶
CompatibleCacheSchema reports whether this chassis can load an artifact declaring the given cache-schema version.
func CompatibleModel ¶
CompatibleModel reports whether this chassis can interpret an artifact/event declaring the given control-model version. Same major line only; an older binary must refuse a newer model rather than guess.
Types ¶
type Event ¶
type Event struct {
ID int64 `json:"id"`
EventID string `json:"event_id"`
Type string `json:"type"`
TenantID string `json:"tenant_id,omitempty"`
StackID string `json:"stack_id,omitempty"`
Version int64 `json:"version,omitempty"`
BaseVersion int64 `json:"base_version,omitempty"`
ArtifactRef string `json:"artifact_ref,omitempty"`
Checksum string `json:"checksum,omitempty"`
ControlVersion uint64 `json:"control_version"`
CreatedAt string `json:"created_at,omitempty"`
}
Event is the control-plane event contract.
Field notes (deliberate, see plan):
- EventID is the producer-assigned semantic identity (UUID; UUIDv7 via chassis/hxid is the conventional choice). It rides the event through retries and replays so consumers can recognise a duplicate even when broker-side dedup (e.g. JetStream Nats-Msg-Id) has expired. Required; an empty EventID fails Validate.
- Version is the *stack* version (stack_versions.version_number).
- BaseVersion is the producer's view of the prior value of the mutated resource — e.g. the active_version it saw before flipping it for a stack.activated event. Optional in v1; not enforced by the applier. Carried so a later revision can layer CAS-style optimistic concurrency on top without a wire-format change.
- ControlVersion is the global monotonic *fleet cursor* — the resume position. Producer-side it is zero (the backend's broker stamps it on publish — JetStream stream_sequence in the NATS overlay; sequential ints in the file backend). Consumer-side Validate requires > 0.
- ArtifactRef points at the event's artifact in the artifact store. It is "the artifact for THIS event", not necessarily a full bootstrap SQLite snapshot — hence ArtifactRef, not "snapshot_ref".
- There is no "active_version": it was ambiguous against Version and is omitted until/unless it earns a distinct meaning.
func (Event) Validate ¶
Validate checks the structural invariants every consumer relies on. It is deliberately strict: a malformed system event must fail loudly, never silently misroute.
Validate is consumer-side: it runs after the carrier has stamped ControlVersion (broker-assigned). Producers do not need to call it before queueing an outbox row — the Sink stamps ControlVersion at publish time, and the next applier on any chassis re-runs Validate.
type RowsArtifact ¶
type RowsArtifact struct {
DB string `json:"db"` // "runtime" | "auth"
Table string `json:"table"` // must be whitelisted
Op string `json:"op"` // "upsert" | "delete"
PK []string `json:"pk"` // primary-key columns (delete)
Rows []map[string]any `json:"rows"`
}
RowsArtifact is the payload for the generic row event types (tenant.created, hostname.*, membership.changed, entitlement.updated, and the auth.* types). It carries authoritative rows for one table and how to apply them. DB selects the target database ("runtime" or "auth"); the table is checked against a hard whitelist on the consumer side before any SQL runs.
type StackActivatedArtifact ¶
type StackActivatedArtifact struct {
TenantID string `json:"tenant_id"`
Stack string `json:"stack"`
Version int64 `json:"version"`
Files []StackArtifactFile `json:"files"`
}
StackActivatedArtifact is the payload for a TypeStackActivated event: the full file set of the activated stack version. The node upserts these into stack_versions/stack_files then materialises them into ops.
type StackArtifactFile ¶
StackArtifactFile is one (path, content) pair in a StackActivatedArtifact. Path is "<scope>/<name>.txcl" plus the well-known "mock-request.json" / "mock-response.json".