Skip to content

Replace CSV export with NDJSON export as the sole Shortcuts export#556

Open
sudden-break wants to merge 1 commit into
ryanbr:mainfrom
sudden-break:replace-csv-export-with-ndjson
Open

Replace CSV export with NDJSON export as the sole Shortcuts export#556
sudden-break wants to merge 1 commit into
ryanbr:mainfrom
sudden-break:replace-csv-export-with-ndjson

Conversation

@sudden-break

Copy link
Copy Markdown

Summary

Removes ShortcutHealthExport (CSV format, noop_sync.txt) and makes ShortcutNdjsonExport the single Shortcuts export path for sideloaded iOS installs that can't use HealthKit directly.

Motivation

The existing CSV export produces a single flat file (noop_sync.txt) with HR,HRV,Steps,yyyy-MM-dd HH:mm lines. The NDJSON export produces 7 structured .txt files (one per data category) that are easier to parse in Shortcuts and carry richer data (sleep stages, workouts, daily metrics, calorie dedup). Having one export path simplifies maintenance and the settings UI.

What changed

New files:

  • Strand/Data/ShortcutNdjsonExport.swift — core export logic (517 lines)
  • StrandTests/ShortcutNdjsonExportTests.swift — unit tests (660 lines)

Deleted files:

  • Strand/Data/ShortcutHealthExport.swift — CSV export (213 lines)
  • StrandTests/ShortcutHealthExportTests.swift — CSV export tests (284 lines)

Modified files:

  • StrandiOS/App/ShortcutExportSettingsView.swift — removed CSV card, NDJSON-only settings UI
  • StrandiOS/App/StrandiOSApp.swift — removed CSV background trigger
  • StrandiOS/App/RootTabView.swift — updated comment
  • Strand/Data/ShortcutHealthImport.swift — updated doc comments
  • Strand/Resources/Localizable.xcstrings — 64 new translation entries (8 languages)
  • project.yml — updated comment

Exported files (7 NDJSON .txt files)

File Content
heart_rate.txt 15-min windowed HR averages
hrv.txt SDNN from R-R intervals (via HRVAnalyzer)
sleep_sleeping.txt Sleep stages (light/deep/rem)
sleep_awake.txt Sleep stages (wake)
workouts.txt Workouts with Apple Health type mapping
daily_metrics.txt RHR, HRV, resp rate, calories (deduplicated)
summary.txt Export metadata

Behavior

  • Triggered on app background (same as old CSV export)
  • Opt-in via "Export for Shortcuts (Apple Health)" toggle in Settings
  • Configurable 7/30/90-day lookback window
  • User-chosen output folder (or Documents fallback)
  • Delta export with watermark-based tracking
  • Auto-migration: users with CSV export enabled get NDJSON enabled automatically
  • Daily metrics: only exports completed days (excludes today)
  • Calorie dedup: subtracts workout kcal from daily active_kcal

Testing

  • 43 unit tests pass (all renderers + delta export behavior)
  • iOS Release build compiles clean
  • Unsigned IPA produced and verified installable via AltStore/SideStore
  • Translations verified in compiled bundle (de, es, fr, it, pt-PT, ru, zh-Hans, zh-Hant)

What's NOT changed

  • ShortcutHealthImport (import from Apple Health) — completely separate, untouched
  • ShortcutExportReads protocol — moved into ShortcutNdjsonExport.swift, still provides the test seam
  • WhoopStore conformance — preserved
  • Background trigger — still fires on app exit, now only calls NDJSON export

@sudden-break
sudden-break force-pushed the replace-csv-export-with-ndjson branch from 3354089 to 0cf52de Compare July 21, 2026 06:05
Removes ShortcutHealthExport (CSV format, noop_sync.txt) and makes
ShortcutNdjsonExport the single Shortcuts export path. Produces 7 NDJSON
.txt files for import into Apple Health via iOS Shortcuts.

New files:
- Strand/Data/ShortcutNdjsonExport.swift (core export logic)
- StrandTests/ShortcutNdjsonExportTests.swift (unit tests)

Deleted files:
- Strand/Data/ShortcutHealthExport.swift (CSV export)
- StrandTests/ShortcutHealthExportTests.swift (CSV export tests)

Modified files:
- StrandiOS/App/ShortcutExportSettingsView.swift — removed CSV card, NDJSON-only UI
- StrandiOS/App/StrandiOSApp.swift — removed CSV background trigger
- StrandiOS/App/RootTabView.swift — updated comment
- Strand/Data/ShortcutHealthImport.swift — updated doc comments
- Strand/Resources/Localizable.xcstrings — added translations for NDJSON strings
- project.yml — updated comment

Behavior:
- One-time auto-migration: users with CSV export enabled get NDJSON enabled
- Configurable 7/30/90-day lookback window
- User-chosen output folder (or Documents fallback)
- Delta export with watermark-based tracking
- 8-language translations (de, es, fr, it, pt-PT, ru, zh-Hans, zh-Hant)
- Existing ShortcutHealthImport (import from Apple Health) unchanged
@sudden-break
sudden-break force-pushed the replace-csv-export-with-ndjson branch from 0cf52de to 99a4e1b Compare July 21, 2026 06:13
@ryanbr

ryanbr commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Review

The NDJSON export itself is well-engineered — good test coverage (43 tests), correct delta export with watermark tracking, proper security (bookmark-based sandboxing), and the calorie dedup logic is sound.

However, removing the CSV export entirely is a breaking change for any user who has an existing Shortcut built around parsing noop_sync.txt. The auto-migration enables NDJSON, but it can't migrate the user's Shortcut workflow — their automation would silently stop working.

Suggestion: keep CSV as a legacy option and offer NDJSON alongside it.

  • Make NDJSON the default for new users
  • Keep the CSV toggle available (even if de-emphasized in the settings UI) so existing Shortcuts don't break
  • Optionally add a deprecation note on the CSV option ("NDJSON is recommended — richer data, easier to parse")
  • Remove CSV in a future version after users have had time to migrate

This way the richer format is front and center without silently breaking anyone's automation.

Minor code notes (not blockers)

  1. JSON string interpolation — sport/stage values use "\(w.sport)" instead of JSONEncoder. Source values are controlled, so low risk, but JSONEncoder would be safer for defense-in-depth.
  2. Midnight-boundary calorie dedup — workout calories attributed to start-day is correct by design, but a test covering a midnight-spanning workout would strengthen confidence.

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