Skip to content

feat: Environmental Performance Adjustments (v1.9.7)#75

Merged
0jonjo merged 7 commits into
mainfrom
feat/environmental-adjustments-v1.9.7
May 16, 2026
Merged

feat: Environmental Performance Adjustments (v1.9.7)#75
0jonjo merged 7 commits into
mainfrom
feat/environmental-adjustments-v1.9.7

Conversation

@0jonjo

@0jonjo 0jonjo commented May 16, 2026

Copy link
Copy Markdown
Owner

Adds scientific environmental adjustments to race predictions and results.

Features

  • Data-Driven Penalties: Uses YAML tables based on Matthew Ely (2007) for heat and NCAA Standards for altitude.
  • Support for Celsius & Fahrenheit: Flexible temperature input.
  • Adjusted Predictions: New methods predict_time_adjusted and predict_time_cameron_adjusted.
  • Transparent Output: Returns penalty percentages and factor breakdowns.

Scientific Basis

  • Altitude: Aligned with NCAA official conversion factors (~3.76% at 6000ft).
  • Heat: Balanced baseline based on Ely's sub-elite runner profile (~4.5% at 20C, ~8.5% at 25C).

Assigned to @0jonjo for review. Waiting for Copilot review as requested.

Align altitude adjustments with NCAA official conversion (32.7s for 5k
at 6000ft) and heat penalties with Matthew Ely 2007 'Sub-Elite' profile.
Ensures calculations are grounded in validated research while
maintaining a safe baseline for recreational runners.
Copilot AI review requested due to automatic review settings May 16, 2026 22:25
@0jonjo 0jonjo self-assigned this May 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an Environmental Performance Adjustments feature to Calcpace, enabling heat/altitude penalty calculations and exposing “adjusted” race prediction methods that return both adjusted times and penalty breakdowns.

Changes:

  • Introduces EnvironmentalAdjuster with YAML-driven penalty tables and interpolation, plus calculate_penalty / adjust_time.
  • Adds new adjusted prediction APIs: predict_time_adjusted (Riegel) and predict_time_cameron_adjusted (Cameron).
  • Updates tests, docs, changelog, and bumps version to 1.9.7.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
lib/calcpace/environmental_adjuster.rb New module implementing penalty calculation + time adjustment using YAML tables
lib/calcpace/data/environmental_factors.yml New heat/altitude factor tables used by the adjuster
lib/calcpace/race_predictor.rb Adds predict_time_adjusted wrapper to apply environmental adjustments to Riegel predictions
lib/calcpace/cameron_predictor.rb Adds predict_time_cameron_adjusted wrapper to apply environmental adjustments to Cameron predictions
lib/calcpace.rb Requires and includes EnvironmentalAdjuster in Calcpace
test/calcpace/test_environmental_adjuster.rb New tests for penalty and adjusted time behavior
test/calcpace/test_race_predictor.rb Adds tests for environmentally adjusted Riegel predictions
test/calcpace/test_cameron_predictor.rb Adds a test for environmentally adjusted Cameron predictions
README.md Documents environmental adjustment APIs and bumps installation version snippet
lib/calcpace/version.rb Bumps gem version to 1.9.7
CHANGELOG.md Adds 1.9.7 release notes for the new feature
Comments suppressed due to low confidence (2)

test/calcpace/test_environmental_adjuster.rb:63

  • The file ends with an extra indented end, and the TestEnvironmentalAdjuster class never gets a proper closing end. As written this is a syntax error and will prevent the test suite from running; remove the stray end and ensure the class is correctly closed.
  end

    end


README.md:69

  • These README example penalties appear inconsistent with the current heat table/interpolation. With the current YAML, 80°F (~26.67°C) would yield ~10.34% heat penalty (not 7.34%), and 28°C would yield ~11.8% (not 8.4%). Please recalculate and update the shown penalty_percent/times so users can trust the examples.
# Fahrenheit support
calc.calculate_penalty(temperature: 80, temperature_unit: :f)
# => { total_penalty_percent: 7.34, ... }

# Adjust a 3:30 marathon time (12600s) for these conditions
result = calc.adjust_time(12600, temperature: 25, altitude: 2000)
# => {
#      original_time: 12600,
#      adjusted_time: 13849.92,
#      adjusted_time_clock: "03:50:49",
#      penalty_percent: 9.92,
#      factors: { heat: 6.0, altitude: 3.92 }
#    }

# Predicted adjusted times (Riegel formula)
calc.predict_time_adjusted('5k', '00:20:00', '10k', temperature: 28)
# => { adjusted_time: 2712.08, adjusted_time_clock: "00:45:12", penalty_percent: 8.4, ... }

# Predicted adjusted times (Cameron formula)
calc.predict_time_cameron_adjusted('10k', '00:40:00', 'marathon', temperature: 80, temperature_unit: :f)
# => { adjusted_time: 10891.0, adjusted_time_clock: "03:01:31", penalty_percent: 7.34, ... }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/calcpace/test_environmental_adjuster.rb
Comment thread lib/calcpace/environmental_adjuster.rb
Comment thread README.md Outdated
Comment thread README.md
0jonjo added 5 commits May 16, 2026 19:35
- Fix syntax error in test_environmental_adjuster.rb (stray end)
- Recalculate and update README examples using the finalized penalty
  factors for heat (Ely 2007) and altitude (NCAA).
Allows finding the ideal-condition equivalent for performances achieved
in heat or altitude. Essential for the 'Environmental Equivalence'
feature in the web app. Includes tests for round-trip consistency.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

lib/calcpace/environmental_adjuster.rb:68

  • normalized_time is rounded to 2 decimals but normalized_time_clock is computed from the unrounded normalized_seconds, which can cause a 1-second mismatch between the numeric and clock representations. Consider computing the clock string from the same rounded value returned as normalized_time.
    {
      original_time: time_seconds,
      normalized_time: normalized_seconds.round(2),
      normalized_time_clock: convert_to_clocktime(normalized_seconds),
      penalty_percent: percent,
      factors: penalty[:factors]


data = FACTORS.fetch('altitude')
threshold = data.fetch('threshold_meters')
return 0.0 if alt <= threshold
Comment thread lib/calcpace/environmental_adjuster.rb
Address Copilot review feedback: calculate clock time string from the
rounded seconds value in both adjust_time and normalize_time. This
prevents potential 1-second mismatches in result hashes.
@0jonjo 0jonjo merged commit 9a825f5 into main May 16, 2026
8 checks passed
@0jonjo 0jonjo deleted the feat/environmental-adjustments-v1.9.7 branch May 16, 2026 23:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants