All files / src/tools suggest-progression.ts

100% Statements 25/25
100% Branches 12/12
100% Functions 1/1
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50                1x                     1x 9x 9x   8x 8x 8x 8x   9x 1x 1x 1x 1x 1x   9x 2x 2x     9x 4x 4x 4x 4x 4x   1x 1x  
import type { SetLog, WeightReps } from '@strengthsys/shared';
 
export interface RepRange {
  low: number;
  high: number;
}
 
/** Standard barbell increment in kg. */
const WEIGHT_INCREMENT = 2.5;
 
/**
 * Suggest the next progression for an exercise based on previous performance.
 *
 * Logic:
 * - If the last set feeling was 'awful': reduce weight by one increment, reset reps to range low
 * - If the last set feeling was 'hard': repeat the same weight and reps
 * - If reps are at or above the target range high: increase weight by one increment, reset reps to range low
 * - Otherwise: keep weight, add one rep
 */
export function suggestProgression(previousSets: SetLog[], targetRange: RepRange): WeightReps {
  const completed = previousSets.filter((s) => !s.skipped && s.actual_weight_kg != null && s.actual_reps != null);
  if (completed.length === 0) throw new Error('No completed sets to base progression on');
 
  const lastSet = completed[completed.length - 1];
  const weight = lastSet.actual_weight_kg!;
  const reps = lastSet.actual_reps!;
  const feeling = lastSet.feeling;
 
  if (feeling === 'awful') {
    return {
      weight_kg: weight - WEIGHT_INCREMENT,
      reps: targetRange.low,
    };
  }
 
  if (feeling === 'hard') {
    return { weight_kg: weight, reps };
  }
 
  // Good/great/okay feelings — progress
  if (reps >= targetRange.high) {
    return {
      weight_kg: weight + WEIGHT_INCREMENT,
      reps: targetRange.low,
    };
  }
 
  return { weight_kg: weight, reps: reps + 1 };
}