package checker import ( "encoding/json" "time" ) const ObservationKeyHappyDeliver = "happydeliver" const ( SectionOverall = "overall" SectionDNS = "dns" SectionAuthentication = "authentication" SectionSpam = "spam" SectionBlacklist = "blacklist" SectionHeader = "header" SectionContent = "content" ) // Overall is first so metric and rule iteration is deterministic. var AllSections = []string{ SectionOverall, SectionDNS, SectionAuthentication, SectionSpam, SectionBlacklist, SectionHeader, SectionContent, } // Report is stored verbatim so new upstream sections appear without an SDK change. type HappyDeliverData struct { Phase string `json:"phase"` Endpoint string `json:"endpoint"` TestID string `json:"test_id,omitempty"` RecipientEmail string `json:"recipient_email,omitempty"` StartedAt time.Time `json:"started_at"` AnalysedAt time.Time `json:"analysed_at,omitempty"` LatencySeconds float64 `json:"latency_seconds,omitempty"` Report json.RawMessage `json:"report,omitempty"` Scores map[string]int `json:"scores,omitempty"` Grades map[string]string `json:"grades,omitempty"` Error string `json:"error,omitempty"` } // Minimal subset: avoids mirroring the full schema so new upstream fields don't break us. type reportEnvelope struct { Score int `json:"score"` Grade string `json:"grade"` Summary struct { DNSScore int `json:"dns_score"` DNSGrade string `json:"dns_grade"` AuthenticationScore int `json:"authentication_score"` AuthenticationGrade string `json:"authentication_grade"` SpamScore int `json:"spam_score"` SpamGrade string `json:"spam_grade"` BlacklistScore int `json:"blacklist_score"` BlacklistGrade string `json:"blacklist_grade"` HeaderScore int `json:"header_score"` HeaderGrade string `json:"header_grade"` ContentScore int `json:"content_score"` ContentGrade string `json:"content_grade"` } `json:"summary"` } func extractScores(raw json.RawMessage) (map[string]int, map[string]string, error) { var env reportEnvelope if err := json.Unmarshal(raw, &env); err != nil { return nil, nil, err } scores := map[string]int{ SectionOverall: env.Score, SectionDNS: env.Summary.DNSScore, SectionAuthentication: env.Summary.AuthenticationScore, SectionSpam: env.Summary.SpamScore, SectionBlacklist: env.Summary.BlacklistScore, SectionHeader: env.Summary.HeaderScore, SectionContent: env.Summary.ContentScore, } grades := map[string]string{ SectionOverall: env.Grade, SectionDNS: env.Summary.DNSGrade, SectionAuthentication: env.Summary.AuthenticationGrade, SectionSpam: env.Summary.SpamGrade, SectionBlacklist: env.Summary.BlacklistGrade, SectionHeader: env.Summary.HeaderGrade, SectionContent: env.Summary.ContentGrade, } return scores, grades, nil }