When an attempt errors, an ERROR AttackResult is saved, and a retry or resume then adds a new row for the same objective. Keeping those ERROR rows as history is intentional, but objective_achieved_rate and group_success_rate divide by every row, so each recovered error still drags the rate down. Running the existing Crescendo retry-and-resume test flow and printing the rate:
rows: ['success', 'error', 'error', 'success'] unique objectives: 2 objective_achieved_rate: 50
Both objectives succeeded, so that should be 100. This number feeds the console, JSON and HTML reports. The GUI already gets it right (calculate_progress_counts explicitly avoids "inflating retries or error attempts"), so the GUI and CLI show different rates for the same run.
Suggested fix: skip ERROR attempts that were replaced by a later attempt of the same unit, using the same unit identity the GUI uses.
When an attempt errors, an ERROR
AttackResultis saved, and a retry or resume then adds a new row for the same objective. Keeping those ERROR rows as history is intentional, butobjective_achieved_rateandgroup_success_ratedivide by every row, so each recovered error still drags the rate down. Running the existing Crescendo retry-and-resume test flow and printing the rate:Both objectives succeeded, so that should be 100. This number feeds the console, JSON and HTML reports. The GUI already gets it right (
calculate_progress_countsexplicitly avoids "inflating retries or error attempts"), so the GUI and CLI show different rates for the same run.Suggested fix: skip ERROR attempts that were replaced by a later attempt of the same unit, using the same unit identity the GUI uses.