fix: deliver validated AI insight responses
This commit is contained in:
@@ -40,8 +40,13 @@ const (
|
||||
|
||||
type Event struct {
|
||||
ID string `json:"id"`
|
||||
OccasionKey string `json:"occasionKey,omitempty"`
|
||||
Variant string `json:"variant,omitempty"`
|
||||
TitleFA string `json:"titleFa"`
|
||||
TitleEN string `json:"titleEn,omitempty"`
|
||||
Aliases []string `json:"aliases,omitempty"`
|
||||
Themes []string `json:"themes,omitempty"`
|
||||
CampaignTags []string `json:"campaignTags,omitempty"`
|
||||
StartDate string `json:"startDate"`
|
||||
EndDate string `json:"endDate"`
|
||||
Recurrence Recurrence `json:"recurrence,omitempty"`
|
||||
@@ -60,6 +65,7 @@ type Event struct {
|
||||
LagDays int `json:"lagDays"`
|
||||
RelevanceBPS int `json:"relevanceBps"`
|
||||
ConfidenceBPS int `json:"confidenceBps"`
|
||||
ImportanceBPS int `json:"importanceBps,omitempty"`
|
||||
}
|
||||
|
||||
func ResolveRecurrence(rule Recurrence, year int, location *time.Location) (time.Time, error) {
|
||||
@@ -79,6 +85,7 @@ func ResolveRecurrence(rule Recurrence, year int, location *time.Location) (time
|
||||
|
||||
func ValidateEvents(events []Event) error {
|
||||
seen := make(map[string]struct{}, len(events))
|
||||
canonical := make(map[string]struct{}, len(events))
|
||||
for _, event := range events {
|
||||
if strings.TrimSpace(event.ID) == "" || strings.TrimSpace(event.TitleFA) == "" || strings.TrimSpace(event.SourceURI) == "" || strings.TrimSpace(event.SourceVersion) == "" || strings.TrimSpace(event.InclusionRationale) == "" || strings.TrimSpace(event.GeographicScope) == "" {
|
||||
return fmt.Errorf("event catalog: event %q is incomplete", event.ID)
|
||||
@@ -87,6 +94,15 @@ func ValidateEvents(events []Event) error {
|
||||
return fmt.Errorf("event catalog: duplicate event %q", event.ID)
|
||||
}
|
||||
seen[event.ID] = struct{}{}
|
||||
if event.OccasionKey == "" {
|
||||
event.OccasionKey = event.ID
|
||||
}
|
||||
if event.Variant == "" {
|
||||
event.Variant = "PRIMARY"
|
||||
}
|
||||
if event.Variant != "PRIMARY" && event.Variant != "CAMPAIGN_WINDOW" && event.Variant != "OPERATIONAL_WINDOW" {
|
||||
return fmt.Errorf("event catalog: event %q has invalid variant", event.ID)
|
||||
}
|
||||
start, err := time.Parse(time.DateOnly, event.StartDate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("event catalog: event %q start date: %w", event.ID, err)
|
||||
@@ -101,7 +117,7 @@ func ValidateEvents(events []Event) error {
|
||||
if (event.Tone == ToneMourning || event.Tone == ToneMemorial) && event.CommercialPosture == PosturePromote {
|
||||
return fmt.Errorf("event catalog: event %q cannot promote during mourning or memorial", event.ID)
|
||||
}
|
||||
if event.LeadDays < 0 || event.LagDays < 0 || event.RelevanceBPS < 0 || event.RelevanceBPS > 10_000 || event.ConfidenceBPS < 0 || event.ConfidenceBPS > 10_000 {
|
||||
if event.LeadDays < 0 || event.LagDays < 0 || event.RelevanceBPS < 0 || event.RelevanceBPS > 10_000 || event.ConfidenceBPS < 0 || event.ConfidenceBPS > 10_000 || event.ImportanceBPS < 0 || event.ImportanceBPS > 10_000 {
|
||||
return fmt.Errorf("event catalog: event %q has invalid impact metadata", event.ID)
|
||||
}
|
||||
if event.LeadDays > 90 || event.LagDays > 90 {
|
||||
@@ -116,6 +132,11 @@ func ValidateEvents(events []Event) error {
|
||||
return fmt.Errorf("event catalog: event %q does not match its resolved recurrence", event.ID)
|
||||
}
|
||||
}
|
||||
canonicalKey := strings.Join([]string{event.OccasionKey, event.Variant, event.StartDate, event.EndDate}, "\x00")
|
||||
if _, exists := canonical[canonicalKey]; exists {
|
||||
return fmt.Errorf("event catalog: duplicate canonical occurrence %q", event.ID)
|
||||
}
|
||||
canonical[canonicalKey] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user