Skip to content

feat: expose dataStartDate on initConnection for Apple Health floor [ENG-1995] - #31

Open
Ant1Miller wants to merge 3 commits into
mainfrom
antoine/eng-1995-apple-health-data-start-date-floor
Open

Ant1Miller wants to merge 3 commits into
mainfrom
antoine/eng-1995-apple-health-data-start-date-floor

Conversation

@Ant1Miller

Copy link
Copy Markdown
Contributor

What

Exposes an optional dataStartDate (DateTime?) on the Dart initConnection, forwarded through the iOS plugin to the native SDK's new lower-bound parameter (TerraiOSPackage#64). When set, Apple Health samples older than it are not delivered on connect/background delivery.

Raised by Thymia, a clinical-research customer who must only ingest data inside each participant's consent window.

How

  • Dart initConnection gains a named optional dataStartDate; sent over the method channel as an ISO string, normalised to millisecond precision first so it round-trips through the iOS ISO8601DateFormatter (.withFractionalSeconds rejects the 6-digit fractional seconds a raw DateTime.now()-derived value would produce).
  • iOS plugin parses it and forwards to native; if a non-nil string fails to parse it logs rather than silently applying no bound.
  • Android: reads channel args by key and simply ignores the new one for now (Health Connect floor is a deliberate follow-up). No Android code change needed or made.

Compatibility

dataStartDate is a named optional appended after the existing positional params, so every existing initConnection caller compiles and behaves identically.

Verification status — needs a device smoke test before merge

Change is small and source-compatible, but this environment has no Flutter/Xcode toolchain, so it was not built or run. Please flutter analyze + a quick iOS device check (pass a dataStartDate, confirm no pre-floor Apple Health samples arrive) before merging. Draft until then. Depends on TerraiOSPackage#64.

Adds an optional dataStartDate to the Dart initConnection, forwarded through
the iOS plugin to the native SDK's new lower-bound parameter so pre-consent
Apple Health history is not delivered. Normalised to millisecond precision so
the ISO string round-trips through the iOS date parser, with a log if it does
not. Android reads channel args by key and ignores the new one for now.

ENG-1995

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Ant1Miller
Ant1Miller force-pushed the antoine/eng-1995-apple-health-data-start-date-floor branch from d40b52b to 617b672 Compare August 4, 2026 07:22
@Ant1Miller

Copy link
Copy Markdown
Contributor Author

/sfs

@mep-y mep-y Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

needs a pass — the stale iOS SDK constraint and lower-bound truncation block merge.

The bridge shape fits, but it must require the TerraiOS release that defines this ABI. Design also needs initConnection to reject, rather than drop, an invalid floor; functionality currently rounds the consent floor down and can deliver pre-window samples. No test files changed, so run the stated iOS device smoke test around the exact floor before merging.

For the non-technically inclined

Apps that keep the older iOS library will fail to build after this update. The consent cutoff can also let in records from before a participant agreed.

prIQ: 90

token: token,
customReadTypes: customPermissionsSet(customPermissions: customPermissions),
schedulerOn: schedulerOn,
dataStartDate: dataStartDate,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The podspec still permits TerraiOS 1.7.10, whose ABI lacks this argument, so existing locks fail to compile.

fails when: An app already locked to TerraiOS 1.7.10 upgrades this Flutter package. Its Podfile.lock still satisfies ~> 1.7.10, so pod install retains 1.7.10; compiling this forwarding call fails because that SDK does not declare the new dataStartDate argument.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right, and it cannot be pinned until TerraiOSPackage#64 lands and carries a version. Recording it as a merge blocker rather than setting a constraint on a release that does not exist yet. This PR is draft and already depends on #64.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

makes sense. keeping this open as the merge blocker until #64 has a released version that the podspec can require.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Still open, and it is a harder blocker than described. initConnection on TerraiOSPackage master is initConnection(type:token:customReadTypes:schedulerOn:completion:) with no dataStartDate at all. That argument exists only in TerraiOSPackage #64, which is an open draft, so no published TerraiOS carries it: not 1.7.10, not 1.7.11, not 1.8.0.

Widening the pin therefore does not help, because there is no version to widen it to. Leaving this unresolved until #64 merges and ships a release, at which point the pin goes to that version.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

right — this is a broader compile blocker, not just a stale lower bound: no released terraios version exposes the call yet. keeping this open until #64 ships is the right call.

Comment thread ios/Classes/SwiftTerraFlutterPlugin.swift
Comment thread lib/terra_flutter_bridge.dart
Round the millisecond conversion up rather than truncating, so a floor with
sub-millisecond precision cannot admit samples older than the consent window
the caller asked for. Reject an unparseable dataStartDate instead of
continuing with no bound, which silently widened ingestion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Ant1Miller

Copy link
Copy Markdown
Contributor Author

/sfs

@mep-y mep-y Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nice — ships, minor stuff inline.

architecture stays in the bridge and leaves HealthKit filtering with the native SDK. functionality now conservatively ceilings the floor and rejects malformed iOS values. design still exposes a generic parameter that silently does nothing on Android; scope it or make unsupported explicit. comment sweep trims one implementation-narration block inline.

prIQ: 98

Comment thread lib/terra_flutter_bridge.dart
Comment thread lib/terra_flutter_bridge.dart Outdated
@Ant1Miller
Ant1Miller marked this pull request as ready for review August 4, 2026 08:15
The Android plugin never reads the dataStartDate key off the method channel,
and Terra.initConnection has no equivalent parameter to forward it to, so the
floor was silently dropped there. Scope it to Apple Health so an unhonourable
floor fails loudly instead.
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.

1 participant