package domain import ( "context" "errors" "strings" "time" ) type JobStatus string const ( JobQueued JobStatus = "queued" JobRunning JobStatus = "running" JobSucceeded JobStatus = "succeeded" JobFailed JobStatus = "failed" JobSkipped JobStatus = "skipped" ) type RunStatus string const ( RunRunning RunStatus = "running" RunSucceeded RunStatus = "succeeded" RunFailed RunStatus = "failed" RunSkipped RunStatus = "skipped" ) type ParsedCommand struct { Name string Alias string Raw string Mode string ModeExplicit bool Full bool Arguments []string } func (c ParsedCommand) IsReview() bool { return c.Name == "review" || c.Name == "rerun" } type RepoReviewConfig struct { Configured bool Enabled bool DefaultMode string MaxDiffBytes int IncludeTests bool Focus []string Ignore []string } func DefaultRepoReviewConfig() RepoReviewConfig { return RepoReviewConfig{Configured: true, Enabled: true, DefaultMode: "full", MaxDiffBytes: 200000, Focus: []string{"correctness", "security", "maintainability"}} } type PullRequestContext struct { Repo string PRNumber int BaseRef string BaseSHA string HeadRef string HeadSHA string CloneURL string BaseCloneURL string HeadCloneURL string HTMLURL string IsFork bool } type Finding struct { Severity string `json:"severity"` File string `json:"file"` LineStart int `json:"line_start"` LineEnd int `json:"line_end"` Title string `json:"title"` Body string `json:"body"` Suggestion *string `json:"suggestion"` } type Usage struct { InputTokens int `json:"input_tokens,omitempty"` OutputTokens int `json:"output_tokens,omitempty"` TotalTokens int `json:"total_tokens,omitempty"` } type ReviewMeta struct { Source string `json:"source,omitempty"` Model string `json:"model,omitempty"` Usage Usage `json:"usage,omitempty"` } type ReviewResult struct { Verdict string `json:"verdict"` Confidence float64 `json:"confidence"` Summary string `json:"summary"` MarkdownComment string `json:"markdown_comment"` Findings []Finding `json:"findings"` Meta *ReviewMeta `json:"_meta,omitempty"` } func (r ReviewResult) Validate() error { if r.Verdict != "correct" && r.Verdict != "has_issues" { return errors.New("invalid verdict") } if r.Confidence < 0 || r.Confidence > 1 { return errors.New("confidence must be between 0 and 1") } if len(r.Summary) > 20000 || len(r.MarkdownComment) > 50000 { return errors.New("review text is too long") } if len(r.Findings) > 200 { return errors.New("too many findings") } for i, f := range r.Findings { if f.Severity != "low" && f.Severity != "medium" && f.Severity != "high" && f.Severity != "critical" { return errors.New("invalid finding severity") } if f.File == "" || len(f.File) > 1000 || f.LineStart < 1 || f.LineEnd < f.LineStart { return errors.New("invalid finding location") } if len(f.Title) > 2000 || len(f.Body) > 20000 { return errors.New("finding text is too long") } if f.Suggestion != nil && len(*f.Suggestion) > 20000 { return errors.New("suggestion is too long") } _ = i } return nil } type WebhookEvent struct { EventName string DeliveryID string Repo string PRNumber int HeadSHA string CommentID int64 CommentBody string Sender string PayloadSHA256 string } type Job struct { ID int64 Repo string PRNumber int HeadSHA string TriggerCommentID int64 TriggerCommentBody string Command string CommandArgs string RequestedBy string Status JobStatus LastError string ResultJSON []byte CreatedAt time.Time UpdatedAt time.Time StartedAt *time.Time FinishedAt *time.Time } type ReviewRun struct { ID int64 JobID int64 Status RunStatus ContainerID string ResultJSON []byte Error string StartedAt time.Time FinishedAt *time.Time } func (j Job) AttemptNumber() int { return 1 } // ReviewRunner isolates all process/container execution from orchestration. type ReviewRunner interface { Run(context.Context, PullRequestContext, ParsedCommand, RepoReviewConfig) (ReviewResult, error) } func NormalizeRepo(repo string) string { return strings.TrimSpace(repo) }