Athlytics 1.0.5
Major analysis-quality fixes
calculate_ef()stream path now uses continuous-block steady-state detection. Previously EF was computed as the median ratio across every scattered point whose rolling CV clearedsteady_cv_threshold, so an interval workout with three short “steady islands” could silently pass themin_steady_minutesgate. The stream path now mirrorscalculate_decoupling(): it usesrle()to find contiguous steady runs and only accepts activities whose longest run lasts at leastmin_steady_minutes. New output columnssteady_duration_minutes,n_steady_blocks, andsampling_interval_secondsmake the accepted block auditable; new status code"insufficient_steady_duration"distinguishes this from the old"non_steady".gap_hrstream-path fallback is now explicit. When the stream has no grade-adjusted channel the function still falls back to plain speed/HR, but the returned row now records this viaef_metric_requested = "gap_hr",ef_metric_used = "speed_hr", and the new status string"gap_stream_unavailable_fallback_to_speed". Downstream consumers that need strict GAP semantics can now filter on these columns instead of assuming theef_metricargument equals the metric actually computed.Rolling windows are now time-based, not row-based.
calculate_ef(),calculate_decoupling(), andflag_quality()previously assumed 1 Hz sampling (window_size <- 300rows). The effective window silently rescaled on 0.5 Hz smart-recording or multi-Hz streams. A new internalestimate_sampling_interval()helper readsdiff(time)and the three functions now target wall-clock windows; the observed interval is exposed assampling_interval_secondson EF/decoupling output and asattr(result, "sampling_interval_seconds")on flag_quality output.flag_quality()HR / power jump thresholds honour their “per-second” documentation.max_hr_jump = 10is now compared against|dHR/dt|(bpm / s) rather than raw sample-to-sample differences; the same change applies tomax_pw_jump. Streams that are not exactly 1 Hz are therefore judged consistently across recording devices.Training-load calculation now distinguishes rest days from missing-data training days.
compute_single_load()returnslist(value, status)instead of collapsing every non-computable case to0.calculate_acwr(),calculate_acwr_ewma(), andcalculate_exposure()gain amissing_load = c("zero", "na")argument:"zero"(default) preserves the historical behaviour,"na"keepsNAon days whose load could not be computed so the rolling means visibly propagate the gap.
Transparency additions
calculate_decoupling(stream_df = ..., return_diagnostics = TRUE)now returns a one-row data frame exposingdecoupling,status,quality_score,hr_coverage,steady_duration_minutes, andsampling_interval_seconds, so callers can distinguish the reason anNAdecoupling was produced. The default still returns a numeric for backward compatibility.calculate_pbs()adds atime_basiscolumn (always"moving"in the current implementation) and clarifies in roxygen that PBs are moving-time best efforts becausefind_best_effort()operates on the strictly-monotonic-distance subset (paused / plateau samples are excluded from the candidate window).flag_quality()surfaces the activity-level score as an attribute. The per-rowquality_scorecolumn is preserved for backward compatibility but the same value is now also attached asattr(result, "activity_quality_score")and its activity-level semantics are documented.calculate_cohort_reference()requiresathlete_idby default. Passing a frame with noathlete_idcolumn previously silently injected a synthetic"unknown"athlete and produced a band that looked cohort-derived but was actually within-athlete. The function nowstop()s unless the caller explicitly opts in viaallow_unknown_athlete = TRUE.
Transparency additions (continued)
-
missing_load = "zero"now warns when it silently absorbs data gaps.calculate_acwr(),calculate_acwr_ewma()andcalculate_exposure()invoke a shared helper that scans the per-activityload_statuscolumn produced bycompute_single_load(); if any activity returned amissing_*/hr_out_of_rangestatus and the caller kept the historical"zero"default, the function now emits a one-shotwarning()listing the top statuses and recommendingmissing_load = "na". The default is still"zero"for backward compatibility.
Code cleanup
calculate_pbs()now uses the same stream-parse call pattern ascalculate_decoupling(). Previously PB processing calledparse_activity_file(file.path(export_dir, activity$filename), export_dir)which relied on the zip resolver stripping theexport_dir/prefix internally. The new call passesactivity$filenameandexport_dirdirectly, matching the decoupling path and removing the redundant prefix hop.calculate_decoupling()stream_dfroxygen corrected. Earlier drafts said “If provided, calculates decoupling for this data directly, ignoring other parameters”. The implementation has not ignored those parameters since 1.0.4; the documentation now matches the behaviour and explicitly lists which argumentsstream_dfhonours.
Documentation
- Expanded the EF and decoupling roxygen
@returntables and theStatus vocabularysections with every status string the two functions can emit. - Added a dedicated
PB time semanticssection tocalculate_pbs()explaining elapsed-vs-moving interpretation; clarified thatelapsed_timeandmoving_timeare compatibility columns that carry the sametime_secondsvalue and thattime_basisis the authoritative field. - Documented the
missing_loadknob on every training-load entry point. - README: installation section now prominently flags the CRAN / GitHub version mismatch (CRAN
0.1.2vs GitHub1.0.5) and recommends r-universe or GitHub for the current offline workflow. Citationversionupdated from 1.0.4 to 1.0.5. The Quick Start ZIP note now reflectscalculate_pbs()andcalculate_decoupling()being zip-aware in 1.0.5.
Athlytics 1.0.4
Test suite cleanup: Further streamlined from ~600 to 373 assertions. All tests now pass locally with zero warnings and zero skips.
Test idiom improvements: Replaced
expect_true(is.data.frame())withexpect_s3_class(),expect_equal(length())withexpect_length(). Removed redundantgg-class checks already covered by vdiffr snapshots.Test file consolidation: Deleted fragmented files (
test-smoke-and-errors.R,test-uncovered-branches.R, etc.) and merged relevant tests into per-feature files.Dependency cleanup: Removed
purrrentirely (only used once via supersededpurrr::transpose()). R CMD check now passes with 0 errors and 0 warnings.Packaging: Removed
CITATION.cff(was flagged by R CMD check as non-standard), cleaned up NAMESPACE and.Rbuildignore.
Athlytics 1.0.3
Test suite rewrite: Reduced from ~1500 to ~200 focused tests with meaningful value assertions; added vdiffr snapshot testing for all plot functions (15 visual regression tests).
-
Bug fixes:
- Fixed FIT import when
FITfileR::records()returns a list - Fixed
calculate_ef_from_stream()column name mismatch (powervswatts) - Fixed
calculate_decoupling()column name mismatch (heart_ratevsheartrate) - Empty data now returns an error instead of a warning with an empty plot
- Fixed FIT import when
Analysis–plotting separation: All plot functions now require pre-computed data; passing analysis arguments emits a deprecation warning.
Custom S3 classes: All calculation functions return dedicated classes (
athlytics_acwr,athlytics_ef,athlytics_decoupling,athlytics_pbs,athlytics_exposure).Scientific references: Added references with DOIs throughout vignettes and roxygen documentation (Gabbett, Hulin, Impellizzeri, Coyle, Allen, Williams, etc.).
ACWR caveats: Added “Important Caveats” section discussing scientific debate on ACWR predictive validity.
-
New features:
- Grade Adjusted Pace (
gap_hr) support for EF calculation -
smooth_per_activity_typeoption inplot_ef() - Configurable risk zone thresholds in
plot_acwr() -
plot_exposure()risk zones no longer require an ACWR column - Custom distances in
calculate_pbs()
- Grade Adjusted Pace (
-
Documentation improvements:
- Strava language setting requirement documented
- Volume vs load terminology clarified
- Pace vs speed distinction corrected (
pace_hrdeprecated in favor ofspeed_hr) - Native pipe
|>used in vignettes - Roxygen markdown formatting enabled
Code cleanup: Removed
zzz.R, unused color palette functions,rStrava/mockeryfrom Suggests, Strava API references; cleaned NAMESPACE imports.CI: R CMD check now runs on 3 R versions (devel, release, oldrel-1) across 3 OS.
Shipped example files:
inst/extdata/containsexample.fit,.gpx,.tcx.Code style: Applied
styler::style_pkg()formatting.
Athlytics 1.0.2
Documentation & Review Fixes
Runnable vignettes: Added executable demo chunks using built-in sample datasets so key plots render during
build_vignettes().Sample data naming: Renamed built-in datasets from
athlytics_sample_*tosample_*and updated docs/examples accordingly.Styling: Ran
styler::style_pkg()to improve formatting consistency.
Athlytics 1.0.1
Code Quality Improvements
Reduced Cyclomatic Complexity: Refactored
calculate_acwr()andcalculate_exposure()by extracting shared load calculation logic into internal helper functions (calculate_daily_load_internal(),compute_single_load(),validate_load_metric_params()). This improves code maintainability and testability without changing the public API.Dependency Cleanup: Removed unused
viridispackage from Imports. The package was declared as a dependency but never actually called (ggplot2’s built-inscale_color_viridis_d()was used instead).Documentation Fixes: Fixed Rd line width issues in
plot_with_reference()examples.-
API Naming Consistency: Added verb-first primary APIs and kept previous names as deprecated wrappers for backward compatibility.
- New:
calculate_cohort_reference()(replacescohort_reference()) - New:
summarize_quality()(replacesquality_summary()) - Old names remain available but emit a deprecation warning to guide migration.
- New:
Build Configuration: Updated
.Rbuildignoreto properly exclude development files.
Athlytics 1.0.0
This major release transitions from Strava API to local data export processing, prioritizing user privacy and data ownership while eliminating API rate limits and authentication requirements.
Breaking Changes & New Features
-
Privacy-First Architecture: Complete shift from Strava API to local ZIP file processing
- New
load_local_activities()function supports direct ZIP file loading (no manual extraction needed) - Removed API dependencies and authentication requirements
- All data processing happens locally - no cloud services involved
- New
-
Enhanced Documentation: Comprehensive documentation improvements across all core functions
- Added detailed parameter explanations with recommended values
- Included interpretation guidelines and typical value ranges
- Added algorithm descriptions and best practices
- Expanded with academic references and cross-function links
- Enhanced
calculate_acwr(),calculate_ef(), andcalculate_decoupling()documentation
-
Multi-Athlete Cohort Analysis: Improved support for research and team analytics
- Better documentation for
cohort_reference()and multi-athlete workflows - Examples updated to show intervention/control group comparisons
- Proper use of
group_modify()for batch processing
- Better documentation for
-
README & Package Updates
- Updated all code examples to reflect local data processing workflow
- Corrected function parameter names throughout (e.g.,
activities_df→activities_data) - Added installation guidance emphasizing GitHub v1.0.0 as latest version
- Removed outdated API-related content
Academic Paper
- Added comprehensive JOSS-style paper (
paper/paper.mdandpaper/paper.bib)- Detailed comparison with related R packages (rStrava, trackeR, activatr, FITfileR, ACWR, injurytools)
- Updated methodology to reflect local data processing approach
- Enhanced reproducible examples using local exports
Technical Improvements
- Fixed encoding issues in BibTeX references
- Updated
.gitignoreto track README.md and paper/ directory - Synchronized all documentation with actual function implementations
- Improved pkgdown website generation
Migration Guide
For users upgrading from 0.1.x:
- Download your Strava bulk data export (Settings > My Account > Download Request)
- Replace
fetch_strava_activities()calls withload_local_activities("export.zip") - Update function calls:
activities_df→activities_data,plot_*()now accepts data directly - Remove Strava API authentication code
Athlytics 0.1.2
CRAN release: 2025-05-16
-
CRAN Resubmission: Carefully addressed feedback from CRAN by making detailed updates and modifications for package resubmission. This primarily involved refining examples (e.g., consistently using
\dontrun{}as advised) and ensuring metadata files meet all CRAN standards.
- Testing: Focused on increasing test coverage towards the goal of 85% across the package. Integrated Codecov for ongoing coverage monitoring.
- Bug Fixes
Athlytics 0.1.1
Core Improvement: Enhanced Reliability & Testing with Simulated Data
This significant update enhances package reliability and ease of use by integrating sample datasets. This enables all examples to run offline and ensures core functionalities have undergone more rigorous, reproducible testing.
Key Changes
-
Examples & Vignettes: All Roxygen examples and key vignette examples now primarily use sample datasets for offline execution and clarity. Network-dependent examples are clearly separated in
\donttest{}blocks. -
Test Suite: Fundamentally refactored the test suite to extensively use sample datasets and
mockery, improving test robustness and parameter coverage. -
Strengthened Package Quality & Compliance: Undertook thorough package validation, leading to key enhancements for overall robustness and adherence to R packaging standards. This involved: ensuring all function examples are correct and reliably executable (notably addressing
strava_oauth(...)scenarios for offline/testing contexts); providing accurate and refined documentation for data objects inR/data.R; fixing Roxygen import directives for precise namespace definition; improving help file readability through Rd line width adjustments; and optimizing package data loading by addingLazyData: truetoDESCRIPTION. - Documentation: Minor improvements to documentation clarity and consistency (e.g., date formatting in plots, explicit naming of data frame arguments in examples).
Athlytics 0.1.0
Major Changes
-
Decoupling Calculation: Switched from
rStrava::get_activity_streamsto direct Strava API calls usinghttrandjsonlitefor fetching activity streams incalculate_decoupling. This aims to resolve previous errors but might impact performance and rate limiting.
Bug Fixes & Improvements
- Fixed
calculate_acwrerror (condition has length > 1) by forcing evaluation before the dplyr pipe. - Corrected
plot_pbsusage in examples and test scripts to include the requireddistance_metersargument. - Added missing dependencies (
httr,jsonlite) toDESCRIPTIONfile. - Improved error handling and messages in several functions.
- Simplified Roxygen documentation for core functions.
- Updated README examples and descriptions for clarity and consistency with code.
