Skip to content

feat(health): export weekly training summaries as CSV and JSON - #50

Merged
johnnyhuy merged 1 commit into
mainfrom
agent/issue-49-weekly-training-export
Nov 13, 2026
Merged

johnnyhuy merged 1 commit into
mainfrom
agent/issue-49-weekly-training-export

Conversation

@johnnyhuy

@johnnyhuy johnnyhuy commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Add CSV and JSON export for weekly training summaries, with explicit units, missing-value handling, sorted activity counts and atomic file writes. Add package API documentation and 11 tests, including XML parsing through weekly aggregation to exported output.

Completes the weekly export slice. Part of #6. Closes #49.

Reverified locally at 19d9db4 on 13 November 2026 in a fresh worktree. The branch is already based on current main.

  • mise run lint passed with 0 serious violations. The 491 existing warnings are outside the new files.
  • mise run build passed.
  • mise run test passed, including 162 XCTest tests, 30 Swift Testing tests and 23 video pipeline checks.
  • CI mise run ios:build:ci and mise run ios:e2e passed.
  • CI mise run ios:coverage initially failed in the existing finish-workout UI test after two animation-idle timeouts. Its captured UI hierarchy still showed the confirmation dialog after the save tap. The same save flow passed in the next test. A single rerun on the unchanged commit passed all 27 UI tests, including both summary tests. No source changes were needed.

Core test capture succeeded at commit 19d9db4. Captured proof transcript. The transcript includes all 11 new tests, including the XML parser-to-export flow, plus the full suite totals. No app UI changed and no capture path was blocked.

mise run lint
Done linting! Found 491 violations, 0 serious in 136 files.

mise run build
Build complete! (35.74s)

mise run test
==> summary: 23 passed, 0 failed
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVDistinguishesMissingMetricsFromMeasuredZero]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVEmptyArrayIsHeaderOnly]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVHeaderUnitsAndSortedActivityCounts]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVPreservesArrayOrder]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVQuotesActivityNamesContainingCSVDelimitersAndUnicode]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testExportsParsedWorkoutsWithNormalisedStatisticsAndCalendarWeeks]' passed (0.002 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testFileWritingPropagatesErrors]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONEmptyArray]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONRejectsNonFiniteMetrics]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONRoundTripPreservesOrderActivityNamesAndMissingMetrics]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testWritesAndReplacesCSVAndJSONFiles]' passed (0.002 seconds).
	 Executed 162 tests, with 0 failures (0 unexpected) in 2.322 (2.353) seconds
	 Executed 162 tests, with 0 failures (0 unexpected) in 2.322 (2.355) seconds
􁁛  Test run with 30 tests in 4 suites passed after 0.009 seconds.

The parser-to-export test verifies UTC week boundaries from dates with a +1000 offset, kJ-to-kcal and km-to-m conversions, heart-rate metrics, and missing values. File tests exercise replacement and error propagation. Floating point conversions retain their existing precision.

The successful CI coverage rerun confirms the existing finish-workout flow passes on the unchanged commit.

mise run ios:coverage
Test Case '-[BetterFitAppUITests.WorkoutSummaryUITests testFinishSessionShowsSummary]' passed (29.580 seconds).
Test Case '-[BetterFitAppUITests.WorkoutSummaryUITests testSummaryHidesRecoverySectionWithoutRecoveryData]' passed (53.984 seconds).
Executed 27 tests, with 0 failures (0 unexpected) in 439.697 (439.718) seconds
Executed 27 tests, with 0 failures (0 unexpected) in 439.697 (439.719) seconds
** TEST SUCCEEDED **

This is a package-only slice with no user-facing app changes. Core test capture supplies the behaviour proof, and the CI UI suite also passed. No simulator screenshot was needed. The parent epic stays open. App sharing and further ingestion work remain outside this slice.

Add weekly export files with explicit units, missing-value handling and safely quoted activity counts. Verify the XML-to-weekly-export flow and document the package API.

Co-authored-by: OpenAI Codex <noreply@openai.com>
@johnnyhuy

Copy link
Copy Markdown
Contributor Author

Core test capture succeeded at commit 19d9db4. The transcript includes all 11 new tests, including the XML parser-to-export flow, plus the full suite totals. No app UI changed and no capture path was blocked.

mise run lint
Done linting! Found 491 violations, 0 serious in 136 files.

mise run build
Build complete! (4.53s)

mise run test
==> summary: 23 passed, 0 failed
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVDistinguishesMissingMetricsFromMeasuredZero]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVEmptyArrayIsHeaderOnly]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVHeaderUnitsAndSortedActivityCounts]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVPreservesArrayOrder]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVQuotesActivityNamesContainingCSVDelimitersAndUnicode]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testExportsParsedWorkoutsWithNormalisedStatisticsAndCalendarWeeks]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testFileWritingPropagatesErrors]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONEmptyArray]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONRejectsNonFiniteMetrics]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONRoundTripPreservesOrderActivityNamesAndMissingMetrics]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testWritesAndReplacesCSVAndJSONFiles]' passed (0.003 seconds).
Executed 162 tests, with 0 failures (0 unexpected) in 2.147 (2.201) seconds
Executed 162 tests, with 0 failures (0 unexpected) in 2.147 (2.203) seconds
􁁛  Test run with 30 tests in 4 suites passed after 0.016 seconds.

@johnnyhuy

Copy link
Copy Markdown
Contributor Author

Reverified PR #50 at 19d9db4 in a fresh worktree. No source changes were needed and the branch is already based on current main.

Core test capture succeeded. No app UI changed and no capture path was blocked.

mise run lint
Done linting! Found 491 violations, 0 serious in 136 files.

mise run build
Build complete! (35.74s)

mise run test
==> summary: 23 passed, 0 failed
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVDistinguishesMissingMetricsFromMeasuredZero]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVEmptyArrayIsHeaderOnly]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVHeaderUnitsAndSortedActivityCounts]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVPreservesArrayOrder]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testCSVQuotesActivityNamesContainingCSVDelimitersAndUnicode]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testExportsParsedWorkoutsWithNormalisedStatisticsAndCalendarWeeks]' passed (0.002 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testFileWritingPropagatesErrors]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONEmptyArray]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONRejectsNonFiniteMetrics]' passed (0.001 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testJSONRoundTripPreservesOrderActivityNamesAndMissingMetrics]' passed (0.000 seconds).
Test Case '-[BetterFitTests.WeeklyTrainingSummaryExportTests testWritesAndReplacesCSVAndJSONFiles]' passed (0.002 seconds).
	 Executed 162 tests, with 0 failures (0 unexpected) in 2.322 (2.353) seconds
	 Executed 162 tests, with 0 failures (0 unexpected) in 2.322 (2.355) seconds
􁁛  Test run with 30 tests in 4 suites passed after 0.009 seconds.

The first CI attempt failed in the existing WorkoutSummaryUITests.testFinishSessionShowsSummary after two animation-idle timeouts. The next test completed the same save flow. The failed coverage job is being rerun once on the unchanged commit to check whether the failure is transient.

@johnnyhuy

Copy link
Copy Markdown
Contributor Author

The coverage rerun passed on the unchanged commit 19d9db4. All checks are now green.

CI coverage proof

mise run ios:coverage
Test Case '-[BetterFitAppUITests.WorkoutSummaryUITests testFinishSessionShowsSummary]' passed (29.580 seconds).
Test Case '-[BetterFitAppUITests.WorkoutSummaryUITests testSummaryHidesRecoverySectionWithoutRecoveryData]' passed (53.984 seconds).
Executed 27 tests, with 0 failures (0 unexpected) in 439.697 (439.718) seconds
Executed 27 tests, with 0 failures (0 unexpected) in 439.697 (439.719) seconds
** TEST SUCCEEDED **

@johnnyhuy
johnnyhuy merged commit 12ba26a into main Nov 13, 2026
13 of 14 checks passed
@johnnyhuy
johnnyhuy deleted the agent/issue-49-weekly-training-export branch November 13, 2026 11:39
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.

Export weekly training summaries as CSV and JSON

1 participant