What is wrong with the T-SQL below that a colleague of mine wrote?

DECLARE @newId int,@counter int,@oldId int,@id int

SET @oldId=0
SET @counter=0

DECLARE ScheduleStep_Cursor CURSOR FOR
SELECT [id],[scheduleId] FROM [ScheduleStep] order by scheduleId asc

OPEN ScheduleStep_Cursor;
FETCH NEXT FROM ScheduleStep_Cursor INTO @id,@newId

WHILE @@FETCH_STATUS = 0


BEGIN
 print 'Schedule : ' + convert(varchar, @newId) + ' id : ' + convert(varchar, @id)

 IF (@oldId=null OR @oldId=0)
   BEGIN

     SET @counter=1

     UPDATE 
       [ScheduleStep] 
     SET 
       milestoneCount=@counter
     WHERE 
       [id]=@id
   END
 ELSE IF(@oldId=@newId)
   BEGIN

     SET @counter=@counter+1

     UPDATE 
       [ScheduleStep] 
     SET 
       milestoneCount=@counter
     WHERE 
       [id]=@id
   END
 ELSE

   BEGIN
     SET @counter=1

     UPDATE 
       [ScheduleStep] 
     SET 
       milestoneCount=@counter
     WHERE 
       [id]=@id
   END

   SET @oldId=@newId
   FETCH NEXT FROM ScheduleStep_Cursor INTO @id,@newId
END

CLOSE ScheduleStep_Cursor;
DEALLOCATE ScheduleStep_Cursor;

The problem is that whilst looping round the cursor, the same rows that are being looped round are being updated, which can result in all kinds of weirdness including an infinite loop. The solution is to make use of the INSENSITIVE keyword which means that the data to be used by the cursor is copied to a temporary table in tempdb. You can then freely update the original table without any problems.

DECLARE ScheduleStep_Cursor INSENSITIVE CURSOR FOR
SELECT [id],[scheduleId] FROM [ScheduleStep] order by scheduleId asc