package domain import "time" // Signal is an attention record — something the lab noticed that needs // attention and possibly action. Dual entity: has an entities row + a // signals table row for indexed querying. type Signal struct { EntityID UUID Kind string Severity string TargetEntityID UUID CheckID UUID Evidence string LikelyCause string State string OccurrenceCount int FirstSeenAt time.Time LastSeenAt time.Time FlapCount int HoldDownUntil *time.Time MuteUntil *time.Time CreatedAt time.Time UpdatedAt time.Time } // Signal lifecycle states (see lifecycle_defs in seeds/ontology.yaml). const ( SignalRaised = "raised" SignalAcknowledged = "acknowledged" SignalActing = "acting" SignalMuted = "muted" SignalResolved = "resolved" SignalFailed = "failed" ) // Signal severities. const ( SeverityInfo = "info" SeverityWarning = "warning" SeverityCritical = "critical" ) // ValidSignalTransitions defines legal state transitions. var ValidSignalTransitions = map[string][]string{ SignalRaised: {SignalAcknowledged, SignalMuted, SignalResolved}, SignalAcknowledged: {SignalActing, SignalResolved, SignalMuted}, SignalActing: {SignalResolved, SignalRaised, SignalFailed}, SignalFailed: {SignalAcknowledged}, SignalMuted: {SignalRaised}, } // CanTransition returns true if from→to is a legal signal state transition. func (s *Signal) CanTransition(to string) bool { allowed, ok := ValidSignalTransitions[s.State] if !ok { return false } for _, a := range allowed { if a == to { return true } } return false }