feat(growth): add deterministic forecasting engine

This commit is contained in:
2026-08-21 00:15:47 +03:30
parent 37416a6f20
commit df140b4c25
8 changed files with 1057 additions and 0 deletions

148
internal/growth/types.go Normal file
View File

@@ -0,0 +1,148 @@
package growth
import "time"
const (
CatalogVersion = "1405.1"
AnalyticsVersion = "1.0.0"
MinBaselineObservations = 4
MinBaselineSessions = 100
MaterialChangeBPS = 2_000
MinSimilarityBPS = 6_000
)
type Confidence string
const (
ConfidenceHigh Confidence = "HIGH"
ConfidenceMedium Confidence = "MEDIUM"
ConfidenceInsufficientData Confidence = "INSUFFICIENT_DATA"
)
type SuppressionReason string
const (
SuppressionInsufficientObservations SuppressionReason = "INSUFFICIENT_BASELINE_OBSERVATIONS"
SuppressionInsufficientBaselineSessions SuppressionReason = "INSUFFICIENT_BASELINE_SESSIONS"
SuppressionInsufficientHistory SuppressionReason = "INSUFFICIENT_HISTORY"
SuppressionInsufficientCohort SuppressionReason = "INSUFFICIENT_COHORT"
SuppressionTerminalScope SuppressionReason = "TERMINAL_SCOPE_UNSUPPORTED"
)
type DailyPoint struct {
Date time.Time `json:"date"`
SessionCount int64 `json:"sessionCount"`
PaidSessionCount int64 `json:"paidSessionCount"`
PaidAmountRial int64 `json:"paidAmountRial"`
EventIDs []string `json:"eventIds,omitempty"`
}
type EventKind string
const (
EventOfficial EventKind = "OFFICIAL"
EventCommercial EventKind = "COMMERCIAL"
)
type Event struct {
ID string `json:"id"`
TitleFA string `json:"titleFa"`
StartDate time.Time `json:"startDate"`
EndDate time.Time `json:"endDate"`
Family string `json:"family"`
Tags []string `json:"tags"`
Source string `json:"source"`
Categories []string `json:"categories"`
Kind EventKind `json:"kind"`
}
type EventEffect struct {
EvidenceID string `json:"evidenceId"`
EventID string `json:"eventId"`
Eligible bool `json:"eligible"`
SuppressionReason SuppressionReason `json:"suppressionReason,omitempty"`
ObservationCount int `json:"observationCount"`
BaselineSessionCount int64 `json:"baselineSessionCount"`
BaselinePaidSessions int64 `json:"baselinePaidSessions"`
BaselineAmountRial int64 `json:"baselineAmountRial"`
ActualSessionCount int64 `json:"actualSessionCount"`
ActualPaidSessions int64 `json:"actualPaidSessions"`
ActualAmountRial int64 `json:"actualAmountRial"`
SessionUpliftBPS int64 `json:"sessionUpliftBps"`
PaidSessionUpliftBPS int64 `json:"paidSessionUpliftBps"`
AmountUpliftBPS int64 `json:"amountUpliftBps"`
MaterialWin bool `json:"materialWin"`
MaterialDecline bool `json:"materialDecline"`
}
type EventMatch struct {
Event Event `json:"event"`
ScoreBPS int64 `json:"scoreBps"`
MatchBasis string `json:"matchBasis"`
}
type Range struct {
P10 int64 `json:"p10"`
P50 int64 `json:"p50"`
P90 int64 `json:"p90"`
}
type ForecastPoint struct {
Date time.Time `json:"date"`
BaselineSessions int64 `json:"baselineSessions"`
BaselineAmountRial int64 `json:"baselineAmountRial"`
PaidSessions Range `json:"paidSessions"`
PaidAmountRial Range `json:"paidAmountRial"`
EventIDs []string `json:"eventIds,omitempty"`
}
type BacktestResult struct {
Origins int `json:"origins"`
SessionMAPEBPS int64 `json:"sessionMapeBps"`
AmountMAPEBPS int64 `json:"amountMapeBps"`
IntervalCoverageBPS int64 `json:"intervalCoverageBps"`
}
type Forecast struct {
StartDate time.Time `json:"startDate"`
HorizonDays int `json:"horizonDays"`
Confidence Confidence `json:"confidence"`
SuppressionReason SuppressionReason `json:"suppressionReason,omitempty"`
Points []ForecastPoint `json:"points"`
Backtest BacktestResult `json:"backtest"`
}
type Opportunity struct {
EvidenceID string `json:"evidenceId"`
EventID string `json:"eventId"`
EventTitleFA string `json:"eventTitleFa"`
Date time.Time `json:"date"`
SimilarityBPS int64 `json:"similarityBps"`
ExpectedSessions Range `json:"expectedSessions"`
ExpectedAmountRial Range `json:"expectedAmountRial"`
HistoricalEvidenceID string `json:"historicalEvidenceId"`
}
type Risk struct {
EvidenceID string `json:"evidenceId"`
Date time.Time `json:"date"`
SessionDeclineBPS int64 `json:"sessionDeclineBps"`
AmountDeclineBPS int64 `json:"amountDeclineBps"`
ExpectedSessions Range `json:"expectedSessions"`
ExpectedAmountRial Range `json:"expectedAmountRial"`
}
type EvidenceBundle struct {
Opportunities []Opportunity `json:"opportunities"`
Risks []Risk `json:"risks"`
}
type CampaignBrief struct {
HeadlineFA string `json:"headlineFa"`
GuidanceFA string `json:"guidanceFa"`
OfferFA string `json:"offerFa"`
PreparationFA string `json:"preparationFa"`
LimitationFA string `json:"limitationFa"`
EvidenceIDs []string `json:"evidenceIds"`
}