package usecase import ( "context" "apps/backend/internal/module/scout/domain" ) // StartRun guards queued → running and is idempotent for a retry of the same // job. A different job can never take over an active or terminal run. func (s *Service) StartRun(ctx context.Context, ownerUID int64, runID, jobID string) (*domain.Run, error) { if s == nil || s.Repo == nil || runID == "" || jobID == "" { return nil, domain.ErrValidation } run, err := s.Repo.GetRun(ctx, ownerUID, runID) if err != nil { return nil, err } if run.JobID != jobID { return nil, domain.ErrIllegalRunStatus } if run.Status == domain.RunRunning { return run, nil } if err := run.Transition(domain.RunRunning, domain.NowNano()); err != nil { return nil, err } if err := s.Repo.ReplaceRunGuarded(ctx, ownerUID, runID, []string{domain.RunQueued}, run); err != nil { return nil, err } return run, nil }