feat: rank growth events with grounded evidence

This commit is contained in:
2026-08-22 18:44:59 +08:00
parent 7f9c16be4b
commit 1a8a61cfe7
20 changed files with 2555 additions and 132 deletions

View File

@@ -21,8 +21,8 @@ func TestValidateEventsDistinguishesCelebrationAndMourning(t *testing.T) {
t.Parallel()
events := []Event{
{ID: "nowruz-1405", TitleFA: "نوروز", StartDate: "2026-03-21", EndDate: "2026-03-24", Type: TypeCultural, Tone: ToneCelebratory, CommercialPosture: PosturePromote, SourceURI: "https://calendar.ut.ac.ir/", SourceVersion: "1405", InclusionRationale: "تقویم رسمی", GeographicScope: "IR", RelevanceBPS: 10000, ConfidenceBPS: 10000},
{ID: "ashura-1405", TitleFA: "عاشورای حسینی", StartDate: "2026-06-25", EndDate: "2026-06-25", Type: TypeReligious, Tone: ToneMourning, CommercialPosture: PostureNoPromotion, SourceURI: "https://calendar.ut.ac.ir/", SourceVersion: "1405", InclusionRationale: "تقویم رسمی", GeographicScope: "IR", RelevanceBPS: 10000, ConfidenceBPS: 10000},
{ID: "nowruz-1405", OccasionKey: "nowruz", TitleFA: "نوروز", StartDate: "2026-03-21", EndDate: "2026-03-24", Type: TypeCultural, Tone: ToneCelebratory, CommercialPosture: PosturePromote, SourceURI: "https://calendar.ut.ac.ir/", SourceVersion: "1405", InclusionRationale: "تقویم رسمی", GeographicScope: "IR", RelevanceBPS: 10000, ConfidenceBPS: 10000},
{ID: "ashura-1405", OccasionKey: "ashura", TitleFA: "عاشورای حسینی", StartDate: "2026-06-25", EndDate: "2026-06-25", Type: TypeReligious, Tone: ToneMourning, CommercialPosture: PostureNoPromotion, SourceURI: "https://calendar.ut.ac.ir/", SourceVersion: "1405", InclusionRationale: "تقویم رسمی", GeographicScope: "IR", RelevanceBPS: 10000, ConfidenceBPS: 10000},
}
if err := ValidateEvents(events); err != nil {
t.Fatal(err)
@@ -32,8 +32,76 @@ func TestValidateEventsDistinguishesCelebrationAndMourning(t *testing.T) {
func TestValidateEventsRejectsPromotionalMourningEvent(t *testing.T) {
t.Parallel()
event := Event{ID: "mourning", TitleFA: "یادبود", StartDate: "2026-01-01", EndDate: "2026-01-01", Type: TypeCultural, Tone: ToneMourning, CommercialPosture: PosturePromote, SourceURI: "https://example.test", SourceVersion: "v1", InclusionRationale: "reviewed", GeographicScope: "IR", RelevanceBPS: 10000, ConfidenceBPS: 10000}
event := Event{ID: "mourning", OccasionKey: "mourning", TitleFA: "یادبود", StartDate: "2026-01-01", EndDate: "2026-01-01", Type: TypeCultural, Tone: ToneMourning, CommercialPosture: PosturePromote, SourceURI: "https://example.test", SourceVersion: "v1", InclusionRationale: "reviewed", GeographicScope: "IR", RelevanceBPS: 10000, ConfidenceBPS: 10000}
if err := ValidateEvents([]Event{event}); err == nil {
t.Fatal("expected mourning promotion validation error")
}
}
func TestValidateEventsRejectsYearSpecificOccasionKey(t *testing.T) {
t.Parallel()
event := validCatalogEvent("black-friday-2026", "2026-11-27", 1405)
event.OccasionKey = "black-friday-2026"
event.Recurrence = RecurrenceBlackFriday
if err := ValidateEvents([]Event{event}); err == nil {
t.Fatal("expected year-specific occasion key validation error")
}
}
func TestValidateEventsRejectsNonCanonicalOccasionKey(t *testing.T) {
t.Parallel()
event := validCatalogEvent("black-friday-2026", "2026-11-27", 1405)
event.OccasionKey = "Black_Friday_2026a"
if err := ValidateEvents([]Event{event}); err == nil {
t.Fatal("expected non-canonical occasion key validation error")
}
}
func TestValidateEventsRejectsDuplicateOccasionVariantInJalaliYear(t *testing.T) {
t.Parallel()
first := validCatalogEvent("yalda-first-1405", "2026-12-12", 1405)
first.OccasionKey = "yalda"
first.Variant = "CAMPAIGN_WINDOW"
second := validCatalogEvent("yalda-second-1405", "2026-12-18", 1405)
second.OccasionKey = first.OccasionKey
second.Variant = first.Variant
if err := ValidateEvents([]Event{first, second}); err == nil {
t.Fatal("expected duplicate occasion variant validation error")
}
}
func TestValidateDeclaredCoverageUsesActualJalaliYear(t *testing.T) {
t.Parallel()
event := validCatalogEvent("eid-al-fitr-1406", "2027-03-10", 1406)
event.OccasionKey = "eid-al-fitr"
event.Variant = "OPERATIONAL_WINDOW"
if err := ValidateDeclaredCoverage([]Event{event}, 1406, 1406); err == nil {
t.Fatal("expected Gregorian date in Jalali 1405 to be rejected as 1406")
}
}
func TestValidateDeclaredCoverageAllowsPreparationWindowEndingBeforeOccasionYear(t *testing.T) {
t.Parallel()
event := validCatalogEvent("nowruz-demand-window-1405", "2026-02-20", 1405)
event.OccasionKey = "nowruz"
event.Variant = "CAMPAIGN_WINDOW"
event.EndDate = "2026-03-20"
if err := ValidateDeclaredCoverage([]Event{event}, 1405, 1405); err != nil {
t.Fatal(err)
}
}
func validCatalogEvent(id, date string, jalaliYear int) Event {
return Event{
ID: id, OccasionKey: "black-friday", Variant: "PRIMARY", JalaliYear: jalaliYear,
TitleFA: "رویداد", StartDate: date, EndDate: date, Type: TypeCommercial,
Tone: ToneNeutral, CommercialPosture: PostureCaution, SourceURI: "https://example.test/event",
SourceVersion: "reviewed", InclusionRationale: "reviewed", GeographicScope: "IR",
RelevanceBPS: 8000, ConfidenceBPS: 8000,
}
}